|
14 | 14 | QueryEvent, RotateEvent, FormatDescriptionEvent, |
15 | 15 | XidEvent, GtidEvent, StopEvent, XAPrepareEvent, |
16 | 16 | BeginLoadQueryEvent, ExecuteLoadQueryEvent, |
17 | | - HeartbeatLogEvent, NotImplementedEvent, MariadbGtidEvent) |
| 17 | + HeartbeatLogEvent, NotImplementedEvent, MariadbGtidEvent, |
| 18 | + MariadbAnnotateRowsEvent) |
18 | 19 | from .exceptions import BinLogNotEnabled |
19 | 20 | from .row_event import ( |
20 | 21 | UpdateRowsEvent, WriteRowsEvent, DeleteRowsEvent, TableMapEvent) |
@@ -141,6 +142,7 @@ def __init__(self, connection_settings, server_id, |
141 | 142 | fail_on_table_metadata_unavailable=False, |
142 | 143 | slave_heartbeat=None, |
143 | 144 | is_mariadb=False, |
| 145 | + annotate_rows_event=False, |
144 | 146 | ignore_decode_errors=False): |
145 | 147 | """ |
146 | 148 | Attributes: |
@@ -178,6 +180,8 @@ def __init__(self, connection_settings, server_id, |
178 | 180 | for semantics |
179 | 181 | is_mariadb: Flag to indicate it's a MariaDB server, used with auto_position |
180 | 182 | to point to Mariadb specific GTID. |
| 183 | + annotate_rows_event: Parameter value to enable annotate rows event in mariadb, |
| 184 | + used with 'is_mariadb' |
181 | 185 | ignore_decode_errors: If true, any decode errors encountered |
182 | 186 | when reading column data will be ignored. |
183 | 187 | """ |
@@ -219,6 +223,7 @@ def __init__(self, connection_settings, server_id, |
219 | 223 | self.auto_position = auto_position |
220 | 224 | self.skip_to_timestamp = skip_to_timestamp |
221 | 225 | self.is_mariadb = is_mariadb |
| 226 | + self.__annotate_rows_event = annotate_rows_event |
222 | 227 |
|
223 | 228 | if end_log_pos: |
224 | 229 | self.is_past_end_log_pos = False |
@@ -331,67 +336,39 @@ def __connect_to_stream(self): |
331 | 336 | self._register_slave() |
332 | 337 |
|
333 | 338 | if not self.auto_position: |
334 | | - # only when log_file and log_pos both provided, the position info is |
335 | | - # valid, if not, get the current position from master |
336 | | - if self.log_file is None or self.log_pos is None: |
337 | | - cur = self._stream_connection.cursor() |
338 | | - cur.execute("SHOW MASTER STATUS") |
339 | | - master_status = cur.fetchone() |
340 | | - if master_status is None: |
341 | | - raise BinLogNotEnabled() |
342 | | - self.log_file, self.log_pos = master_status[:2] |
343 | | - cur.close() |
344 | | - |
345 | | - prelude = struct.pack('<i', len(self.log_file) + 11) \ |
346 | | - + bytes(bytearray([COM_BINLOG_DUMP])) |
347 | | - |
348 | | - if self.__resume_stream: |
349 | | - prelude += struct.pack('<I', self.log_pos) |
350 | | - else: |
351 | | - prelude += struct.pack('<I', 4) |
352 | | - |
353 | | - flags = 0 |
354 | | - if not self.__blocking: |
355 | | - flags |= 0x01 # BINLOG_DUMP_NON_BLOCK |
356 | | - prelude += struct.pack('<H', flags) |
357 | | - |
358 | | - prelude += struct.pack('<I', self.__server_id) |
359 | | - prelude += self.log_file.encode() |
360 | | - else: |
361 | 339 | if self.is_mariadb: |
362 | | - # https://mariadb.com/kb/en/5-slave-registration/ |
363 | | - cur = self._stream_connection.cursor() |
364 | | - cur.execute("SET @slave_connect_state='%s'" % self.auto_position) |
365 | | - cur.execute("SET @slave_gtid_strict_mode=1") |
366 | | - cur.execute("SET @slave_gtid_ignore_duplicates=0") |
367 | | - cur.close() |
368 | | - |
369 | | - # https://mariadb.com/kb/en/com_binlog_dump/ |
370 | | - header_size = ( |
371 | | - 4 + # binlog pos |
372 | | - 2 + # binlog flags |
373 | | - 4 + # slave server_id, |
374 | | - 4 # requested binlog file name , set it to empty |
375 | | - ) |
376 | | - |
377 | | - prelude = struct.pack('<i', header_size) + bytes(bytearray([COM_BINLOG_DUMP])) |
378 | | - |
379 | | - # binlog pos |
380 | | - prelude += struct.pack('<i', 4) |
| 340 | + prelude = self.__set_mariadb_settings() |
| 341 | + else: |
| 342 | + # only when log_file and log_pos both provided, the position info is |
| 343 | + # valid, if not, get the current position from master |
| 344 | + if self.log_file is None or self.log_pos is None: |
| 345 | + cur = self._stream_connection.cursor() |
| 346 | + cur.execute("SHOW MASTER STATUS") |
| 347 | + master_status = cur.fetchone() |
| 348 | + if master_status is None: |
| 349 | + raise BinLogNotEnabled() |
| 350 | + self.log_file, self.log_pos = master_status[:2] |
| 351 | + cur.close() |
| 352 | + |
| 353 | + prelude = struct.pack('<i', len(self.log_file) + 11) \ |
| 354 | + + bytes(bytearray([COM_BINLOG_DUMP])) |
| 355 | + |
| 356 | + if self.__resume_stream: |
| 357 | + prelude += struct.pack('<I', self.log_pos) |
| 358 | + else: |
| 359 | + prelude += struct.pack('<I', 4) |
381 | 360 |
|
382 | 361 | flags = 0 |
| 362 | + |
383 | 363 | if not self.__blocking: |
384 | 364 | flags |= 0x01 # BINLOG_DUMP_NON_BLOCK |
385 | | - |
386 | | - # binlog flags |
387 | 365 | prelude += struct.pack('<H', flags) |
388 | 366 |
|
389 | | - # server id (4 bytes) |
390 | 367 | prelude += struct.pack('<I', self.__server_id) |
391 | | - |
392 | | - # empty_binlog_name (4 bytes) |
393 | | - prelude += b'\0\0\0\0' |
394 | | - |
| 368 | + prelude += self.log_file.encode() |
| 369 | + else: |
| 370 | + if self.is_mariadb: |
| 371 | + prelude = self.__set_mariadb_settings() |
395 | 372 | else: |
396 | 373 | # Format for mysql packet master_auto_position |
397 | 374 | # |
@@ -473,6 +450,48 @@ def __connect_to_stream(self): |
473 | 450 | self._stream_connection._next_seq_id = 1 |
474 | 451 | self.__connected_stream = True |
475 | 452 |
|
| 453 | + def __set_mariadb_settings(self): |
| 454 | + # https://mariadb.com/kb/en/5-slave-registration/ |
| 455 | + cur = self._stream_connection.cursor() |
| 456 | + if self.auto_position != None : |
| 457 | + cur.execute("SET @slave_connect_state='%s'" % self.auto_position) |
| 458 | + cur.execute("SET @slave_gtid_strict_mode=1") |
| 459 | + cur.execute("SET @slave_gtid_ignore_duplicates=0") |
| 460 | + cur.close() |
| 461 | + |
| 462 | + # https://mariadb.com/kb/en/com_binlog_dump/ |
| 463 | + header_size = ( |
| 464 | + 4 + # binlog pos |
| 465 | + 2 + # binlog flags |
| 466 | + 4 + # slave server_id, |
| 467 | + 4 # requested binlog file name , set it to empty |
| 468 | + ) |
| 469 | + |
| 470 | + prelude = struct.pack('<i', header_size) + bytes(bytearray([COM_BINLOG_DUMP])) |
| 471 | + |
| 472 | + # binlog pos |
| 473 | + prelude += struct.pack('<i', 4) |
| 474 | + |
| 475 | + flags = 0 |
| 476 | + |
| 477 | + # Enable annotate rows event |
| 478 | + if self.__annotate_rows_event: |
| 479 | + flags |= 0x02 # BINLOG_SEND_ANNOTATE_ROWS_EVENT |
| 480 | + |
| 481 | + if not self.__blocking: |
| 482 | + flags |= 0x01 # BINLOG_DUMP_NON_BLOCK |
| 483 | + |
| 484 | + # binlog flags |
| 485 | + prelude += struct.pack('<H', flags) |
| 486 | + |
| 487 | + # server id (4 bytes) |
| 488 | + prelude += struct.pack('<I', self.__server_id) |
| 489 | + |
| 490 | + # empty_binlog_name (4 bytes) |
| 491 | + prelude += b'\0\0\0\0' |
| 492 | + |
| 493 | + return prelude |
| 494 | + |
476 | 495 | def fetchone(self): |
477 | 496 | while True: |
478 | 497 | if self.end_log_pos and self.is_past_end_log_pos: |
@@ -600,7 +619,8 @@ def _allowed_event_list(self, only_events, ignored_events, |
600 | 619 | TableMapEvent, |
601 | 620 | HeartbeatLogEvent, |
602 | 621 | NotImplementedEvent, |
603 | | - MariadbGtidEvent |
| 622 | + MariadbGtidEvent, |
| 623 | + MariadbAnnotateRowsEvent |
604 | 624 | )) |
605 | 625 | if ignored_events is not None: |
606 | 626 | for e in ignored_events: |
|
0 commit comments