Skip to content

Commit 6150f0e

Browse files
authored
Implement rows query event from mysql (#112)
1 parent c2c2ea7 commit 6150f0e

File tree

9 files changed

+126
-3
lines changed

9 files changed

+126
-3
lines changed

.github/workflows/tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424

2525
- name: Start mysql service
2626
run: |
27-
echo -e "\n[mysqld]\nserver-id=1\nbinlog_format=row\nlog_bin=/var/log/mysql/mysql-bin.log" | sudo tee -a /etc/mysql/my.cnf
27+
echo -e "\n[mysqld]\nserver-id=1\nbinlog_format=row\nlog_bin=/var/log/mysql/mysql-bin.log\nbinlog_rows_query_log_events=ON" | sudo tee -a /etc/mysql/my.cnf
2828
sudo /etc/init.d/mysql start
2929
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -proot
3030

docker-compose.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ services:
1212
'--log_bin=binlog',
1313
'--max_binlog_size=8M',
1414
'--binlog_format=row',
15-
'--server-id=1'
15+
'--server-id=1',
16+
'--binlog_rows_query_log_events=ON'
1617
]
1718
environment:
1819
- MYSQL_ROOT_PASSWORD=root

src/MySQLReplication/Definitions/ConstEventsNames.php

+1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ enum ConstEventsNames: string
1717
case TABLE_MAP = 'tableMap';
1818
case WRITE = 'write';
1919
case FORMAT_DESCRIPTION = 'format description';
20+
case ROWS_QUERY = 'rows_query';
2021
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MySQLReplication\Event\DTO;
6+
7+
use MySQLReplication\Definitions\ConstEventsNames;
8+
use MySQLReplication\Event\EventInfo;
9+
10+
class RowsQueryDTO extends EventDTO
11+
{
12+
private ConstEventsNames $type = ConstEventsNames::ROWS_QUERY;
13+
14+
public function __construct(
15+
EventInfo $eventInfo,
16+
public readonly string $query,
17+
) {
18+
parent::__construct($eventInfo);
19+
}
20+
21+
public function __toString(): string
22+
{
23+
return PHP_EOL .
24+
'=== Event ' . $this->getType() . ' === ' . PHP_EOL .
25+
'Date: ' . $this->eventInfo->getDateTime() . PHP_EOL .
26+
'Log position: ' . $this->eventInfo->pos . PHP_EOL .
27+
'Event size: ' . $this->eventInfo->size . PHP_EOL .
28+
'Query: ' . $this->query . PHP_EOL;
29+
}
30+
31+
public function getType(): string
32+
{
33+
return $this->type->value;
34+
}
35+
36+
public function jsonSerialize(): array
37+
{
38+
return get_object_vars($this);
39+
}
40+
}

src/MySQLReplication/Event/Event.php

+5
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ private function makeEvent(BinaryDataReader $binaryDataReader): ?EventDTO
120120
);
121121
}
122122

123+
// The Rows Query Log Event will be triggered with enabled MySQL Config `binlog_rows_query_log_events`
124+
if ($eventInfo->type === ConstEventType::ROWS_QUERY_LOG_EVENT->value) {
125+
return (new RowsQueryEvent($eventInfo, $binaryDataReader, $this->binLogServerInfo))->makeRowsQueryDTO();
126+
}
127+
123128
if ($eventInfo->type === ConstEventType::FORMAT_DESCRIPTION_EVENT->value) {
124129
return new FormatDescriptionEventDTO($eventInfo);
125130
}

src/MySQLReplication/Event/EventSubscribers.php

+7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use MySQLReplication\Event\DTO\MariaDbGtidLogDTO;
1414
use MySQLReplication\Event\DTO\QueryDTO;
1515
use MySQLReplication\Event\DTO\RotateDTO;
16+
use MySQLReplication\Event\DTO\RowsQueryDTO;
1617
use MySQLReplication\Event\DTO\TableMapDTO;
1718
use MySQLReplication\Event\DTO\UpdateRowsDTO;
1819
use MySQLReplication\Event\DTO\WriteRowsDTO;
@@ -35,6 +36,7 @@ public static function getSubscribedEvents(): array
3536
ConstEventsNames::MARIADB_GTID->value => 'onMariaDbGtid',
3637
ConstEventsNames::FORMAT_DESCRIPTION->value => 'onFormatDescription',
3738
ConstEventsNames::HEARTBEAT->value => 'onHeartbeat',
39+
ConstEventsNames::ROWS_QUERY->value => 'onRowsQuery',
3840
];
3941
}
4042

@@ -93,6 +95,11 @@ public function onHeartbeat(HeartbeatDTO $event): void
9395
$this->allEvents($event);
9496
}
9597

98+
public function onRowsQuery(RowsQueryDTO $event): void
99+
{
100+
$this->allEvents($event);
101+
}
102+
96103
protected function allEvents(EventDTO $event): void
97104
{
98105
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MySQLReplication\Event;
6+
7+
use MySQLReplication\Event\DTO\RowsQueryDTO;
8+
9+
/**
10+
* The Rows_query event is within the binary log when the MySQL Option `binlog_rows_query_log_events`
11+
* is enabled.
12+
*
13+
* @see https://dev.mysql.com/doc/dev/mysql-server/latest/classRows__query__log__event.html
14+
*/
15+
class RowsQueryEvent extends EventCommon
16+
{
17+
public function makeRowsQueryDTO(): RowsQueryDTO
18+
{
19+
// $this->binaryDataReader->advance(1);
20+
return new RowsQueryDTO(
21+
$this->eventInfo,
22+
$this->binaryDataReader->read($this->binaryDataReader->readInt8()),
23+
);
24+
}
25+
}

tests/Integration/BaseCase.php

+9-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ protected function setUp(): void
4141
->withHost('0.0.0.0')
4242
->withPassword('root')
4343
->withPort(3306)
44-
->withEventsIgnore([ConstEventType::GTID_LOG_EVENT->value]);
44+
->withEventsIgnore($this->getIgnoredEvents());
4545

4646
$this->connect();
4747

@@ -83,6 +83,14 @@ public function connect(): void
8383
$this->connection->executeStatement('SET SESSION sql_mode = \'\';');
8484
}
8585

86+
protected function getIgnoredEvents(): array
87+
{
88+
return [
89+
ConstEventType::GTID_LOG_EVENT->value, // Generally in here
90+
ConstEventType::ROWS_QUERY_LOG_EVENT->value, // Just debugging, there is a special test for it
91+
];
92+
}
93+
8694
protected function getEvent(): EventDTO
8795
{
8896
if ($this->mySQLReplicationFactory === null) {

tests/Integration/RowsQueryTest.php

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MySQLReplication\Tests\Integration;
6+
7+
use MySQLReplication\Definitions\ConstEventType;
8+
use MySQLReplication\Event\DTO\QueryDTO;
9+
use MySQLReplication\Event\DTO\RowsQueryDTO;
10+
11+
final class RowsQueryTest extends BaseCase
12+
{
13+
public function testThatTheEditingQueryIsReadFromBinLog(): void
14+
{
15+
$this->connection->executeStatement(
16+
'CREATE TABLE test (id INT NOT NULL AUTO_INCREMENT, data VARCHAR (50) NOT NULL, PRIMARY KEY (id))'
17+
);
18+
19+
$insertQuery = 'INSERT INTO test (data) VALUES(\'Hello\') /* Foo:Bar; */';
20+
$this->connection->executeStatement($insertQuery);
21+
22+
// The Create Table Query ... irrelevant content for this test
23+
self::assertInstanceOf(QueryDTO::class, $this->getEvent());
24+
// The BEGIN Query ... irrelevant content for this test
25+
self::assertInstanceOf(QueryDTO::class, $this->getEvent());
26+
27+
$rowsQueryEvent = $this->getEvent();
28+
self::assertInstanceOf(RowsQueryDTO::class, $rowsQueryEvent);
29+
self::assertSame($insertQuery, $rowsQueryEvent->query);
30+
}
31+
32+
protected function getIgnoredEvents(): array
33+
{
34+
return [ConstEventType::GTID_LOG_EVENT->value];
35+
}
36+
}

0 commit comments

Comments
 (0)