|
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