init
Some checks failed
Build Debezium (Push) / Update Dependencies (push) Has been cancelled
Build Debezium (Push) / Checkstyle and Formatting (push) Has been cancelled
Build Debezium (Push) / MongoDB ${{ matrix.version-mongo-server }} (5.0) (push) Has been cancelled
Build Debezium (Push) / MongoDB ${{ matrix.version-mongo-server }} (7.0) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci, 8.0) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci, 8.4) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci, 9.0) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci-gtids, 8.0) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci-gtids, 8.4) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci-gtids, 9.0) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci-percona, 8.0) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci-percona, 8.4) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci-percona, 9.0) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci-ssl, 8.0) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci-ssl, 8.4) (push) Has been cancelled
Build Debezium (Push) / MySQL ${{ matrix.version-mysql-server }} - ${{ matrix.profile }} (mysql-ci-ssl, 9.0) (push) Has been cancelled
Build Debezium (Push) / MariaDB - ${{ matrix.profile }} (mysql-ci) (push) Has been cancelled
Build Debezium (Push) / MariaDB - ${{ matrix.profile }} (mysql-ci-gtids) (push) Has been cancelled
Build Debezium (Push) / PostgreSQL - ${{ matrix.profile }} (assembly,postgres-12) (push) Has been cancelled
Build Debezium (Push) / PostgreSQL - ${{ matrix.profile }} (assembly,postgres-16,pgoutput-decoder) (push) Has been cancelled
Build Debezium (Push) / SQL Server (push) Has been cancelled
Build Debezium (Push) / Oracle (push) Has been cancelled
Build Debezium (Push) / Quarkus Outbox Extension (push) Has been cancelled
Build Debezium (Push) / REST Extension (push) Has been cancelled
Build Debezium (Push) / Schema Generator (push) Has been cancelled
Build Debezium (Push) / Testing Module (push) Has been cancelled
Build Debezium (Push) / Storage Module (push) Has been cancelled
Build Debezium (Push) / Cassandra (push) Has been cancelled
Build Debezium (Push) / Db2 (push) Has been cancelled
Build Debezium (Push) / Informix (push) Has been cancelled
Build Debezium (Push) / IBMi (push) Has been cancelled
Build Debezium (Push) / Vitess (push) Has been cancelled
Build Debezium (Push) / Spanner (push) Has been cancelled
Build Debezium (Push) / JDBC (push) Has been cancelled
Build Debezium (Push) / Debezium Server (push) Has been cancelled

This commit is contained in:
avr 2024-09-13 13:04:03 +03:00
parent 23b8aaa56f
commit 3547a160b1
172 changed files with 1 additions and 10989 deletions

View File

@ -1,1044 +0,0 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>io.debezium</groupId>
<artifactId>debezium-parent</artifactId>
<version>3.0.0-SNAPSHOT</version>
<relativePath>../debezium-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>debezium-connector-mariadb</artifactId>
<name>Debezium Connector for MariaDB</name>
<packaging>jar</packaging>
<dependencies>
<!-- Runtime dependencies -->
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-connector-binlog</artifactId>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>connect-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Testing dependencies -->
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-connector-binlog</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-core</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-embedded</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-embedded</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-testing-testcontainers</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
</exclusion>
<exclusion>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mil.nga</groupId>
<artifactId>wkb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.confluent</groupId>
<artifactId>kafka-connect-avro-converter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.apicurio</groupId>
<artifactId>apicurio-registry-utils-converter</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>slf4j-jboss-logmanager</artifactId>
<groupId>org.jboss.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mariadb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<!-- Used for unit testing with Kafka -->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_${version.kafka.scala}</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<!--
Specify the properties for the various Docker containers.
-->
<mariadb.server.image.source>mariadb</mariadb.server.image.source>
<version.mariadb.server>11.4.3</version.mariadb.server>
<mariadb.user>mysqluser</mariadb.user>
<mariadb.password>mysqlpw</mariadb.password>
<mariadb.replica.user>mysqlreplica</mariadb.replica.user>
<mariadb.replica.password>mysqlpw</mariadb.replica.password>
<mariadb.port>3306</mariadb.port>
<mariadb.percona.port>3306</mariadb.percona.port>
<mariadb.gtid.port>3306</mariadb.gtid.port>
<mariadb.gtid.replica.port>3306</mariadb.gtid.replica.port>
<mariadb.ssl.port>3306</mariadb.ssl.port>
<mariadb.replica.port>3306</mariadb.replica.port> <!-- by default use primary as 'replica' -->
<mariadb.init.timeout>60000</mariadb.init.timeout> <!-- 60 seconds -->
<apicurio.port>8080</apicurio.port>
<apicurio.init.timeout>60000</apicurio.init.timeout> <!-- 60 seconds -->
<mariadb.replica.fileset.path>${project.basedir}/src/test/docker/init-replica</mariadb.replica.fileset.path>
<!--
By default, we should use the docker image maintained by the MariaDB team. This property is changed with different profiles.
However, we run one container with GTIDs and one without.
-->
<docker.dbs>debezium/mariadb-server-test-database</docker.dbs>
<docker.filter>${docker.dbs}</docker.filter>
<docker.skip>false</docker.skip>
<docker.initimage>rm -f /etc/localtime; ln -s /usr/share/zoneinfo/Pacific/Samoa /etc/localtime</docker.initimage>
</properties>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<watchInterval>500</watchInterval>
<logDate>default</logDate>
<verbose>true</verbose>
<imagePullPolicy>IfNotPresent</imagePullPolicy>
<images>
<!--
Images based on "${mariadb.server.image.source}" Docker image
-->
<image>
<!-- A Docker image using a partial MariaDB installation maintained by MariaDB team. -->
<name>debezium/mariadb-server-test-database</name>
<run>
<namingStrategy>none</namingStrategy>
<env>
<MARIADB_ROOT_PASSWORD>debezium-rocks</MARIADB_ROOT_PASSWORD>
<MARIADB_DATABASE>mysql</MARIADB_DATABASE> <!-- database created upon init -->
<MARIADB_USER>${mariadb.user}</MARIADB_USER>
<MARIADB_PASSWORD>${mariadb.password}</MARIADB_PASSWORD>
</env>
<ports>
<port>${mariadb.port}:3306</port>
</ports>
<log>
<prefix>mariadb</prefix>
<enabled>true</enabled>
<color>yellow</color>
</log>
<wait>
<log>(MariaDB) init process done. Ready for start up.(?s)(.*)(mariadbd): ready for connections.</log>
<time>${mariadb.init.timeout}</time>
</wait>
</run>
<build>
<from>${mariadb.server.image.source}:${version.mariadb.server}</from>
<runCmds>
<run>${docker.initimage}</run>
</runCmds>
<assembly>
<inline>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/test/docker/server</directory>
<includes>
<include>my.cnf</include>
</includes>
<outputDirectory>etc/mysql</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/test/docker/init</directory>
<outputDirectory>docker-entrypoint-initdb.d</outputDirectory>
</fileSet>
</fileSets>
</inline>
<targetDir>/</targetDir>
</assembly>
</build>
<external>
<type>properties</type>
<mode>override</mode>
</external>
</image>
<image>
<!-- A Docker image using a partial MariaDB installation maintained by MariaDB team
that enable MariaDB ssl connection -->
<name>debezium/mariadb-server-test-database-ssl</name>
<run>
<namingStrategy>none</namingStrategy>
<env>
<MARIADB_ROOT_PASSWORD>debezium-rocks</MARIADB_ROOT_PASSWORD>
<MARIADB_DATABASE>mysql</MARIADB_DATABASE> <!-- database created upon init -->
<MARIADB_USER>${mariadb.user}</MARIADB_USER>
<MARIADB_PASSWORD>${mariadb.password}</MARIADB_PASSWORD>
</env>
<ports>
<port>${mariadb.ssl.port}:3306</port>
</ports>
<volumes>
<bind>
<volume>${project.basedir}/src/test/resources/ssl-certs:/etc/certs</volume>
</bind>
</volumes>
<log>
<prefix>mariadb</prefix>
<enabled>true</enabled>
<color>yellow</color>
</log>
<wait>
<log>(MariaDB) init process done. Ready for start up.(?s)(.*)(mariadbd): ready for connections.</log>
<time>${mariadb.init.timeout}</time>
</wait>
</run>
<build>
<from>${mariadb.server.image.source}:${version.mariadb.server}</from>
<runCmds>
<run>${docker.initimage}</run>
</runCmds>
<assembly>
<inline>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/test/docker/server-ssl</directory>
<includes>
<include>my.cnf</include>
</includes>
<outputDirectory>etc/mysql</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/test/docker/init</directory>
<outputDirectory>docker-entrypoint-initdb.d</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/test/docker/init-ssl</directory>
<outputDirectory>docker-entrypoint-initdb.d</outputDirectory>
</fileSet>
</fileSets>
</inline>
<targetDir>/</targetDir>
</assembly>
</build>
<external>
<type>properties</type>
<mode>override</mode>
</external>
</image>
<image>
<!-- A Docker image using a partial MariaDB installation maintained by MariaDB team. -->
<name>debezium/mariadb-server-gtids-test-database</name>
<alias>database-gtids</alias>
<run>
<namingStrategy>alias</namingStrategy>
<env>
<MARIADB_ROOT_PASSWORD>debezium-rocks</MARIADB_ROOT_PASSWORD>
<MARIADB_DATABASE>mysql</MARIADB_DATABASE> <!-- database created upon init -->
<MARIADB_USER>${mariadb.user}</MARIADB_USER>
<MARIADB_PASSWORD>${mariadb.password}</MARIADB_PASSWORD>
</env>
<ports>
<port>${mariadb.gtid.port}:3306</port>
</ports>
<log>
<prefix>mariadb-gtids</prefix>
<enabled>true</enabled>
<color>cyan</color>
</log>
<wait>
<log>(MariaDB) init process done. Ready for start up.(?s)(.*)(mariadbd): ready for connections.</log>
<time>${mariadb.init.timeout}</time>
</wait>
</run>
<build>
<from>${mariadb.server.image.source}:${version.mariadb.server}</from>
<runCmds>
<run>${docker.initimage}</run>
</runCmds>
<assembly>
<inline>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/test/docker/server-gtids</directory>
<includes>
<include>my.cnf</include>
</includes>
<outputDirectory>etc/mysql</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/test/docker/init</directory>
<outputDirectory>docker-entrypoint-initdb.d</outputDirectory>
</fileSet>
</fileSets>
</inline>
<targetDir>/</targetDir>
</assembly>
</build>
<external>
<type>properties</type>
<mode>override</mode>
</external>
</image>
<image>
<!--
A Docker image using a MariaDB installation maintained by MariaDB team
that is a replica of `debezium/mariadb-server-gtids-test-database`
-->
<name>debezium/mariadb-server-gtids-test-database-replica</name>
<run>
<namingStrategy>none</namingStrategy>
<env>
<MARIADB_ROOT_PASSWORD>debezium-rocks</MARIADB_ROOT_PASSWORD>
<MARIADB_USER>${mariadb.replica.user}</MARIADB_USER>
<MARIADB_PASSWORD>${mariadb.replica.password}</MARIADB_PASSWORD>
</env>
<links>
<link>database-gtids</link>
</links>
<ports>
<port>${mariadb.gtid.replica.port}:3306</port>
</ports>
<log>
<prefix>mariadb-gtids-replica</prefix>
<enabled>true</enabled>
<color>magenta</color>
</log>
<wait>
<log>(MariaDB) init process done. Ready for start up.(?s)(.*)(mariadbd): ready for connections.</log>
<time>${mariadb.init.timeout}</time>
</wait>
</run>
<build>
<from>${mariadb.server.image.source}:${version.mariadb.server}</from>
<runCmds>
<run>${docker.initimage}</run>
</runCmds>
<assembly>
<inline>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/test/docker/server-replica</directory>
<includes>
<include>my.cnf</include>
</includes>
<outputDirectory>etc/mysql</outputDirectory>
</fileSet>
<fileSet>
<directory>${mariadb.replica.fileset.path}</directory>
<outputDirectory>docker-entrypoint-initdb.d</outputDirectory>
</fileSet>
</fileSets>
</inline>
<targetDir>/</targetDir>
</assembly>
</build>
<external>
<type>properties</type>
<mode>override</mode>
</external>
</image>
<image>
<name>apicurio/apicurio-registry-mem:${version.apicurio}</name>
<run>
<namingStrategy>none</namingStrategy>
<ports>
<port>${apicurio.port}:8080</port>
</ports>
<log>
<prefix>apicurio</prefix>
<enabled>true</enabled>
<color>blue</color>
</log>
<wait>
<log>.*apicurio-registry-app.*started in.*</log>
<time>${apicurio.init.timeout}</time>
</wait>
</run>
</image>
</images>
</configuration>
<!--
Connect this plugin to the maven lifecycle around the integration-test phase:
start the container in pre-integration-test and stop it in post-integration-test.
-->
<executions>
<execution>
<id>start</id>
<phase>pre-integration-test</phase>
<goals>
<goal>build</goal>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<!--
Unlike surefire, the failsafe plugin ensures 'post-integration-test' phase always runs, even
when there are failed integration tests. We rely upon this to always shut down the Docker container
after the integration tests (defined as '*IT.java') are run.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<skipTests>${skipITs}</skipTests>
<enableAssertions>true</enableAssertions>
<systemPropertyVariables>
<!-- Make these available to the tests via system properties -->
<database.hostname>${docker.host.address}</database.hostname>
<database.port>${mariadb.port}</database.port>
<database.user>${mariadb.user}</database.user>
<database.password>${mariadb.password}</database.password>
<database.replica.hostname>${docker.host.address}</database.replica.hostname>
<database.replica.port>${mariadb.replica.port}</database.replica.port>
<!-- Specifies which driver to use for the tests -->
<skipLongRunningTests>${skipLongRunningTests}</skipLongRunningTests>
<database.ssl.mode>disabled</database.ssl.mode>
</systemPropertyVariables>
<runOrder>${runOrder}</runOrder>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.debezium</groupId>
<artifactId>debezium-schema-generator</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<id>generate-connector-metadata</id>
<goals>
<goal>generate-api-spec</goal>
</goals>
<phase>prepare-package</phase>
<configuration>
<outputDirectory>${project.build.outputDirectory}/META-INF/resources/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<!-- Apply the properties set in the POM to the resource files -->
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<includes>
<include>*</include>
<include>**/*</include>
</includes>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>false</filtering>
<includes>
<include>*</include>
<include>**/*</include>
</includes>
</testResource>
</testResources>
</build>
<!--
Define several useful profiles
-->
<profiles>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This assembly profile is used during official builds. In addition to
compiling, and running the unit and integration tests like the non-assembly
profiles, this profile creates additional (like the connector plugin archives),
starts up all three Docker containers (normal MariaDB, MariaDB+GTIDs, and alt-MariaDB)
and runs the integration tests against each of them.
To use, specify "-Passembly" on the Maven command line.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<profile>
<id>assembly</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<!-- Run multiple images at the same time, but use different ports for all MariaDB servers -->
<docker.dbs>
debezium/mariadb-server-test-database,debezium/mariadb-server-gtids-test-database,debezium/mariadb-server-gtids-test-database-replica,debezium/mariadb-server-test-database-ssl
</docker.dbs>
<mariadb.port>4301</mariadb.port>
<mariadb.gtid.port>4302</mariadb.gtid.port>
<mariadb.gtid.replica.port>4303</mariadb.gtid.replica.port>
<mariadb.percona.port>4304</mariadb.percona.port>
<mariadb.ssl.port>4305</mariadb.ssl.port>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<dependencies>
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-assembly-descriptors</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>default</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<attach>true</attach> <!-- we want attach & deploy these to Maven -->
<descriptorRefs>
<descriptorRef>${assembly.descriptor}</descriptorRef>
</descriptorRefs>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
<!--
Override the failsafe plugin to run the integration tests for each set of databases.
But make sure each database server is used only once ...
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${version.failsafe.plugin}</version>
<configuration>
<skipTests>${skipITs}</skipTests>
<enableAssertions>true</enableAssertions>
<systemPropertyVariables>
<!-- Make these available to the tests via system properties -->
<database.hostname>${docker.host.address}</database.hostname>
<database.user>${mariadb.user}</database.user>
<database.password>${mariadb.password}</database.password>
<database.replica.hostname>${docker.host.address}</database.replica.hostname>
<database.replica.user>${mariadb.replica.user}</database.replica.user>
<database.replica.password>${mariadb.replica.password}</database.replica.password>
<database.port>${mariadb.port}</database.port>
<database.replica.port>${mariadb.port}</database.replica.port>
<database.ssl.mode>disabled</database.ssl.mode>
<!-- Specifies which driver to use for the tests -->
<skipLongRunningTests>false</skipLongRunningTests>
<isAssemblyProfileActive>true</isAssemblyProfileActive>
</systemPropertyVariables>
<runOrder>${runOrder}</runOrder>
</configuration>
<executions>
<!-- First run the integration tests with the non-GTID server alone -->
<execution>
<id>integration-test-mariadb</id>
<goals>
<goal>integration-test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<!-- same port for both, since we're only running one server -->
<database.port>${mariadb.port}</database.port>
<database.replica.port>${mariadb.port}</database.replica.port>
</systemPropertyVariables>
</configuration>
</execution>
<!-- Then run the integration tests with the GTID server + replica server -->
<execution>
<id>integration-test-mariadb-gtids-with-replica</id>
<goals>
<goal>integration-test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<database.port>${mariadb.gtid.port}</database.port>
<database.replica.port>${mariadb.gtid.replica.port}</database.replica.port>
</systemPropertyVariables>
</configuration>
</execution>
<!-- SSL -->
<execution>
<id>integration-test-ssl</id>
<goals>
<goal>integration-test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<database.ssl.mode>verify_ca</database.ssl.mode>
<database.ssl.truststore>${project.basedir}/src/test/resources/ssl/truststore</database.ssl.truststore>
<database.ssl.truststore.password>debezium</database.ssl.truststore.password>
<database.ssl.keystore>${project.basedir}/src/test/resources/ssl/keystore</database.ssl.keystore>
<database.ssl.keystore.password>debezium</database.ssl.keystore.password>
<!-- same port for both, since we're only running one server -->
<database.port>${mariadb.ssl.port}</database.port>
<database.replica.port>${mariadb.ssl.port}</database.replica.port>
</systemPropertyVariables>
</configuration>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Do not perform any Docker-related functionality
To use, specify "-DskipITs" on the Maven command line.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<profile>
<id>skip-integration-tests</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>skipITs</name>
</property>
</activation>
<properties>
<docker.skip>true</docker.skip>
</properties>
</profile>
<profile>
<id>quick</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>quick</name>
</property>
</activation>
<properties>
<skipITs>true</skipITs>
<docker.skip>true</docker.skip>
</properties>
</profile>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the alternative Docker image for MariaDB.
To use, specify "-Dmariadb-gtids" or -Pmariadb-gtids on the Maven command line.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<profile>
<id>mariadb-gtids</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>mariadb-gtids</name>
</property>
</activation>
<properties>
<!-- Docker properties -->
<docker.dbs>debezium/mariadb-server-gtids-test-database</docker.dbs>
<!-- Integration test properties -->
<database.port>${mariadb.gtid.port}</database.port>
<database.replica.port>${mariadb.gtid.port}</database.replica.port>
</properties>
</profile>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the Docker image for a MariaDB replica of another MariaDB server
configured to use GTIDs. To use, specify "-Dmariadb-replica"
or -Pmariadb-replica on the Maven command line.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<profile>
<id>mariadb-replica</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>mariadb-replica</name>
</property>
</activation>
<properties>
<!-- Docker properties -->
<mariadb.gtid.port>3306</mariadb.gtid.port>
<mariadb.gtid.replica.port>4306</mariadb.gtid.replica.port>
<docker.dbs>debezium/mariadb-server-gtids-test-database,debezium/mariadb-server-gtids-test-database-replica</docker.dbs>
<!-- Integration test properties -->
<database.port>${mariadb.gtid.port}</database.port>
<database.replica.port>${mariadb.gtid.replica.port}</database.replica.port>
</properties>
</profile>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the alternative Docker image for MariaDB.
To use, specify "-Dmariadb-ssl" or -Pmariadb-ssl on the Maven command line.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<profile>
<id>mariadb-ssl</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>mariadb-ssl</name>
</property>
</activation>
<properties>
<!-- Docker properties -->
<docker.dbs>debezium/mariadb-server-test-database-ssl</docker.dbs>
<!-- Integration test properties -->
<database.port>${mariadb.ssl.port}</database.port>
<database.replica.port>${mariadb.ssl.port}</database.replica.port>
<docker.initimage>rm -f /etc/localtime; ln -s /usr/share/zoneinfo/Pacific/Pago_Pago /etc/localtime</docker.initimage>
</properties>
</profile>
<profile>
<id>apicurio</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>apicurio</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<use.apicurio>true</use.apicurio>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<docker.filter>${docker.dbs},apicurio/apicurio-registry-mem:${version.apicurio}</docker.filter>
</properties>
</profile>
<!-- CI configurations, used for parallel execution on GH actions -->
<!-- Runs tests only with standalone -->
<profile>
<id>mariadb-ci</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<docker.dbs>debezium/mariadb-server-test-database</docker.dbs>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<dependencies>
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-assembly-descriptors</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>default</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<attach>true</attach> <!-- we want attach & deploy these to Maven -->
<descriptorRefs>
<descriptorRef>${assembly.descriptor}</descriptorRef>
</descriptorRefs>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${version.failsafe.plugin}</version>
<configuration>
<skipTests>${skipITs}</skipTests>
<enableAssertions>true</enableAssertions>
<systemPropertyVariables>
<!-- Make these available to the tests via system properties -->
<database.hostname>${docker.host.address}</database.hostname>
<database.user>${mariadb.user}</database.user>
<database.password>${mariadb.password}</database.password>
<database.replica.hostname>${docker.host.address}</database.replica.hostname>
<database.replica.user>${mariadb.replica.user}</database.replica.user>
<database.replica.password>${mariadb.replica.password}</database.replica.password>
<database.port>${mariadb.port}</database.port>
<database.replica.port>${mariadb.port}</database.replica.port>
<database.ssl.mode>disabled</database.ssl.mode>
<!-- Specifies which driver to use for the tests -->
<skipLongRunningTests>false</skipLongRunningTests>
<isAssemblyProfileActive>true</isAssemblyProfileActive>
</systemPropertyVariables>
<runOrder>${runOrder}</runOrder>
</configuration>
<executions>
<execution>
<id>integration-test-mariadb</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- Runs tests only with GTID setup -->
<profile>
<id>mariadb-ci-gtids</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<docker.dbs>debezium/mariadb-server-gtids-test-database,debezium/mariadb-server-gtids-test-database-replica</docker.dbs>
<mariadb.gtid.port>4302</mariadb.gtid.port>
<mariadb.gtid.replica.port>4303</mariadb.gtid.replica.port>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<dependencies>
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-assembly-descriptors</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>default</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<attach>true</attach> <!-- we want attach & deploy these to Maven -->
<descriptorRefs>
<descriptorRef>${assembly.descriptor}</descriptorRef>
</descriptorRefs>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${version.failsafe.plugin}</version>
<configuration>
<skipTests>${skipITs}</skipTests>
<enableAssertions>true</enableAssertions>
<systemPropertyVariables>
<!-- Make these available to the tests via system properties -->
<database.hostname>${docker.host.address}</database.hostname>
<database.user>${mariadb.user}</database.user>
<database.password>${mariadb.password}</database.password>
<database.replica.hostname>${docker.host.address}</database.replica.hostname>
<database.replica.user>${mariadb.replica.user}</database.replica.user>
<database.replica.password>${mariadb.replica.password}</database.replica.password>
<database.port>${mariadb.gtid.port}</database.port>
<database.replica.port>${mariadb.gtid.replica.port}</database.replica.port>
<database.ssl.mode>disabled</database.ssl.mode>
<!-- Specifies which driver to use for the tests -->
<skipLongRunningTests>false</skipLongRunningTests>
<isAssemblyProfileActive>true</isAssemblyProfileActive>
</systemPropertyVariables>
<runOrder>${runOrder}</runOrder>
</configuration>
<executions>
<execution>
<id>integration-test-mariadb-gtids-with-replica</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- Runs tests only with SSL setup -->
<profile>
<id>mariadb-ci-ssl</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<docker.dbs>debezium/mariadb-server-test-database-ssl</docker.dbs>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<dependencies>
<dependency>
<groupId>io.debezium</groupId>
<artifactId>debezium-assembly-descriptors</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>default</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<attach>true</attach> <!-- we want attach & deploy these to Maven -->
<descriptorRefs>
<descriptorRef>${assembly.descriptor}</descriptorRef>
</descriptorRefs>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${version.failsafe.plugin}</version>
<configuration>
<skipTests>${skipITs}</skipTests>
<enableAssertions>true</enableAssertions>
<systemPropertyVariables>
<!-- Make these available to the tests via system properties -->
<database.hostname>${docker.host.address}</database.hostname>
<database.user>${mariadb.user}</database.user>
<database.password>${mariadb.password}</database.password>
<database.replica.hostname>${docker.host.address}</database.replica.hostname>
<database.replica.user>${mariadb.replica.user}</database.replica.user>
<database.replica.password>${mariadb.replica.password}</database.replica.password>
<database.port>${mariadb.port}</database.port>
<database.replica.port>${mariadb.port}</database.replica.port>
<database.ssl.mode>verify_ca</database.ssl.mode>
<!-- Specifies which driver to use for the tests -->
<skipLongRunningTests>false</skipLongRunningTests>
<isAssemblyProfileActive>true</isAssemblyProfileActive>
<database.ssl.truststore>${project.basedir}/src/test/resources/ssl/truststore</database.ssl.truststore>
<database.ssl.truststore.password>debezium</database.ssl.truststore.password>
<database.ssl.keystore>${project.basedir}/src/test/resources/ssl/keystore</database.ssl.keystore>
<database.ssl.keystore.password>debezium</database.ssl.keystore.password>
</systemPropertyVariables>
<runOrder>${runOrder}</runOrder>
</configuration>
<executions>
<execution>
<id>integration-test-ssl</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -1,152 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.util.Optional;
import java.util.function.Function;
import org.apache.kafka.connect.source.SourceRecord;
import io.debezium.connector.base.ChangeEventQueue;
import io.debezium.connector.binlog.jdbc.BinlogConnectorConnection;
import io.debezium.connector.mariadb.metrics.MariaDbSnapshotChangeEventSourceMetrics;
import io.debezium.connector.mariadb.metrics.MariaDbStreamingChangeEventSourceMetrics;
import io.debezium.jdbc.MainConnectionProvidingConnectionFactory;
import io.debezium.pipeline.DataChangeEvent;
import io.debezium.pipeline.ErrorHandler;
import io.debezium.pipeline.EventDispatcher;
import io.debezium.pipeline.notification.NotificationService;
import io.debezium.pipeline.source.snapshot.incremental.IncrementalSnapshotChangeEventSource;
import io.debezium.pipeline.source.snapshot.incremental.SignalBasedIncrementalSnapshotChangeEventSource;
import io.debezium.pipeline.source.spi.ChangeEventSourceFactory;
import io.debezium.pipeline.source.spi.DataChangeEventListener;
import io.debezium.pipeline.source.spi.SnapshotChangeEventSource;
import io.debezium.pipeline.source.spi.SnapshotProgressListener;
import io.debezium.pipeline.source.spi.StreamingChangeEventSource;
import io.debezium.relational.TableId;
import io.debezium.snapshot.SnapshotterService;
import io.debezium.spi.schema.DataCollectionId;
import io.debezium.util.Clock;
import io.debezium.util.Strings;
/**
* @author Chris Cranford
*/
public class MariaDbChangeEventSourceFactory implements ChangeEventSourceFactory<MariaDbPartition, MariaDbOffsetContext> {
private final MariaDbConnectorConfig configuration;
private final MainConnectionProvidingConnectionFactory<BinlogConnectorConnection> connectionFactory;
private final ErrorHandler errorHandler;
private final EventDispatcher<MariaDbPartition, TableId> dispatcher;
private final Clock clock;
private final MariaDbTaskContext taskContext;
private final MariaDbStreamingChangeEventSourceMetrics streamingMetrics;
private final MariaDbDatabaseSchema schema;
// Snapshot requires buffering to modify the last record in the snapshot as sometimes it is
// impossible to detect it till the snapshot is ended. Mainly when the last snapshotted table is empty.
// Based on the DBZ-3113 the code can change in the future, and it will be handled in the core shared code.
private final ChangeEventQueue<DataChangeEvent> queue;
private final SnapshotterService snapshotterService;
public MariaDbChangeEventSourceFactory(MariaDbConnectorConfig configuration,
MainConnectionProvidingConnectionFactory<BinlogConnectorConnection> connectionFactory,
ErrorHandler errorHandler,
EventDispatcher<MariaDbPartition, TableId> dispatcher,
Clock clock,
MariaDbDatabaseSchema schema,
MariaDbTaskContext taskContext,
MariaDbStreamingChangeEventSourceMetrics streamingMetrics,
ChangeEventQueue<DataChangeEvent> queue,
SnapshotterService snapshotterService) {
this.configuration = configuration;
this.connectionFactory = connectionFactory;
this.errorHandler = errorHandler;
this.dispatcher = dispatcher;
this.clock = clock;
this.taskContext = taskContext;
this.streamingMetrics = streamingMetrics;
this.queue = queue;
this.schema = schema;
this.snapshotterService = snapshotterService;
}
@Override
public SnapshotChangeEventSource<MariaDbPartition, MariaDbOffsetContext> getSnapshotChangeEventSource(
SnapshotProgressListener<MariaDbPartition> snapshotProgressListener,
NotificationService<MariaDbPartition, MariaDbOffsetContext> notificationService) {
return new MariaDbSnapshotChangeEventSource(
configuration,
connectionFactory,
taskContext.getSchema(),
dispatcher,
clock,
(MariaDbSnapshotChangeEventSourceMetrics) snapshotProgressListener,
this::modifyAndFlushLastRecord,
this::preSnapshot,
notificationService,
snapshotterService);
}
@Override
public StreamingChangeEventSource<MariaDbPartition, MariaDbOffsetContext> getStreamingChangeEventSource() {
queue.disableBuffering();
return new MariaDbStreamingChangeEventSource(
configuration,
connectionFactory.mainConnection(),
dispatcher,
errorHandler,
clock,
taskContext,
streamingMetrics,
snapshotterService);
}
@Override
public Optional<IncrementalSnapshotChangeEventSource<MariaDbPartition, ? extends DataCollectionId>> getIncrementalSnapshotChangeEventSource(
MariaDbOffsetContext offsetContext,
SnapshotProgressListener<MariaDbPartition> snapshotProgressListener,
DataChangeEventListener<MariaDbPartition> dataChangeEventListener,
NotificationService<MariaDbPartition, MariaDbOffsetContext> notificationService) {
if (configuration.isReadOnlyConnection()) {
if (connectionFactory.mainConnection().isGtidModeEnabled()) {
return Optional.of(new MariaDbReadOnlyIncrementalSnapshotChangeEventSource(
configuration,
connectionFactory.mainConnection(),
dispatcher,
schema,
clock,
snapshotProgressListener,
dataChangeEventListener,
notificationService));
}
throw new UnsupportedOperationException("Read only connection requires GTID_MODE to be ON");
}
// If no data collection id is provided, don't return an instance as the implement requires the table
if (Strings.isNullOrBlank(configuration.getSignalingDataCollectionId())) {
return Optional.empty();
}
return Optional.of(new SignalBasedIncrementalSnapshotChangeEventSource<>(
configuration,
connectionFactory.mainConnection(),
dispatcher,
schema,
clock,
snapshotProgressListener,
dataChangeEventListener,
notificationService));
}
private void preSnapshot() {
queue.enableBuffering();
}
private void modifyAndFlushLastRecord(Function<SourceRecord, SourceRecord> modify) throws InterruptedException {
queue.flushBuffer(dataChange -> new DataChangeEvent(modify.apply(dataChange.getRecord())));
queue.disableBuffering();
}
}

View File

@ -1,60 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.util.Map;
import org.apache.kafka.common.config.ConfigDef;
import org.apache.kafka.common.config.ConfigValue;
import org.apache.kafka.connect.connector.Task;
import io.debezium.config.Configuration;
import io.debezium.connector.binlog.BinlogConnector;
import io.debezium.connector.mariadb.jdbc.MariaDbConnection;
import io.debezium.connector.mariadb.jdbc.MariaDbConnectionConfiguration;
import io.debezium.connector.mariadb.jdbc.MariaDbFieldReader;
/**
* A Debezium source connector that creates tasks and reads changes from MariaDB's binary transaction logs,
* generating change events.
*
* @author Chris Cranford
*/
public class MariaDbConnector extends BinlogConnector<MariaDbConnectorConfig> {
public MariaDbConnector() {
}
@Override
public String version() {
return Module.version();
}
@Override
public Class<? extends Task> taskClass() {
return MariaDbConnectorTask.class;
}
@Override
public ConfigDef config() {
return MariaDbConnectorConfig.configDef();
}
@Override
protected Map<String, ConfigValue> validateAllFields(Configuration config) {
return config.validate(MariaDbConnectorConfig.ALL_FIELDS);
}
@Override
protected MariaDbConnection createConnection(Configuration config, MariaDbConnectorConfig connectorConfig) {
return new MariaDbConnection(new MariaDbConnectionConfiguration(config), new MariaDbFieldReader(connectorConfig));
}
@Override
protected MariaDbConnectorConfig createConnectorConfig(Configuration config) {
return new MariaDbConnectorConfig(config);
}
}

View File

@ -1,301 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.util.Optional;
import java.util.function.Predicate;
import org.apache.kafka.common.config.ConfigDef;
import org.apache.kafka.common.config.ConfigDef.Importance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.debezium.config.CommonConnectorConfig;
import io.debezium.config.ConfigDefinition;
import io.debezium.config.Configuration;
import io.debezium.config.EnumeratedValue;
import io.debezium.config.Field;
import io.debezium.config.Field.ValidationOutput;
import io.debezium.connector.AbstractSourceInfo;
import io.debezium.connector.SourceInfoStructMaker;
import io.debezium.connector.binlog.BinlogConnectorConfig;
import io.debezium.connector.binlog.gtid.GtidSetFactory;
import io.debezium.connector.mariadb.charset.MariaDbCharsetRegistryServiceProvider;
import io.debezium.connector.mariadb.gtid.MariaDbGtidSetFactory;
import io.debezium.connector.mariadb.history.MariaDbHistoryRecordComparator;
import io.debezium.function.Predicates;
import io.debezium.relational.history.HistoryRecordComparator;
/**
* Configuration properties for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbConnectorConfig extends BinlogConnectorConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(MariaDbConnectorConfig.class);
/**
* For MariaDB to mimic MySQL behavior using {@link Integer#MIN_VALUE}, the default fetch
* size must explicitly be set to {@code 1}. This is because MariaDB drivers 3.x+ do not
* support the old non-compliant JDBC-spec style that MySQL uses.
*/
private static final int DEFAULT_NON_STREAMING_FETCH_SIZE = 1;
public static final Field SOURCE_INFO_STRUCT_MAKER = CommonConnectorConfig.SOURCE_INFO_STRUCT_MAKER
.withDefault(MariaDbSourceInfoStructMaker.class.getName());
/**
* The set of predefined snapshot locking mode options.
*/
public enum SnapshotLockingMode implements EnumeratedValue {
/**
* This mode will block all writes for the entire duration of the snapshot.<p></p>
*
* Replaces deprecated configuration option snapshot.locking.minimal with a value of false.
*/
EXTENDED("extended"),
/**
* The connector holds the global read lock for just the initial portion of the snapshot while the connector reads the database
* schemas and other metadata. The remaining work in a snapshot involves selecting all rows from each table, and this can be done
* in a consistent fashion using the REPEATABLE READ transaction even when the global read lock is no longer held and while other
* MySQL clients are updating the database.<p></p>
*
* Replaces deprecated configuration option snapshot.locking.minimal with a value of true.
*/
MINIMAL("minimal"),
/**
* This mode will avoid using ANY table locks during the snapshot process. This mode can only be used with SnapShotMode
* set to schema_only or schema_only_recovery.
*/
NONE("none"),
/**
* Inject a custom mode, which allows for more control over snapshot locking.
*/
CUSTOM("custom");
private final String value;
SnapshotLockingMode(String value) {
this.value = value;
}
@Override
public String getValue() {
return value;
}
public boolean usesMinimalLocking() {
return value.equals(MINIMAL.value);
}
public boolean usesLocking() {
return !value.equals(NONE.value);
}
public boolean flushResetsIsolationLevel() {
return true;
}
/**
* Determine if the supplied value is one of the predefined options.
*
* @param value the configuration property value; may not be null
* @return the matching option, or null if no match is found
*/
public static SnapshotLockingMode parse(String value) {
if (value == null) {
return null;
}
value = value.trim();
for (SnapshotLockingMode option : SnapshotLockingMode.values()) {
if (option.getValue().equalsIgnoreCase(value)) {
return option;
}
}
return null;
}
/**
* Determine if the supplied value is one of the predefined options.
*
* @param value the configuration property value; may not be null
* @param defaultValue the default value; may be null
* @return the matching option, or null if no match is found and the non-null default is invalid
*/
public static SnapshotLockingMode parse(String value, String defaultValue) {
SnapshotLockingMode mode = parse(value);
if (mode == null && defaultValue != null) {
mode = parse(defaultValue);
}
return mode;
}
}
public static final Field SNAPSHOT_LOCKING_MODE = Field.create(SNAPSHOT_LOCKING_MODE_PROPERTY_NAME)
.withDisplayName("Snapshot locking mode")
.withEnum(SnapshotLockingMode.class, SnapshotLockingMode.MINIMAL)
.withImportance(Importance.LOW)
.withDescription("Controls how long the connector holds onto the global read lock while it is performing "
+ "a snapshot. The default is 'minimal', meaning the connector holds the global read lock (and thus "
+ "prevents updates) for just the initial portion of the snapshot while the database schemas and other "
+ "metadata are being read. The remaining work in a snapshot involves selecting all rows from each table, "
+ "and this can be done using the snapshot process' REPEATABLE READ transaction isolation even when the "
+ "lock is no longer held and other operations are updating the database. However, in some cases it may "
+ "be desirable to block all writes for the entire duration of the snapshot; in such cases set this "
+ "to 'extended'. Using a value of 'none' will prevent the connector from acquiring any table locks "
+ "during the snapshot process. This mode can only be used in combination with snapshot.mode values of "
+ "'schema_only' or 'schema_only_recovery' and is only safe to use if no schema changes are happening "
+ "while the snapshot is taken.")
.withValidation(MariaDbConnectorConfig::validateSnapshotLockingMode);
/**
* MariaDB GTID format uses "{@code domain-server-sequence}". This configuration should specify a
* comma-separated list of regular expressions that match the "{@code domain-server}" tuples when
* locating the binlog position in a MariaDB server. Only the GTID ranges that have sources that
* match one of these patterns will be used.
*/
public static final Field GTID_SOURCE_INCLUDES = BinlogConnectorConfig.GTID_SOURCE_INCLUDES
.withDescription("The source domain IDs used to include GTID ranges when determining the starting "
+ "position in the MariaDB server's binlog.");
/**
* MariaDB GTID format uses "{@code domain-server-sequence}". This configuration should specify a
* comma-separataed list of regular expressions that match the "{@code domain-server}" tuples when
* locating the binlog position in a MariaDB server. GTIDs that do not match any of these patterns
* will be used.
*/
public static final Field GTID_SOURCE_EXCLUDES = BinlogConnectorConfig.GTID_SOURCE_EXCLUDES
.withDescription("The source domain IDs used to exclude GTID ranges when determining the starting "
+ "position in the MariaDB server's binlog.");
private static final ConfigDefinition CONFIG_DEFINITION = BinlogConnectorConfig.CONFIG_DEFINITION.edit()
.name("MariaDB")
.excluding(
BinlogConnectorConfig.GTID_SOURCE_INCLUDES,
BinlogConnectorConfig.GTID_SOURCE_EXCLUDES)
.connector(SNAPSHOT_LOCKING_MODE)
.events(
GTID_SOURCE_INCLUDES,
GTID_SOURCE_EXCLUDES,
SOURCE_INFO_STRUCT_MAKER)
.create();
protected static ConfigDef configDef() {
return CONFIG_DEFINITION.configDef();
}
/**
* The set of {@link Field}s defined as part of this connector configuration.
*/
public static Field.Set ALL_FIELDS = Field.setOf(CONFIG_DEFINITION.all());
private final GtidSetFactory gtidSetFactory;
private final Predicate<String> gtidSourceFilter;
private final SnapshotLockingMode snapshotLockingMode;
private final SnapshotLockingStrategy snapshotLockingStrategy;
public MariaDbConnectorConfig(Configuration config) {
super(MariaDbConnector.class, config, DEFAULT_NON_STREAMING_FETCH_SIZE);
this.gtidSetFactory = new MariaDbGtidSetFactory();
final String gtidIncludes = config.getString(GTID_SOURCE_INCLUDES);
final String gtidExcludes = config.getString(GTID_SOURCE_EXCLUDES);
this.gtidSourceFilter = gtidIncludes != null ? Predicates.includes(gtidIncludes)
: (gtidExcludes != null ? Predicates.excludes(gtidExcludes) : null);
this.snapshotLockingMode = SnapshotLockingMode.parse(config.getString(SNAPSHOT_LOCKING_MODE));
this.snapshotLockingStrategy = new MariaDbSnapshotLockingStrategy(snapshotLockingMode);
getServiceRegistry().registerServiceProvider(new MariaDbCharsetRegistryServiceProvider());
}
@Override
protected SourceInfoStructMaker<? extends AbstractSourceInfo> getSourceInfoStructMaker(Version version) {
return getSourceInfoStructMaker(SOURCE_INFO_STRUCT_MAKER, Module.name(), Module.version(), this);
}
@Override
public String getContextName() {
return Module.contextName();
}
@Override
public String getConnectorName() {
return Module.name();
}
@Override
public Predicate<String> getGtidSourceFilter() {
return gtidSourceFilter;
}
@Override
public GtidSetFactory getGtidSetFactory() {
return gtidSetFactory;
}
@Override
protected HistoryRecordComparator getHistoryRecordComparator() {
return new MariaDbHistoryRecordComparator(gtidSourceFilter, getGtidSetFactory());
}
@Override
protected SnapshotLockingStrategy getSnapshotLockingStrategy() {
return snapshotLockingStrategy;
}
@Override
public Optional<SnapshotLockingMode> getSnapshotLockingMode() {
return Optional.of(snapshotLockingMode);
}
/**
* Custom {@link io.debezium.connector.binlog.BinlogConnectorConfig.SnapshotLockingStrategy} for MariaDB.
*/
public static class MariaDbSnapshotLockingStrategy implements SnapshotLockingStrategy {
public final SnapshotLockingMode snapshotLockingMode;
public MariaDbSnapshotLockingStrategy(SnapshotLockingMode snapshotLockingMode) {
this.snapshotLockingMode = snapshotLockingMode;
}
@Override
public boolean isLockingEnabled() {
return snapshotLockingMode.usesLocking();
}
@Override
public boolean isMinimalLockingEnabled() {
return snapshotLockingMode.usesMinimalLocking();
}
@Override
public boolean isIsolationLevelResetOnFlush() {
return snapshotLockingMode.flushResetsIsolationLevel();
}
}
/**
* Validate the new snapshot.locking.mode configuration.
*
* @param config the connector configuration
* @param field the field being validated
* @param problems the validation output
* @return the number of problems detected
*/
private static int validateSnapshotLockingMode(Configuration config, Field field, ValidationOutput problems) {
if (config.hasKey(SNAPSHOT_LOCKING_MODE.name())) {
SnapshotLockingMode lockingModeValue = SnapshotLockingMode.parse(config.getString(SNAPSHOT_LOCKING_MODE));
if (lockingModeValue == null) {
problems.accept(SNAPSHOT_LOCKING_MODE, lockingModeValue, "Must be a valid snapshot.locking.mode value");
return 1;
}
}
return 0;
}
}

View File

@ -1,296 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import static io.debezium.connector.binlog.BinlogConnectorConfig.TOPIC_NAMING_STRATEGY;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.kafka.connect.source.SourceRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.debezium.DebeziumException;
import io.debezium.bean.StandardBeanNames;
import io.debezium.config.Configuration;
import io.debezium.config.Field;
import io.debezium.connector.base.ChangeEventQueue;
import io.debezium.connector.binlog.BinlogEventMetadataProvider;
import io.debezium.connector.binlog.BinlogSourceTask;
import io.debezium.connector.binlog.jdbc.BinlogConnectorConnection;
import io.debezium.connector.binlog.jdbc.BinlogFieldReader;
import io.debezium.connector.mariadb.jdbc.MariaDbConnection;
import io.debezium.connector.mariadb.jdbc.MariaDbConnectionConfiguration;
import io.debezium.connector.mariadb.jdbc.MariaDbFieldReader;
import io.debezium.connector.mariadb.jdbc.MariaDbValueConverters;
import io.debezium.connector.mariadb.metrics.MariaDbChangeEventSourceMetricsFactory;
import io.debezium.connector.mariadb.metrics.MariaDbStreamingChangeEventSourceMetrics;
import io.debezium.document.DocumentReader;
import io.debezium.jdbc.DefaultMainConnectionProvidingConnectionFactory;
import io.debezium.jdbc.MainConnectionProvidingConnectionFactory;
import io.debezium.pipeline.ChangeEventSourceCoordinator;
import io.debezium.pipeline.DataChangeEvent;
import io.debezium.pipeline.ErrorHandler;
import io.debezium.pipeline.EventDispatcher;
import io.debezium.pipeline.notification.NotificationService;
import io.debezium.pipeline.signal.SignalProcessor;
import io.debezium.pipeline.spi.Offsets;
import io.debezium.relational.TableId;
import io.debezium.schema.SchemaFactory;
import io.debezium.schema.SchemaNameAdjuster;
import io.debezium.snapshot.SnapshotterService;
import io.debezium.spi.snapshot.Snapshotter;
import io.debezium.spi.topic.TopicNamingStrategy;
import io.debezium.util.Clock;
/**
* The MariaDB connector task that performs snapshot and streaming of changes from the database.
*
* @author Chris Cranford
*/
public class MariaDbConnectorTask extends BinlogSourceTask<MariaDbPartition, MariaDbOffsetContext> {
private static final Logger LOGGER = LoggerFactory.getLogger(MariaDbConnectorTask.class);
private static final String CONTEXT_NAME = "mariadb-connector-task";
private volatile MariaDbTaskContext taskContext;
private volatile ChangeEventQueue<DataChangeEvent> queue;
private volatile BinlogConnectorConnection connection;
private volatile BinlogConnectorConnection beanRegistryJdbcConnection;
private volatile ErrorHandler errorHandler;
private volatile MariaDbDatabaseSchema schema;
@Override
public String version() {
return Module.version();
}
@Override
protected Iterable<Field> getAllConfigurationFields() {
return MariaDbConnectorConfig.ALL_FIELDS;
}
@Override
protected ChangeEventSourceCoordinator<MariaDbPartition, MariaDbOffsetContext> start(Configuration configuration) {
final Clock clock = Clock.system();
final MariaDbConnectorConfig connectorConfig = new MariaDbConnectorConfig(configuration);
final TopicNamingStrategy<TableId> topicNamingStrategy = connectorConfig.getTopicNamingStrategy(TOPIC_NAMING_STRATEGY);
final SchemaNameAdjuster schemaNameAdjuster = connectorConfig.schemaNameAdjuster();
final MariaDbValueConverters valueConverters = getValueConverters(connectorConfig);
// DBZ-3238
// Automatically set useCursorFetch to true when a snapshot fetch size other than the default is given.
// By default, do not load whole result sets into memory.
final Configuration config = configuration.edit()
.withDefault("database.responseBuffering", "adaptive")
.withDefault("database.fetchSize", 10_000)
.withDefault("database.useCursorFetch", connectorConfig.useCursorFetch())
.build();
final MainConnectionProvidingConnectionFactory<BinlogConnectorConnection> connectionFactory = new DefaultMainConnectionProvidingConnectionFactory<>(() -> {
final MariaDbConnectionConfiguration connectionConfig = new MariaDbConnectionConfiguration(config);
return new MariaDbConnection(connectionConfig, new MariaDbFieldReader(connectorConfig));
});
this.connection = connectionFactory.mainConnection();
final Offsets<MariaDbPartition, MariaDbOffsetContext> previousOffsets = getPreviousOffsets(
new MariaDbPartition.Provider(connectorConfig, config),
new MariaDbOffsetContext.Loader(connectorConfig));
final boolean tableIdCaseInsensitive = connection.isTableIdCaseSensitive();
this.schema = new MariaDbDatabaseSchema(connectorConfig, valueConverters, topicNamingStrategy, schemaNameAdjuster, tableIdCaseInsensitive);
// Manual Bean Registration
beanRegistryJdbcConnection = connectionFactory.newConnection();
connectorConfig.getBeanRegistry().add(StandardBeanNames.CONFIGURATION, config);
connectorConfig.getBeanRegistry().add(StandardBeanNames.CONNECTOR_CONFIG, connectorConfig);
connectorConfig.getBeanRegistry().add(StandardBeanNames.DATABASE_SCHEMA, schema);
connectorConfig.getBeanRegistry().add(StandardBeanNames.JDBC_CONNECTION, beanRegistryJdbcConnection);
connectorConfig.getBeanRegistry().add(StandardBeanNames.VALUE_CONVERTER, valueConverters);
connectorConfig.getBeanRegistry().add(StandardBeanNames.OFFSETS, previousOffsets);
// Service providers
registerServiceProviders(connectorConfig.getServiceRegistry());
final SnapshotterService snapshotterService = connectorConfig.getServiceRegistry().tryGetService(SnapshotterService.class);
final Snapshotter snapshotter = snapshotterService.getSnapshotter();
validateBinlogConfiguration(snapshotter, connection);
// If the binlog position is not available, it is necessary to re-execute the snapshot
if (validateSnapshotFeasibility(snapshotter, previousOffsets.getTheOnlyOffset(), connection)) {
previousOffsets.resetOffset(previousOffsets.getTheOnlyPartition());
}
LOGGER.info("Closing JDBC connection before starting schema recovery.");
try {
connection.close();
}
catch (SQLException e) {
throw new DebeziumException(e);
}
MariaDbOffsetContext previousOffset = previousOffsets.getTheOnlyOffset();
validateAndLoadSchemaHistory(connectorConfig, connection::validateLogPosition, previousOffsets, schema, snapshotter);
LOGGER.info("Reconnecting after finishing schema recovery");
try {
connection.setAutoCommit(false);
}
catch (SQLException e) {
throw new DebeziumException(e);
}
// If the binlog position is not available it is necessary to re-execute snapshot
if (previousOffset == null) {
LOGGER.info("No previous offset found");
}
else {
LOGGER.info("Found previous offset {}", previousOffset);
}
taskContext = new MariaDbTaskContext(connectorConfig, schema);
// Set up the task record queue ...
this.queue = new ChangeEventQueue.Builder<DataChangeEvent>()
.pollInterval(connectorConfig.getPollInterval())
.maxBatchSize(connectorConfig.getMaxBatchSize())
.maxQueueSize(connectorConfig.getMaxQueueSize())
.maxQueueSizeInBytes(connectorConfig.getMaxQueueSizeInBytes())
.loggingContextSupplier(() -> taskContext.configureLoggingContext(CONTEXT_NAME))
.buffering()
.build();
errorHandler = new MariaDbErrorHandler(connectorConfig, queue, errorHandler);
final BinlogEventMetadataProvider metadataProvider = new BinlogEventMetadataProvider();
SignalProcessor<MariaDbPartition, MariaDbOffsetContext> signalProcessor = new SignalProcessor<>(
MariaDbConnector.class,
connectorConfig,
Map.of(),
getAvailableSignalChannels(),
DocumentReader.defaultReader(),
previousOffsets);
resetOffset(connectorConfig, previousOffset, signalProcessor);
final Configuration heartbeatConfig = config;
final EventDispatcher<MariaDbPartition, TableId> dispatcher = new EventDispatcher<>(
connectorConfig,
topicNamingStrategy,
schema,
queue,
connectorConfig.getTableFilters().dataCollectionFilter(),
DataChangeEvent::new,
null,
metadataProvider,
connectorConfig.createHeartbeat(
topicNamingStrategy,
schemaNameAdjuster,
() -> new MariaDbConnection(
new MariaDbConnectionConfiguration(heartbeatConfig),
getFieldReader(connectorConfig)),
new BinlogHeartbeatErrorHandler()),
schemaNameAdjuster,
signalProcessor);
final MariaDbStreamingChangeEventSourceMetrics streamingMetrics = new MariaDbStreamingChangeEventSourceMetrics(
taskContext,
queue,
metadataProvider);
NotificationService<MariaDbPartition, MariaDbOffsetContext> notificationService = new NotificationService<>(
getNotificationChannels(),
connectorConfig,
SchemaFactory.get(),
dispatcher::enqueueNotification);
ChangeEventSourceCoordinator<MariaDbPartition, MariaDbOffsetContext> coordinator = new ChangeEventSourceCoordinator<>(
previousOffsets,
errorHandler,
MariaDbConnector.class,
connectorConfig,
new MariaDbChangeEventSourceFactory(
connectorConfig,
connectionFactory,
errorHandler,
dispatcher,
clock,
schema,
taskContext,
streamingMetrics,
queue,
snapshotterService),
new MariaDbChangeEventSourceMetricsFactory(streamingMetrics),
dispatcher,
schema,
signalProcessor,
notificationService,
snapshotterService);
coordinator.start(taskContext, this.queue, metadataProvider);
return coordinator;
}
@Override
protected void doStop() {
try {
if (connection != null) {
connection.close();
}
}
catch (SQLException e) {
LOGGER.error("Exception while closing the JDBC connection.", e);
}
try {
if (beanRegistryJdbcConnection != null) {
beanRegistryJdbcConnection.close();
}
}
catch (SQLException e) {
LOGGER.error("Exception while closing the Bean Registry JDBC connection.", e);
}
if (schema != null) {
schema.close();
}
}
@Override
protected List<SourceRecord> doPoll() throws InterruptedException {
final List<DataChangeEvent> records = queue.poll();
return records.stream().map(DataChangeEvent::getRecord).collect(Collectors.toList());
}
@Override
@SuppressWarnings("unchecked")
protected Long getReadOnlyIncrementalSnapshotSignalOffset(MariaDbOffsetContext previousOffset) {
return ((MariaDbReadOnlyIncrementalSnapshotContext<TableId>) previousOffset.getIncrementalSnapshotContext()).getSignalOffset();
}
private MariaDbValueConverters getValueConverters(MariaDbConnectorConfig connectorConfig) {
return new MariaDbValueConverters(
connectorConfig.getDecimalMode(),
connectorConfig.getTemporalPrecisionMode(),
connectorConfig.getBigIntUnsignedHandlingMode().asBigIntUnsignedMode(),
connectorConfig.binaryHandlingMode(),
connectorConfig.isTimeAdjustedEnabled() ? MariaDbValueConverters::adjustTemporal : x -> x,
connectorConfig.getEventConvertingFailureHandlingMode(),
connectorConfig.getServiceRegistry());
}
private BinlogFieldReader getFieldReader(MariaDbConnectorConfig connectorConfig) {
return new MariaDbFieldReader(connectorConfig);
}
}

View File

@ -1,48 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogConnectorConfig;
import io.debezium.connector.binlog.BinlogDatabaseSchema;
import io.debezium.connector.binlog.charset.BinlogCharsetRegistry;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.connector.mariadb.jdbc.MariaDbDefaultValueConverter;
import io.debezium.connector.mariadb.jdbc.MariaDbValueConverters;
import io.debezium.relational.TableId;
import io.debezium.relational.ddl.DdlParser;
import io.debezium.schema.SchemaNameAdjuster;
import io.debezium.spi.topic.TopicNamingStrategy;
/**
* A concrete implementation of database schema for MariaDB databases.
*
* @author Chris Cranford
*/
public class MariaDbDatabaseSchema extends BinlogDatabaseSchema<MariaDbPartition, MariaDbOffsetContext, MariaDbValueConverters, MariaDbDefaultValueConverter> {
public MariaDbDatabaseSchema(MariaDbConnectorConfig connectorConfig, MariaDbValueConverters valueConverter,
TopicNamingStrategy<TableId> topicNamingStrategy, SchemaNameAdjuster schemaNameAdjuster,
boolean tableIdCaseInsensitive) {
super(connectorConfig,
valueConverter,
new MariaDbDefaultValueConverter(valueConverter),
topicNamingStrategy,
schemaNameAdjuster,
tableIdCaseInsensitive);
}
@Override
protected DdlParser createDdlParser(BinlogConnectorConfig connectorConfig, MariaDbValueConverters valueConverter) {
return new MariaDbAntlrDdlParser(
true,
false,
connectorConfig.isSchemaChangesHistoryEnabled(),
valueConverter,
getTableFilter(),
connectorConfig.getServiceRegistry().getService(BinlogCharsetRegistry.class));
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Set;
import io.debezium.connector.base.ChangeEventQueue;
import io.debezium.pipeline.ErrorHandler;
import io.debezium.util.Collect;
/**
* Error handler for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbErrorHandler extends ErrorHandler {
public MariaDbErrorHandler(MariaDbConnectorConfig connectorConfig, ChangeEventQueue<?> queue, ErrorHandler replacedErrorHandler) {
super(MariaDbConnector.class, connectorConfig, queue, replacedErrorHandler);
}
@Override
protected Set<Class<? extends Exception>> communicationExceptions() {
return Collect.unmodifiableSet(IOException.class, SQLException.class);
}
}

View File

@ -1,76 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import static io.debezium.connector.common.OffsetUtils.longOffsetValue;
import java.util.Map;
import org.apache.kafka.connect.errors.ConnectException;
import io.debezium.connector.binlog.BinlogOffsetContext;
import io.debezium.connector.binlog.BinlogSourceInfo;
import io.debezium.pipeline.source.snapshot.incremental.IncrementalSnapshotContext;
import io.debezium.pipeline.source.snapshot.incremental.SignalBasedIncrementalSnapshotContext;
import io.debezium.pipeline.txmetadata.TransactionContext;
import io.debezium.relational.TableId;
/**
* Context that manages the connector offset details.
*
* @author Chris Cranford
*/
public class MariaDbOffsetContext extends BinlogOffsetContext<SourceInfo> {
public MariaDbOffsetContext(boolean snapshot, boolean snapshotCompleted, TransactionContext transactionContext,
IncrementalSnapshotContext<TableId> incrementalSnapshotContext, SourceInfo sourceInfo) {
super(snapshot, snapshotCompleted, transactionContext, incrementalSnapshotContext, sourceInfo);
}
public static MariaDbOffsetContext initial(MariaDbConnectorConfig config) {
final MariaDbOffsetContext offset = new MariaDbOffsetContext(
false,
false,
new TransactionContext(),
config.isReadOnlyConnection()
? new MariaDbReadOnlyIncrementalSnapshotContext<>()
: new SignalBasedIncrementalSnapshotContext<>(),
new SourceInfo(config));
offset.setBinlogStartPoint("", 0L);
return offset;
}
public static class Loader extends BinlogOffsetContext.Loader<MariaDbOffsetContext> {
private final MariaDbConnectorConfig connectorConfig;
public Loader(MariaDbConnectorConfig connectorConfig) {
this.connectorConfig = connectorConfig;
}
@Override
public MariaDbOffsetContext load(Map<String, ?> offset) {
final String binlogFilename = (String) offset.get(BinlogSourceInfo.BINLOG_FILENAME_OFFSET_KEY);
if (binlogFilename == null) {
throw new ConnectException("Source offset '" + BinlogSourceInfo.BINLOG_FILENAME_OFFSET_KEY + "' parameter is missing");
}
final long binlogPosition = longOffsetValue(offset, BinlogSourceInfo.BINLOG_POSITION_OFFSET_KEY);
final MariaDbOffsetContext offsetContext = new MariaDbOffsetContext(
isTrue(offset, BinlogSourceInfo.SNAPSHOT_KEY),
isTrue(offset, SNAPSHOT_COMPLETED_KEY),
TransactionContext.load(offset),
connectorConfig.isReadOnlyConnection()
? MariaDbReadOnlyIncrementalSnapshotContext.load(offset)
: SignalBasedIncrementalSnapshotContext.load(offset),
new SourceInfo(connectorConfig));
offsetContext.setBinlogStartPoint(binlogFilename, binlogPosition);
offsetContext.setInitialSkips(longOffsetValue(offset, EVENTS_TO_SKIP_OFFSET_KEY),
(int) longOffsetValue(offset, BinlogSourceInfo.BINLOG_ROW_IN_EVENT_OFFSET_KEY));
offsetContext.setCompletedGtidSet((String) offset.get(GTID_SET_KEY)); // may be null
return offsetContext;
}
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import static io.debezium.relational.RelationalDatabaseConnectorConfig.DATABASE_NAME;
import java.util.Collections;
import java.util.Set;
import io.debezium.config.Configuration;
import io.debezium.connector.binlog.BinlogConnectorConfig;
import io.debezium.connector.binlog.BinlogPartition;
import io.debezium.pipeline.spi.Partition;
/**
* Describes the partition scheme used by the MariaDB connector.
*
* @author Chris Cranford
*/
public class MariaDbPartition extends BinlogPartition {
public MariaDbPartition(String serverName, String databaseName) {
super(serverName, databaseName);
}
public static class Provider implements Partition.Provider<MariaDbPartition> {
private final BinlogConnectorConfig connectorConfig;
private final Configuration taskConfig;
public Provider(BinlogConnectorConfig connectorConfig, Configuration taskConfig) {
this.connectorConfig = connectorConfig;
this.taskConfig = taskConfig;
}
@Override
public Set<MariaDbPartition> getPartitions() {
return Collections.singleton(new MariaDbPartition(
connectorConfig.getLogicalName(), taskConfig.getString(DATABASE_NAME.name())));
}
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.sql.SQLException;
import java.util.function.Consumer;
import io.debezium.DebeziumException;
import io.debezium.connector.binlog.BinlogReadOnlyIncrementalSnapshotChangeEventSource;
import io.debezium.connector.binlog.gtid.GtidSet;
import io.debezium.connector.mariadb.gtid.MariaDbGtidSet;
import io.debezium.jdbc.JdbcConnection;
import io.debezium.pipeline.EventDispatcher;
import io.debezium.pipeline.notification.NotificationService;
import io.debezium.pipeline.source.spi.DataChangeEventListener;
import io.debezium.pipeline.source.spi.SnapshotProgressListener;
import io.debezium.relational.TableId;
import io.debezium.schema.DatabaseSchema;
import io.debezium.util.Clock;
/**
*
* @author Chris Cranford
*/
public class MariaDbReadOnlyIncrementalSnapshotChangeEventSource
extends BinlogReadOnlyIncrementalSnapshotChangeEventSource<MariaDbPartition, MariaDbOffsetContext> {
public MariaDbReadOnlyIncrementalSnapshotChangeEventSource(MariaDbConnectorConfig connectorConfig,
JdbcConnection jdbcConnection,
EventDispatcher<MariaDbPartition, TableId> dispatcher,
DatabaseSchema<?> databaseSchema,
Clock clock,
SnapshotProgressListener<MariaDbPartition> progressListener,
DataChangeEventListener<MariaDbPartition> dataChangeEventListener,
NotificationService<MariaDbPartition, MariaDbOffsetContext> notificationService) {
super(connectorConfig, jdbcConnection, dispatcher, databaseSchema, clock, progressListener, dataChangeEventListener, notificationService);
}
@Override
protected void getExecutedGtidSet(Consumer<GtidSet> watermark) {
try {
jdbcConnection.query("SHOW GLOBAL VARIABLES LIKE 'GTID_BINLOG_POS'", rs -> {
if (rs.next()) {
if (rs.getMetaData().getColumnCount() > 0) {
final String gtidSet = rs.getString(2);
watermark.accept(new MariaDbGtidSet(gtidSet));
}
else {
throw new UnsupportedOperationException("Need to add support for executed GTIDs for versions prior to 5.6.5");
}
}
});
jdbcConnection.commit();
}
catch (SQLException e) {
throw new DebeziumException(e);
}
}
}

View File

@ -1,133 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.debezium.connector.binlog.BinlogReadOnlyIncrementalSnapshotContext;
import io.debezium.connector.binlog.gtid.GtidSet;
import io.debezium.connector.mariadb.gtid.MariaDbGtidSet;
import io.debezium.connector.mariadb.gtid.MariaDbGtidSet.MariaDbGtid;
import io.debezium.connector.mariadb.gtid.MariaDbGtidSet.MariaDbStreamSet;
import io.debezium.pipeline.spi.OffsetContext;
/**
* @author Chris Cranford
*/
public class MariaDbReadOnlyIncrementalSnapshotContext<T> extends BinlogReadOnlyIncrementalSnapshotContext<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(MariaDbReadOnlyIncrementalSnapshotContext.class);
private MariaDbGtidSet previousLowWatermark;
private MariaDbGtidSet previousHighWatermark;
private MariaDbGtidSet lowWatermark;
private MariaDbGtidSet highWatermark;
public MariaDbReadOnlyIncrementalSnapshotContext() {
this(true);
}
public MariaDbReadOnlyIncrementalSnapshotContext(boolean useCatalogBeforeSchema) {
super(useCatalogBeforeSchema);
}
@Override
public boolean updateWindowState(OffsetContext offsetContext) {
String currentGtid = getCurrentGtid(offsetContext);
if (!windowOpened && lowWatermark != null) {
boolean pastLowWatermark = !lowWatermark.contains(currentGtid);
if (pastLowWatermark) {
LOGGER.debug("Current gtid {}, low watermark {}", currentGtid, lowWatermark);
windowOpened = true;
}
}
if (windowOpened && highWatermark != null) {
boolean pastHighWatermark = !highWatermark.contains(currentGtid);
if (pastHighWatermark) {
LOGGER.debug("Current gtid {}, high watermark {}", currentGtid, highWatermark);
closeWindow();
return true;
}
}
return false;
}
@Override
public boolean hasServerIdentifierChanged() {
return serverStreamSetChanged();
}
@Override
public boolean reachedHighWatermark(String currentGtid) {
if (highWatermark == null) {
return false;
}
if (currentGtid == null) {
return true;
}
final MariaDbGtid currentMariaDbGtid = MariaDbGtidSet.parse(currentGtid);
final MariaDbStreamSet streamSet = getStreamSetForGtid(currentMariaDbGtid);
if (streamSet != null) {
long maxSequenceId = streamSet.stream()
.mapToLong(MariaDbGtid::getSequence)
.max()
.getAsLong();
if (maxSequenceId <= currentMariaDbGtid.getSequence()) {
LOGGER.debug("Gtid {} reached high watermark {}", currentGtid, highWatermark);
return true;
}
}
return false;
}
@Override
public boolean watermarksChanged() {
return !previousLowWatermark.equals(lowWatermark) || !previousHighWatermark.equals(highWatermark);
}
@Override
public void closeWindow() {
windowOpened = false;
previousHighWatermark = highWatermark;
highWatermark = null;
previousLowWatermark = lowWatermark;
lowWatermark = null;
}
@Override
public void setLowWatermark(GtidSet lowWatermark) {
this.lowWatermark = (MariaDbGtidSet) lowWatermark;
}
@Override
public void setHighWatermark(GtidSet highWatermark) {
this.highWatermark = (MariaDbGtidSet) highWatermark.subtract(lowWatermark);
}
private MariaDbStreamSet getStreamSetForGtid(MariaDbGtid currentGtid) {
return highWatermark.isEmpty()
? lowWatermark.forGtidStream(currentGtid)
: highWatermark.forGtidStream(currentGtid);
}
public boolean serverStreamSetChanged() {
return !highWatermark.isEmpty();
}
public static <U> MariaDbReadOnlyIncrementalSnapshotContext<U> load(Map<String, ?> offsets) {
return load(offsets, true);
}
public static <U> MariaDbReadOnlyIncrementalSnapshotContext<U> load(Map<String, ?> offsets, boolean useCatalogBeforeSchema) {
MariaDbReadOnlyIncrementalSnapshotContext<U> context = new MariaDbReadOnlyIncrementalSnapshotContext<>(useCatalogBeforeSchema);
init(context, offsets);
return context;
}
}

View File

@ -1,19 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.schema.SchemaFactory;
/**
* @author Chris Cranford
*/
public class MariaDbSchemaFactory extends SchemaFactory {
private static final MariaDbSchemaFactory INSTANCE = new MariaDbSchemaFactory();
public static MariaDbSchemaFactory get() {
return INSTANCE;
}
}

View File

@ -1,96 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.util.function.Function;
import org.apache.kafka.connect.source.SourceRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.debezium.DebeziumException;
import io.debezium.connector.binlog.BinlogConnectorConfig;
import io.debezium.connector.binlog.BinlogSnapshotChangeEventSource;
import io.debezium.connector.binlog.jdbc.BinlogConnectorConnection;
import io.debezium.connector.mariadb.metrics.MariaDbSnapshotChangeEventSourceMetrics;
import io.debezium.function.BlockingConsumer;
import io.debezium.jdbc.MainConnectionProvidingConnectionFactory;
import io.debezium.pipeline.EventDispatcher;
import io.debezium.pipeline.notification.NotificationService;
import io.debezium.relational.TableId;
import io.debezium.snapshot.SnapshotterService;
import io.debezium.util.Clock;
/**
* A {@link io.debezium.pipeline.source.spi.SnapshotChangeEventSource} implementation for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbSnapshotChangeEventSource extends BinlogSnapshotChangeEventSource<MariaDbPartition, MariaDbOffsetContext> {
private static final Logger LOGGER = LoggerFactory.getLogger(MariaDbSnapshotChangeEventSource.class);
private final MariaDbConnectorConfig connectorConfig;
public MariaDbSnapshotChangeEventSource(MariaDbConnectorConfig connectorConfig,
MainConnectionProvidingConnectionFactory<BinlogConnectorConnection> connectionFactory,
MariaDbDatabaseSchema schema,
EventDispatcher<MariaDbPartition, TableId> dispatcher,
Clock clock,
MariaDbSnapshotChangeEventSourceMetrics metrics,
BlockingConsumer<Function<SourceRecord, SourceRecord>> lastEventProcessor,
Runnable preSnapshotAction,
NotificationService<MariaDbPartition, MariaDbOffsetContext> notificationService,
SnapshotterService snapshotterService) {
super(connectorConfig, connectionFactory, schema, dispatcher, clock, metrics, lastEventProcessor,
preSnapshotAction, notificationService, snapshotterService);
this.connectorConfig = connectorConfig;
}
@Override
protected MariaDbOffsetContext getInitialOffsetContext(BinlogConnectorConfig connectorConfig) {
return MariaDbOffsetContext.initial((MariaDbConnectorConfig) connectorConfig);
}
@Override
protected void setOffsetContextBinlogPositionAndGtidDetailsForSnapshot(MariaDbOffsetContext offsetContext,
BinlogConnectorConnection connection,
SnapshotterService snapshotterService)
throws Exception {
LOGGER.info("Read binlog position of MariaDB primary server");
final String showMasterStmt = connection.binaryLogStatusStatement();
connection.query(showMasterStmt, rs -> {
if (rs.next()) {
final String binlogFilename = rs.getString(1);
final long binlogPosition = rs.getLong(2);
offsetContext.setBinlogStartPoint(binlogFilename, binlogPosition);
connection.query("SHOW GLOBAL VARIABLES LIKE 'GTID_BINLOG_POS'", rs2 -> {
if (rs2.next() && rs2.getMetaData().getColumnCount() > 0) {
final String gtidSet = rs2.getString(2);
offsetContext.setCompletedGtidSet(gtidSet);
LOGGER.info("\t using binlog '{}' at position '{}' and gtid '{}'", binlogFilename, binlogPosition, gtidSet);
}
else {
LOGGER.info("\t using binlog '{}' at position '{}'", binlogFilename, binlogPosition);
}
});
}
else if (!snapshotterService.getSnapshotter().shouldStream()) {
LOGGER.warn("Failed retrieving binlog position, continuing as streaming CDC wasn't requested");
}
else {
throw new DebeziumException("Cannot read the binlog filename and position via '" + showMasterStmt
+ "'. Make sure your server is correctly configured");
}
});
}
@Override
protected MariaDbOffsetContext copyOffset(RelationalSnapshotContext<MariaDbPartition, MariaDbOffsetContext> snapshotContext) {
return new MariaDbOffsetContext.Loader(connectorConfig).load(snapshotContext.offset.getOffset());
}
}

View File

@ -1,22 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import org.apache.kafka.connect.data.Struct;
import io.debezium.connector.binlog.BinlogSourceInfoStructMaker;
/**
* The {@code source} {@link Struct} information maker for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbSourceInfoStructMaker extends BinlogSourceInfoStructMaker<SourceInfo> {
@Override
protected String getConnectorName() {
return Module.name();
}
}

View File

@ -1,169 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.time.Instant;
import java.util.Map;
import java.util.function.Predicate;
import org.apache.kafka.connect.source.SourceConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.shyiko.mysql.binlog.BinaryLogClient;
import com.github.shyiko.mysql.binlog.MariadbGtidSet;
import com.github.shyiko.mysql.binlog.event.AnnotateRowsEventData;
import com.github.shyiko.mysql.binlog.event.Event;
import com.github.shyiko.mysql.binlog.event.EventData;
import com.github.shyiko.mysql.binlog.event.EventType;
import com.github.shyiko.mysql.binlog.event.MariadbGtidEventData;
import io.debezium.connector.binlog.BinlogConnectorConfig;
import io.debezium.connector.binlog.BinlogStreamingChangeEventSource;
import io.debezium.connector.binlog.BinlogTaskContext;
import io.debezium.connector.binlog.jdbc.BinlogConnectorConnection;
import io.debezium.connector.mariadb.metrics.MariaDbStreamingChangeEventSourceMetrics;
import io.debezium.pipeline.ErrorHandler;
import io.debezium.pipeline.EventDispatcher;
import io.debezium.relational.TableId;
import io.debezium.snapshot.SnapshotterService;
import io.debezium.util.Clock;
import io.debezium.util.Strings;
/**
* @author Chris Cranford
*/
public class MariaDbStreamingChangeEventSource extends BinlogStreamingChangeEventSource<MariaDbPartition, MariaDbOffsetContext> {
private static final Logger LOGGER = LoggerFactory.getLogger(MariaDbStreamingChangeEventSource.class);
private final MariaDbConnectorConfig connectorConfig;
private final TableId signalDataCollectionId;
private MariadbGtidSet gtidSet;
public MariaDbStreamingChangeEventSource(MariaDbConnectorConfig connectorConfig,
BinlogConnectorConnection connection,
EventDispatcher<MariaDbPartition, TableId> dispatcher,
ErrorHandler errorHandler,
Clock clock,
MariaDbTaskContext taskContext,
MariaDbStreamingChangeEventSourceMetrics metrics,
SnapshotterService snapshotterService) {
super(connectorConfig, connection, dispatcher, errorHandler, clock, taskContext, taskContext.getSchema(), metrics, snapshotterService);
this.connectorConfig = connectorConfig;
this.signalDataCollectionId = getSignalDataCollectionId(connectorConfig);
}
@Override
public void init(MariaDbOffsetContext offsetContext) {
setEffectiveOffsetContext(offsetContext != null ? offsetContext : MariaDbOffsetContext.initial(connectorConfig));
}
@Override
protected Class<? extends SourceConnector> getConnectorClass() {
return MariaDbConnector.class;
}
@Override
protected BinaryLogClient createBinaryLogClient(BinlogTaskContext<?> taskContext,
BinlogConnectorConfig connectorConfig,
Map<String, Thread> clientThreads,
BinlogConnectorConnection connection) {
final BinaryLogClient client = super.createBinaryLogClient(taskContext, connectorConfig, clientThreads, connection);
if (connectorConfig.isSqlQueryIncluded()) {
// Binlog client explicitly needs to be told to enable ANNOTATE_ROWS events, which is the MariaDB
// equivalent of ROWS_QUERY for MySQL. This must be done ahead of the connection to make sure that
// the right negotiation bits are set during the handshake.
client.setUseSendAnnotateRowsEvent(true);
}
return client;
}
@Override
protected void configureReplicaCompatibility(BinaryLogClient client) {
client.setMariaDbSlaveCapability(4);
}
@Override
protected void setEventTimestamp(Event event, long eventTs) {
eventTimestamp = Instant.ofEpochMilli(eventTs);
}
@Override
protected void handleGtidEvent(MariaDbPartition partition, MariaDbOffsetContext offsetContext, Event event,
Predicate<String> gtidDmlSourceFilter)
throws InterruptedException {
LOGGER.debug("MariaDB GTID transaction: {}", event);
// NOTE: MariadbGtidEventData (GTID_EVENT) does not include the server id in the event data payload.
// We need to manually construct the GTID combining the data from the GTID_EVENT payload and header.
MariadbGtidEventData gtidEvent = unwrapData(event);
String gtid = String.format("%d-%d-%d", gtidEvent.getDomainId(), event.getHeader().getServerId(), gtidEvent.getSequence());
// String gtid = gtidEvent.toString();
gtidSet.add(gtid);
offsetContext.startGtid(gtid, gtidSet.toString());
setIgnoreDmlEventByGtidSource(false);
if (gtidDmlSourceFilter != null && gtid != null) {
String uuid = gtidEvent.getDomainId() + "-" + gtidEvent.getServerId();
if (!gtidDmlSourceFilter.test(uuid)) {
setIgnoreDmlEventByGtidSource(true);
}
}
setGtidChanged(gtid);
// With compatibility mode 4, this event equates to a new transaction.
handleTransactionBegin(partition, offsetContext, event, null);
}
@Override
protected void handleRecordingQuery(MariaDbOffsetContext offsetContext, Event event) {
final EventData eventData = unwrapData(event);
if (eventData instanceof AnnotateRowsEventData) {
final String query = ((AnnotateRowsEventData) eventData).getRowsQuery();
// todo: Cache ANNOTATE_ROWS query with events
// During incremental snapshots, the updates made to the signal table can lead to a case where
// the query stored in the offsets mismatch the events being dispatched.
//
// IncrementalSnapshotIT#updates performs a series of updates where the pk/aa columns are changed
// i.e. [1,0] to [1,2000] and the ANNOTATE_ROWS event that conatins the query specifies this SQL:
// "UPDATE `schema`.`a` SET aa = aa + 2000 WHERE pk > 0 and pk <= 10"
//
// The problem is that signal events do not seem to record a query string in the offsets for MySQL
// but this gets recorded for MariaDB, and causes a mismatch of query string values that differs
// from MySQL's behavior. For now, this allows the tests to pass.
if (signalDataCollectionId != null) {
if (query.toLowerCase().contains(signalDataCollectionId.toQuotedString('`').toLowerCase())) {
return;
}
}
offsetContext.setQuery(query);
}
}
@Override
protected EventType getIncludeQueryEventType() {
return EventType.ANNOTATE_ROWS;
}
@Override
protected EventType getGtidEventType() {
return EventType.MARIADB_GTID;
}
@Override
protected void initializeGtidSet(String value) {
this.gtidSet = new MariadbGtidSet(value);
}
private static TableId getSignalDataCollectionId(MariaDbConnectorConfig connectorConfig) {
if (!Strings.isNullOrBlank(connectorConfig.getSignalingDataCollectionId())) {
return TableId.parse(connectorConfig.getSignalingDataCollectionId());
}
return null;
}
}

View File

@ -1,19 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogTaskContext;
/**
* A state (context) associated with a MariaDB connector task.
*
* @author Chris Cranford
*/
public class MariaDbTaskContext extends BinlogTaskContext<MariaDbDatabaseSchema> {
public MariaDbTaskContext(MariaDbConnectorConfig config, MariaDbDatabaseSchema schema) {
super(config, schema);
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.util.Properties;
import io.debezium.util.IoUtil;
/**
* Information about this MariaDb connector module.
*
* @author Chris Cranford
*/
public class Module {
private static final Properties INFO = IoUtil.loadProperties(Module.class, "io/debezium/connector/mariadb/build.version");
public static String version() {
return INFO.getProperty("version");
}
/**
* Get the connector's symbolic name.
*
* @return the connector plug-in's symbolic name, never {@code null}.
*/
public static String name() {
return "mariadb";
}
/**
* Get the connector context name used for logging and JMX.
*
* @return the context name, never {@code null}
*/
public static String contextName() {
return "MariaDB";
}
}

View File

@ -1,73 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.annotation.NotThreadSafe;
import io.debezium.connector.binlog.BinlogSourceInfo;
/**
* Information about the source, which includes the position in the binary transaction log.<p></p>
*
* The {@link MariaDbPartition#getSourcePartition() source partition} information describes the database whose
* log is being consumed. Typically, the database is identified by the host address and port number of the
* MariaDB server and the name of the database. Here's an example JSON representation:
*
* <pre>
* {
* "server": "production-server"
* }
* </pre>
*
* The offset includes the {@link #binlogFileName() binlog filename}, the {@link #binlogPosition() position of the first event}
* in the transaction log, the {@link MariaDbOffsetContext#eventsToSkipUponRestart() number of events to skip on restart},
* and the {@link MariaDbOffsetContext#rowsToSkipUponRestart() number of rows to skip}. An example:
*
* <pre>
* {
* "server_id": 112233,
* "ts_ms": 123456789,
* "gtid": "0-1-3",
* "file": "binlog.000003",
* "pos": 990,
* "event": 0,
* "row": 0,
* "snapshot": true
* }
* </pre>
*
* The "{@code snapshot}" field only appears in offsets produced during the snapshot phase. The "{@code ts_ms}" field
* contains the <em>milliseconds</em> since Unix epoch (since Jan 1 1970) of the MariaDB event.<p></p>
*
* Each change event {@link io.debezium.data.Envelope} also contains a {@link #struct() source} struct that contains
* the MariaDB information about that specific event, including a mixture of fields from the binary log filename and
* position where the event can be found, GTID details, etc. Like with the offset, the "{@code snapshot}" field will
* only appear for events produced during the snapshot phase.<p></p>
*
* Here's a JSON example of the source metadata for an event:
* <pre>
* {
* "name": "production-server",
* "server_id": 112233,
* "ts_ms": 123456789,
* "gtid": "0-1-3",
* "file": "binlog.000003",
* "pos": 1081,
* "row": 0,
* "snapshot": true,
* "thread": 1,
* "db": "inventory",
* "table": "products"
* }
* </pre>
*
* @author Chris Cranford
*/
@NotThreadSafe
public class SourceInfo extends BinlogSourceInfo {
public SourceInfo(MariaDbConnectorConfig connectorConfig) {
super(connectorConfig);
}
}

View File

@ -1,505 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr;
import java.sql.Types;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.tree.ParseTree;
import io.debezium.annotation.VisibleForTesting;
import io.debezium.antlr.AntlrDdlParser;
import io.debezium.antlr.AntlrDdlParserListener;
import io.debezium.antlr.DataTypeResolver;
import io.debezium.connector.binlog.charset.BinlogCharsetRegistry;
import io.debezium.connector.binlog.jdbc.BinlogSystemVariables;
import io.debezium.connector.mariadb.antlr.listener.MariaDbAntlrDdlParserListener;
import io.debezium.connector.mariadb.jdbc.MariaDbValueConverters;
import io.debezium.ddl.parser.mariadb.generated.MariaDBLexer;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser.CharsetNameContext;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser.CollationNameContext;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser.RenameTableClauseContext;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser.RenameTableContext;
import io.debezium.relational.Column;
import io.debezium.relational.ColumnEditor;
import io.debezium.relational.SystemVariables;
import io.debezium.relational.TableEditor;
import io.debezium.relational.TableId;
import io.debezium.relational.Tables;
/**
* An ANTLR based parser for MariaDB DDL statements.
*
* @author Chris Cranford
*/
public class MariaDbAntlrDdlParser extends AntlrDdlParser<MariaDBLexer, MariaDBParser> {
private final ConcurrentHashMap<String, String> charsetNameForDatabase = new ConcurrentHashMap<>();
private final MariaDbValueConverters converters;
private final Tables.TableFilter tableFilter;
private final BinlogCharsetRegistry charsetRegistry;
@VisibleForTesting
public MariaDbAntlrDdlParser() {
this(null, Tables.TableFilter.includeAll());
}
@VisibleForTesting
public MariaDbAntlrDdlParser(MariaDbValueConverters valueConverters) {
this(valueConverters, Tables.TableFilter.includeAll());
}
@VisibleForTesting
public MariaDbAntlrDdlParser(MariaDbValueConverters valueConverters, Tables.TableFilter tableFilter) {
this(true, false, true, valueConverters, tableFilter, null);
}
public MariaDbAntlrDdlParser(boolean throwWerrorsFromTreeWalk, boolean includeViews, boolean includeComments,
MariaDbValueConverters valueConverters, Tables.TableFilter tableFilter, BinlogCharsetRegistry charsetRegistry) {
super(throwWerrorsFromTreeWalk, includeViews, includeComments);
systemVariables = new BinlogSystemVariables();
this.converters = valueConverters;
this.tableFilter = tableFilter;
this.charsetRegistry = charsetRegistry;
}
@Override
protected ParseTree parseTree(MariaDBParser parser) {
return parser.root();
}
@Override
protected AntlrDdlParserListener createParseTreeWalkerListener() {
return new MariaDbAntlrDdlParserListener(this);
}
@Override
protected MariaDBLexer createNewLexerInstance(CharStream charStreams) {
return new MariaDBLexer(charStreams);
}
@Override
protected MariaDBParser createNewParserInstance(CommonTokenStream commonTokenStream) {
return new MariaDBParser(commonTokenStream);
}
@Override
protected SystemVariables createNewSystemVariablesInstance() {
return new BinlogSystemVariables();
}
@Override
protected boolean isGrammarInUpperCase() {
return true;
}
@Override
protected DataTypeResolver initializeDataTypeResolver() {
DataTypeResolver.Builder dataTypeResolverBuilder = new DataTypeResolver.Builder();
dataTypeResolverBuilder.registerDataTypes(MariaDBParser.StringDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeResolver.DataTypeEntry(Types.CHAR, MariaDBParser.CHAR),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.CHAR, MariaDBParser.VARYING),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.VARCHAR),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.TINYTEXT),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.TEXT),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.MEDIUMTEXT),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.LONGTEXT),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.LONG),
new DataTypeResolver.DataTypeEntry(Types.NCHAR, MariaDBParser.NCHAR),
new DataTypeResolver.DataTypeEntry(Types.NVARCHAR, MariaDBParser.NCHAR, MariaDBParser.VARYING),
new DataTypeResolver.DataTypeEntry(Types.NVARCHAR, MariaDBParser.NVARCHAR),
new DataTypeResolver.DataTypeEntry(Types.CHAR, MariaDBParser.CHAR, MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.VARCHAR, MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.TINYTEXT, MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.TEXT, MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.MEDIUMTEXT, MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.LONGTEXT, MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.NCHAR, MariaDBParser.NCHAR, MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.NVARCHAR, MariaDBParser.NVARCHAR, MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.CHAR, MariaDBParser.CHARACTER),
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.CHARACTER, MariaDBParser.VARYING)));
dataTypeResolverBuilder.registerDataTypes(MariaDBParser.NationalStringDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeResolver.DataTypeEntry(Types.NVARCHAR, MariaDBParser.NATIONAL, MariaDBParser.VARCHAR).setSuffixTokens(MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.NCHAR, MariaDBParser.NATIONAL, MariaDBParser.CHARACTER).setSuffixTokens(MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.NCHAR, MariaDBParser.NATIONAL, MariaDBParser.CHAR).setSuffixTokens(MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.NVARCHAR, MariaDBParser.NCHAR, MariaDBParser.VARCHAR).setSuffixTokens(MariaDBParser.BINARY)));
dataTypeResolverBuilder.registerDataTypes(MariaDBParser.NationalVaryingStringDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeResolver.DataTypeEntry(Types.NVARCHAR, MariaDBParser.NATIONAL, MariaDBParser.CHAR, MariaDBParser.VARYING),
new DataTypeResolver.DataTypeEntry(Types.NVARCHAR, MariaDBParser.NATIONAL, MariaDBParser.CHARACTER, MariaDBParser.VARYING)));
dataTypeResolverBuilder.registerDataTypes(MariaDBParser.DimensionDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeResolver.DataTypeEntry(Types.SMALLINT, MariaDBParser.TINYINT)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.SMALLINT, MariaDBParser.INT1)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.SMALLINT, MariaDBParser.SMALLINT)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.SMALLINT, MariaDBParser.INT2)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.INTEGER, MariaDBParser.MEDIUMINT)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.INTEGER, MariaDBParser.INT3)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.INTEGER, MariaDBParser.MIDDLEINT)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.INTEGER, MariaDBParser.INT)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.INTEGER, MariaDBParser.INTEGER)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.INTEGER, MariaDBParser.INT4)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.BIGINT, MariaDBParser.BIGINT)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.BIGINT, MariaDBParser.INT8)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.REAL, MariaDBParser.REAL)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.DOUBLE, MariaDBParser.DOUBLE)
.setSuffixTokens(MariaDBParser.PRECISION, MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.DOUBLE, MariaDBParser.FLOAT8)
.setSuffixTokens(MariaDBParser.PRECISION, MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.FLOAT, MariaDBParser.FLOAT)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.FLOAT, MariaDBParser.FLOAT4)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL),
new DataTypeResolver.DataTypeEntry(Types.DECIMAL, MariaDBParser.DECIMAL)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL)
.setDefaultLengthScaleDimension(10, 0),
new DataTypeResolver.DataTypeEntry(Types.DECIMAL, MariaDBParser.DEC)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL)
.setDefaultLengthScaleDimension(10, 0),
new DataTypeResolver.DataTypeEntry(Types.DECIMAL, MariaDBParser.FIXED)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL)
.setDefaultLengthScaleDimension(10, 0),
new DataTypeResolver.DataTypeEntry(Types.NUMERIC, MariaDBParser.NUMERIC)
.setSuffixTokens(MariaDBParser.SIGNED, MariaDBParser.UNSIGNED, MariaDBParser.ZEROFILL)
.setDefaultLengthScaleDimension(10, 0),
new DataTypeResolver.DataTypeEntry(Types.BIT, MariaDBParser.BIT)
.setDefaultLengthDimension(1),
new DataTypeResolver.DataTypeEntry(Types.TIME, MariaDBParser.TIME),
new DataTypeResolver.DataTypeEntry(Types.TIMESTAMP_WITH_TIMEZONE, MariaDBParser.TIMESTAMP),
new DataTypeResolver.DataTypeEntry(Types.TIMESTAMP, MariaDBParser.DATETIME),
new DataTypeResolver.DataTypeEntry(Types.BINARY, MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.VARBINARY, MariaDBParser.VARBINARY),
new DataTypeResolver.DataTypeEntry(Types.BLOB, MariaDBParser.BLOB),
new DataTypeResolver.DataTypeEntry(Types.INTEGER, MariaDBParser.YEAR)));
dataTypeResolverBuilder.registerDataTypes(MariaDBParser.SimpleDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeResolver.DataTypeEntry(Types.DATE, MariaDBParser.DATE),
new DataTypeResolver.DataTypeEntry(Types.BLOB, MariaDBParser.TINYBLOB),
new DataTypeResolver.DataTypeEntry(Types.BLOB, MariaDBParser.MEDIUMBLOB),
new DataTypeResolver.DataTypeEntry(Types.BLOB, MariaDBParser.LONGBLOB),
new DataTypeResolver.DataTypeEntry(Types.BOOLEAN, MariaDBParser.BOOL),
new DataTypeResolver.DataTypeEntry(Types.BOOLEAN, MariaDBParser.BOOLEAN),
new DataTypeResolver.DataTypeEntry(Types.BIGINT, MariaDBParser.SERIAL)));
dataTypeResolverBuilder.registerDataTypes(MariaDBParser.CollectionDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeResolver.DataTypeEntry(Types.CHAR, MariaDBParser.ENUM).setSuffixTokens(MariaDBParser.BINARY),
new DataTypeResolver.DataTypeEntry(Types.CHAR, MariaDBParser.SET).setSuffixTokens(MariaDBParser.BINARY)));
dataTypeResolverBuilder.registerDataTypes(MariaDBParser.SpatialDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.GEOMETRYCOLLECTION),
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.GEOMCOLLECTION),
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.LINESTRING),
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.MULTILINESTRING),
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.MULTIPOINT),
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.MULTIPOLYGON),
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.POINT),
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.POLYGON),
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.JSON),
new DataTypeResolver.DataTypeEntry(Types.OTHER, MariaDBParser.GEOMETRY)));
dataTypeResolverBuilder.registerDataTypes(MariaDBParser.LongVarbinaryDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeResolver.DataTypeEntry(Types.BLOB, MariaDBParser.LONG)
.setSuffixTokens(MariaDBParser.VARBINARY)));
dataTypeResolverBuilder.registerDataTypes(MariaDBParser.LongVarcharDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeResolver.DataTypeEntry(Types.VARCHAR, MariaDBParser.LONG)
.setSuffixTokens(MariaDBParser.VARCHAR)));
return dataTypeResolverBuilder.build();
}
/**
* Get the character set registry.
*
* @return the character set registry
*/
public BinlogCharsetRegistry getCharsetRegistry() {
return charsetRegistry;
}
/**
* Provides a map of default character sets by database/schema name.
*
* @return map of default character sets.
*/
public ConcurrentMap<String, String> charsetNameForDatabase() {
return charsetNameForDatabase;
}
/**
* Parse a name from {@link MariaDBParser.UidContext}.
*
* @param uidContext uid context
* @return name without quotes.
*/
public String parseName(MariaDBParser.UidContext uidContext) {
return withoutQuotes(uidContext);
}
/**
* Parse qualified table identification from {@link MariaDBParser.FullIdContext}.
* {@link MariaDbAntlrDdlParser#currentSchema()} will be used if definition of schema name is not part of the context.
*
* @param fullIdContext full id context.
* @return qualified {@link TableId}.
*/
public TableId parseQualifiedTableId(MariaDBParser.FullIdContext fullIdContext) {
final char[] fullTableName = fullIdContext.getText().toCharArray();
StringBuilder component = new StringBuilder();
String dbName = null;
String tableName = null;
final char EMPTY = '\0';
char lastQuote = EMPTY;
for (int i = 0; i < fullTableName.length; i++) {
char c = fullTableName[i];
if (isQuote(c)) {
// Opening quote
if (lastQuote == EMPTY) {
lastQuote = c;
}
// Closing quote
else if (lastQuote == c) {
// escape of quote by doubling
if (i < fullTableName.length - 1 && fullTableName[i + 1] == c) {
component.append(c);
i++;
}
else {
lastQuote = EMPTY;
}
}
// Quote that is part of name
else {
component.append(c);
}
}
// dot that is not in quotes, so name separator
else if (c == '.' && lastQuote == EMPTY) {
dbName = component.toString();
component = new StringBuilder();
}
// Any char is part of name including quoted dot
else {
component.append(c);
}
}
tableName = component.toString();
return resolveTableId(dbName != null ? dbName : currentSchema(), tableName);
}
/**
* Parse column names for primary index from {@link MariaDBParser.IndexColumnNamesContext}. This method will update
* column to be not optional and set primary key column names to table.
*
* @param indexColumnNamesContext primary key index column names context.
* @param tableEditor editor for table where primary key index is parsed.
*/
public void parsePrimaryIndexColumnNames(MariaDBParser.IndexColumnNamesContext indexColumnNamesContext, TableEditor tableEditor) {
List<String> pkColumnNames = indexColumnNamesContext.indexColumnName().stream()
.map(indexColumnNameContext -> {
// MariaDB does not allow a primary key to have nullable columns, so let's make sure we model that correctly ...
String columnName;
if (indexColumnNameContext.uid() != null) {
columnName = parseName(indexColumnNameContext.uid());
}
else if (indexColumnNameContext.STRING_LITERAL() != null) {
columnName = withoutQuotes(indexColumnNameContext.STRING_LITERAL().getText());
}
else {
columnName = indexColumnNameContext.expression().getText();
}
Column column = tableEditor.columnWithName(columnName);
if (column != null && column.isOptional()) {
final ColumnEditor ce = column.edit().optional(false);
if (ce.hasDefaultValue() && !ce.defaultValueExpression().isPresent()) {
ce.unsetDefaultValueExpression();
}
tableEditor.addColumn(ce.create());
}
return column != null ? column.name() : columnName;
})
.collect(Collectors.toList());
tableEditor.setPrimaryKeyNames(pkColumnNames);
}
/**
* Parse column names for unique index from {@link MariaDBParser.IndexColumnNamesContext}. This method will set
* unique key column names to table if there are no optional.
*
* @param indexColumnNamesContext unique key index column names context.
* @param tableEditor editor for table where primary key index is parsed.
*/
public void parseUniqueIndexColumnNames(MariaDBParser.IndexColumnNamesContext indexColumnNamesContext, TableEditor tableEditor) {
List<Column> indexColumns = getIndexColumns(indexColumnNamesContext, tableEditor);
if (indexColumns.stream().filter(col -> Objects.isNull(col) || col.isOptional()).count() > 0) {
logger.warn("Skip to set unique index columns {} to primary key which including optional columns", indexColumns);
}
else {
tableEditor.setPrimaryKeyNames(indexColumns.stream().map(Column::name).collect(Collectors.toList()));
}
}
/**
* Determine if a table's unique index should be included when parsing relative unique index statement.
*
* @param indexColumnNamesContext unique index column names context.
* @param tableEditor editor for table where unique index is parsed.
* @return true if the index is to be included; false otherwise.
*/
public boolean isTableUniqueIndexIncluded(MariaDBParser.IndexColumnNamesContext indexColumnNamesContext, TableEditor tableEditor) {
return getIndexColumns(indexColumnNamesContext, tableEditor).stream().filter(Objects::isNull).count() == 0;
}
private List<Column> getIndexColumns(MariaDBParser.IndexColumnNamesContext indexColumnNamesContext, TableEditor tableEditor) {
return indexColumnNamesContext.indexColumnName().stream()
.map(indexColumnNameContext -> {
String columnName;
if (indexColumnNameContext.uid() != null) {
columnName = parseName(indexColumnNameContext.uid());
}
else if (indexColumnNameContext.STRING_LITERAL() != null) {
columnName = withoutQuotes(indexColumnNameContext.STRING_LITERAL().getText());
}
else {
columnName = indexColumnNameContext.expression().getText();
}
return tableEditor.columnWithName(columnName);
})
.collect(Collectors.toList());
}
/**
* Get the name of the character set for the current database, via the "character_set_database" system property.
*
* @return the name of the character set for the current database, or null if not known ...
*/
public String currentDatabaseCharset() {
String charsetName = systemVariables.getVariable(BinlogSystemVariables.CHARSET_NAME_DATABASE);
if (charsetName == null || "DEFAULT".equalsIgnoreCase(charsetName)) {
charsetName = systemVariables.getVariable(BinlogSystemVariables.CHARSET_NAME_SERVER);
}
return charsetName;
}
/**
* Get the name of the character set for the give table name.
*
* @return the name of the character set for the given table, or null if not known ...
*/
public String charsetForTable(TableId tableId) {
final String defaultDatabaseCharset = tableId.catalog() != null ? charsetNameForDatabase().get(tableId.catalog()) : null;
return defaultDatabaseCharset != null ? defaultDatabaseCharset : currentDatabaseCharset();
}
/**
* Runs a function if all given object are not null.
*
* @param function function to run; may not be null
* @param nullableObjects object to be tested, if they are null.
*/
public void runIfNotNull(Runnable function, Object... nullableObjects) {
for (Object nullableObject : nullableObjects) {
if (nullableObject == null) {
return;
}
}
function.run();
}
/**
* Extracts the enumeration values properly parsed and escaped.
*
* @param enumValues the raw enumeration values from the parsed column definition
* @return the list of options allowed for the {@code ENUM} or {@code SET}; never null.
*/
public static List<String> extractEnumAndSetOptions(List<String> enumValues) {
return enumValues.stream()
.map(MariaDbAntlrDdlParser::withoutQuotes)
.map(MariaDbAntlrDdlParser::escapeOption)
.collect(Collectors.toList());
}
public static String escapeOption(String option) {
// Replace comma to backslash followed by comma (this escape sequence implies comma is part of the option)
// Replace backlash+single-quote to a single-quote.
// Replace double single-quote to a single-quote.
return option.replaceAll(",", "\\\\,").replaceAll("\\\\'", "'").replace("''", "'");
}
public MariaDbValueConverters getConverters() {
return converters;
}
public Tables.TableFilter getTableFilter() {
return tableFilter;
}
/**
* Obtains the charset name either form charset if present or from collation.
*
* @param charsetNode
* @param collationNode
* @return character set
*/
public String extractCharset(CharsetNameContext charsetNode, CollationNameContext collationNode) {
String charsetName = null;
if (charsetNode != null && charsetNode.getText() != null) {
charsetName = withoutQuotes(charsetNode.getText());
// System.out.println("[charSetNode]: charSetName => " + charsetName + " (" + charsetNode.getText() + ")");
}
else if (collationNode != null && collationNode.getText() != null) {
final String collationName = withoutQuotes(collationNode.getText()).toLowerCase();
for (int index = 0; index < charsetRegistry.getCharsetMapSize(); index++) {
if (collationName.equals(charsetRegistry.getCollationNameForCollationIndex(index))) {
charsetName = charsetRegistry.getCharsetNameForCollationIndex(index);
break;
}
}
// System.out.println("[collationNode]: charSetName => " + charsetName + " (" + collationNode.getText() + ")");
}
return charsetName;
}
/**
* Signal an alter table event to ddl changes listener.
*
* @param id the table identifier; may not be null
* @param previousId the previous name of the view if it was renamed, or null if it was not renamed
* @param ctx the start of the statement; may not be null
*/
public void signalAlterTable(TableId id, TableId previousId, RenameTableClauseContext ctx) {
final RenameTableContext parent = (RenameTableContext) ctx.getParent();
Interval interval = new Interval(ctx.getParent().start.getStartIndex(),
parent.renameTableClause().get(0).start.getStartIndex() - 1);
String prefix = ctx.getParent().start.getInputStream().getText(interval);
signalAlterTable(id, previousId, prefix + getText(ctx));
}
}

View File

@ -1,362 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import static io.debezium.antlr.AntlrDdlParser.getText;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.relational.Column;
import io.debezium.relational.ColumnEditor;
import io.debezium.relational.TableId;
import io.debezium.text.ParsingException;
/**
* A parser listener that parses ALTER TABLE statements.
*
* @author Chris Cranford
*/
public class AlterTableParserListener extends TableCommonParserListener {
private static final int STARTING_INDEX = 1;
private final static Logger LOG = LoggerFactory.getLogger(AlterTableParserListener.class);
private ColumnEditor defaultValueColumnEditor;
private DefaultValueParserListener defaultValueListener;
private List<ColumnEditor> columnEditors;
private int parsingColumnIndex = STARTING_INDEX;
public AlterTableParserListener(MariaDbAntlrDdlParser parser, List<ParseTreeListener> listeners) {
super(parser, listeners);
}
@Override
public void enterAlterTable(MariaDBParser.AlterTableContext ctx) {
final TableId tableId = parser.parseQualifiedTableId(ctx.tableName().fullId());
if (parser.databaseTables().forTable(tableId) == null) {
LOG.debug("Ignoring ALTER TABLE statement for non-captured table {}", tableId);
return;
}
tableEditor = parser.databaseTables().editTable(tableId);
if (tableEditor == null) {
throw new ParsingException(null, "Trying to alter table " + tableId.toString()
+ ", which does not exist. Query: " + getText(ctx));
}
super.enterAlterTable(ctx);
}
@Override
public void exitAlterTable(MariaDBParser.AlterTableContext ctx) {
parser.runIfNotNull(() -> {
listeners.remove(columnDefinitionListener);
parser.databaseTables().overwriteTable(tableEditor.create());
parser.signalAlterTable(tableEditor.tableId(), null, ctx.getParent());
}, tableEditor);
super.exitAlterTable(ctx);
tableEditor = null;
}
@Override
public void enterAlterByAddColumn(MariaDBParser.AlterByAddColumnContext ctx) {
parser.runIfNotNull(() -> {
String columnName = parser.parseName(ctx.uid(0));
ColumnEditor columnEditor = Column.editor().name(columnName);
columnDefinitionListener = new ColumnDefinitionParserListener(tableEditor, columnEditor, parser, listeners);
listeners.add(columnDefinitionListener);
}, tableEditor);
super.exitAlterByAddColumn(ctx);
}
@Override
public void exitAlterByAddColumn(MariaDBParser.AlterByAddColumnContext ctx) {
parser.runIfNotNull(() -> {
Column column = columnDefinitionListener.getColumn();
tableEditor.addColumn(column);
String columnName = column.name();
if (ctx.FIRST() != null) {
tableEditor.reorderColumn(columnName, null);
}
else if (ctx.AFTER() != null) {
String afterColumn = parser.parseName(ctx.uid(1));
tableEditor.reorderColumn(columnName, afterColumn);
}
listeners.remove(columnDefinitionListener);
}, tableEditor, columnDefinitionListener);
super.exitAlterByAddColumn(ctx);
}
@Override
public void enterAlterByAddColumns(MariaDBParser.AlterByAddColumnsContext ctx) {
// multiple columns are added. Initialize a list of column editors for them
parser.runIfNotNull(() -> {
columnEditors = new ArrayList<>(ctx.uid().size());
for (MariaDBParser.UidContext uidContext : ctx.uid()) {
String columnName = parser.parseName(uidContext);
columnEditors.add(Column.editor().name(columnName));
}
columnDefinitionListener = new ColumnDefinitionParserListener(tableEditor, columnEditors.get(0), parser, listeners);
listeners.add(columnDefinitionListener);
}, tableEditor);
super.enterAlterByAddColumns(ctx);
}
@Override
public void exitColumnDefinition(MariaDBParser.ColumnDefinitionContext ctx) {
parser.runIfNotNull(() -> {
if (columnEditors != null) {
// column editor list is not null when a multiple columns are parsed in one statement
if (columnEditors.size() > parsingColumnIndex) {
// assign next column editor to parse another column definition
columnDefinitionListener.setColumnEditor(columnEditors.get(parsingColumnIndex++));
}
else {
// all columns parsed
// reset global variables for next parsed statement
columnEditors.forEach(columnEditor -> tableEditor.addColumn(columnEditor.create()));
columnEditors = null;
parsingColumnIndex = STARTING_INDEX;
}
}
}, tableEditor, columnEditors);
super.exitColumnDefinition(ctx);
}
@Override
public void exitAlterByAddColumns(MariaDBParser.AlterByAddColumnsContext ctx) {
parser.runIfNotNull(() -> {
columnEditors.forEach(columnEditor -> tableEditor.addColumn(columnEditor.create()));
listeners.remove(columnDefinitionListener);
}, tableEditor, columnEditors);
super.exitAlterByAddColumns(ctx);
}
@Override
public void enterAlterByChangeColumn(MariaDBParser.AlterByChangeColumnContext ctx) {
parser.runIfNotNull(() -> {
String oldColumnName = parser.parseName(ctx.oldColumn);
Column existingColumn = tableEditor.columnWithName(oldColumnName);
if (existingColumn != null) {
// DBZ-771 unset previously set default value, as it's not kept by MariaDB; for any column modifications a new
// default value (which could be the same) has to be provided by the column_definition which we'll parse later
// on; only in 8.0 (not yet supported by this parser) columns can be renamed without repeating the full column
// definition; so in fact it's arguably not correct to use edit() on the existing column to begin with, but
// I'm going to leave this as is for now, to be prepared for the ability of updating column definitions in 8.0
ColumnEditor columnEditor = existingColumn.edit();
columnEditor.unsetDefaultValueExpression();
columnEditor.unsetLength();
if (columnEditor.scale().isPresent()) {
columnEditor.unsetScale();
}
columnDefinitionListener = new ColumnDefinitionParserListener(tableEditor, columnEditor, parser, listeners);
listeners.add(columnDefinitionListener);
}
else {
throw new ParsingException(null, "Trying to change column " + oldColumnName + " in "
+ tableEditor.tableId().toString() + " table, which does not exist. Query: " + getText(ctx));
}
}, tableEditor);
super.enterAlterByChangeColumn(ctx);
}
@Override
public void exitAlterByChangeColumn(MariaDBParser.AlterByChangeColumnContext ctx) {
parser.runIfNotNull(() -> {
Column column = columnDefinitionListener.getColumn();
tableEditor.addColumn(column);
String newColumnName = parser.parseName(ctx.newColumn);
if (newColumnName != null && !column.name().equals(newColumnName)) {
tableEditor.renameColumn(column.name(), newColumnName);
}
if (ctx.FIRST() != null) {
tableEditor.reorderColumn(newColumnName, null);
}
else if (ctx.afterColumn != null) {
tableEditor.reorderColumn(newColumnName, parser.parseName(ctx.afterColumn));
}
listeners.remove(columnDefinitionListener);
}, tableEditor, columnDefinitionListener);
super.exitAlterByChangeColumn(ctx);
}
@Override
public void enterAlterByModifyColumn(MariaDBParser.AlterByModifyColumnContext ctx) {
parser.runIfNotNull(() -> {
String columnName = parser.parseName(ctx.uid(0));
Column existingColumn = tableEditor.columnWithName(columnName);
if (existingColumn != null) {
ColumnEditor columnEditor = Column.editor().name(columnName);
columnDefinitionListener = new ColumnDefinitionParserListener(tableEditor, columnEditor, parser, listeners);
listeners.add(columnDefinitionListener);
}
else {
throw new ParsingException(null, "Trying to change column " + columnName + " in "
+ tableEditor.tableId().toString() + " table, which does not exist. Query: " + getText(ctx));
}
}, tableEditor);
super.enterAlterByModifyColumn(ctx);
}
@Override
public void exitAlterByModifyColumn(MariaDBParser.AlterByModifyColumnContext ctx) {
parser.runIfNotNull(() -> {
Column column = columnDefinitionListener.getColumn();
tableEditor.addColumn(column);
if (ctx.FIRST() != null) {
tableEditor.reorderColumn(column.name(), null);
}
else if (ctx.AFTER() != null) {
String afterColumn = parser.parseName(ctx.uid(1));
tableEditor.reorderColumn(column.name(), afterColumn);
}
listeners.remove(columnDefinitionListener);
}, tableEditor, columnDefinitionListener);
super.exitAlterByModifyColumn(ctx);
}
@Override
public void enterAlterByDropColumn(MariaDBParser.AlterByDropColumnContext ctx) {
parser.runIfNotNull(() -> {
tableEditor.removeColumn(parser.parseName(ctx.uid()));
}, tableEditor);
super.enterAlterByDropColumn(ctx);
}
@Override
public void enterAlterByRename(MariaDBParser.AlterByRenameContext ctx) {
parser.runIfNotNull(() -> {
final TableId newTableId = ctx.uid() != null
? parser.resolveTableId(parser.currentSchema(), parser.parseName(ctx.uid()))
: parser.parseQualifiedTableId(ctx.fullId());
parser.databaseTables().overwriteTable(tableEditor.create());
parser.databaseTables().renameTable(tableEditor.tableId(), newTableId);
tableEditor = parser.databaseTables().editTable(newTableId);
}, tableEditor);
super.enterAlterByRename(ctx);
}
@Override
public void enterAlterByChangeDefault(MariaDBParser.AlterByChangeDefaultContext ctx) {
parser.runIfNotNull(() -> {
String columnName = parser.parseName(ctx.uid());
Column column = tableEditor.columnWithName(columnName);
if (column != null) {
defaultValueColumnEditor = column.edit();
if (ctx.SET() != null) {
defaultValueListener = new DefaultValueParserListener(defaultValueColumnEditor,
new AtomicReference<>(column.isOptional()));
listeners.add(defaultValueListener);
}
else if (ctx.DROP() != null) {
defaultValueColumnEditor.unsetDefaultValueExpression();
}
}
}, tableEditor);
super.enterAlterByChangeDefault(ctx);
}
@Override
public void exitAlterByChangeDefault(MariaDBParser.AlterByChangeDefaultContext ctx) {
parser.runIfNotNull(() -> {
tableEditor.updateColumn(defaultValueColumnEditor.create());
listeners.remove(defaultValueListener);
defaultValueColumnEditor = null;
}, defaultValueColumnEditor);
super.exitAlterByChangeDefault(ctx);
}
@Override
public void enterAlterByAddPrimaryKey(MariaDBParser.AlterByAddPrimaryKeyContext ctx) {
parser.runIfNotNull(() -> {
parser.parsePrimaryIndexColumnNames(ctx.indexColumnNames(), tableEditor);
}, tableEditor);
super.enterAlterByAddPrimaryKey(ctx);
}
@Override
public void enterAlterByDropPrimaryKey(MariaDBParser.AlterByDropPrimaryKeyContext ctx) {
parser.runIfNotNull(() -> {
tableEditor.setPrimaryKeyNames(new ArrayList<>());
}, tableEditor);
super.enterAlterByDropPrimaryKey(ctx);
}
@Override
public void enterAlterByAddUniqueKey(MariaDBParser.AlterByAddUniqueKeyContext ctx) {
parser.runIfNotNull(() -> {
if (!tableEditor.hasPrimaryKey() && parser.isTableUniqueIndexIncluded(ctx.indexColumnNames(), tableEditor)) {
// this may eventually get overwritten by a real PK
parser.parseUniqueIndexColumnNames(ctx.indexColumnNames(), tableEditor);
}
}, tableEditor);
super.enterAlterByAddUniqueKey(ctx);
}
@Override
public void enterAlterByRenameColumn(MariaDBParser.AlterByRenameColumnContext ctx) {
parser.runIfNotNull(() -> {
String oldColumnName = parser.parseName(ctx.oldColumn);
Column existingColumn = tableEditor.columnWithName(oldColumnName);
if (existingColumn != null) {
// DBZ-771 unset previously set default value, as it's not kept by MariaDB; for any column modifications a new
// default value (which could be the same) has to be provided by the column_definition which we'll parse later
// on; only in 8.0 (not yet supported by this parser) columns can be renamed without repeating the full column
// definition; so in fact it's arguably not correct to use edit() on the existing column to begin with, but
// I'm going to leave this as is for now, to be prepared for the ability of updating column definitions in 8.0
ColumnEditor columnEditor = existingColumn.edit();
// columnEditor.unsetDefaultValue();
columnDefinitionListener = new ColumnDefinitionParserListener(tableEditor, columnEditor, parser, listeners);
listeners.add(columnDefinitionListener);
}
else {
throw new ParsingException(null, "Trying to change column " + oldColumnName + " in "
+ tableEditor.tableId().toString() + " table, which does not exist. Query: " + getText(ctx));
}
}, tableEditor);
super.enterAlterByRenameColumn(ctx);
}
@Override
public void exitAlterByRenameColumn(MariaDBParser.AlterByRenameColumnContext ctx) {
parser.runIfNotNull(() -> {
Column column = columnDefinitionListener.getColumn();
tableEditor.addColumn(column);
String newColumnName = parser.parseName(ctx.newColumn);
if (newColumnName != null && !column.name().equals(newColumnName)) {
tableEditor.renameColumn(column.name(), newColumnName);
}
listeners.remove(columnDefinitionListener);
}, tableEditor, columnDefinitionListener);
super.exitAlterByRenameColumn(ctx);
}
@Override
public void enterTableOptionComment(MariaDBParser.TableOptionCommentContext ctx) {
if (!parser.skipComments()) {
parser.runIfNotNull(() -> {
if (ctx.COMMENT() != null) {
tableEditor.setComment(parser.withoutQuotes(ctx.STRING_LITERAL().getText()));
}
}, tableEditor);
}
super.enterTableOptionComment(ctx);
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import java.util.List;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import io.debezium.antlr.AntlrDdlParser;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.Column;
import io.debezium.relational.TableEditor;
import io.debezium.relational.TableId;
import io.debezium.text.ParsingException;
/**
* Parser listener that parses ALTER VIEW statements.
*
* @author Chris Cranford
*/
public class AlterViewParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
private final List<ParseTreeListener> listeners;
private TableEditor tableEditor;
private ViewSelectedColumnsParserListener selectColumnsListener;
public AlterViewParserListener(MariaDbAntlrDdlParser parser, List<ParseTreeListener> listeners) {
this.parser = parser;
this.listeners = listeners;
}
@Override
public void enterAlterView(MariaDBParser.AlterViewContext ctx) {
if (!parser.skipViews()) {
TableId tableId = parser.parseQualifiedTableId(ctx.fullId());
tableEditor = parser.databaseTables().editTable(tableId);
if (tableEditor == null) {
throw new ParsingException(null, "Trying to alter view " + tableId.toString()
+ ", which does not exist. Query:" + AntlrDdlParser.getText(ctx));
}
// alter view will override existing columns for a new one
tableEditor.columnNames().forEach(tableEditor::removeColumn);
// create new columns just with specified name for now
if (ctx.uidList() != null) {
ctx.uidList().uid().stream().map(parser::parseName).forEach(columnName -> {
tableEditor.addColumn(Column.editor().name(columnName).create());
});
}
selectColumnsListener = new ViewSelectedColumnsParserListener(tableEditor, parser);
listeners.add(selectColumnsListener);
}
super.enterAlterView(ctx);
}
@Override
public void exitAlterView(MariaDBParser.AlterViewContext ctx) {
parser.runIfNotNull(() -> {
tableEditor.addColumns(selectColumnsListener.getSelectedColumns());
// Make sure that the table's character set has been set ...
if (!tableEditor.hasDefaultCharsetName()) {
tableEditor.setDefaultCharsetName(parser.currentDatabaseCharset());
}
parser.databaseTables().overwriteTable(tableEditor.create());
listeners.remove(selectColumnsListener);
}, tableEditor);
// signal view even if it was skipped
parser.signalAlterView(parser.parseQualifiedTableId(ctx.fullId()), null, ctx);
super.exitAlterView(ctx);
}
}

View File

@ -1,304 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import java.sql.Types;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.debezium.antlr.AntlrDdlParser;
import io.debezium.antlr.DataTypeResolver;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.Column;
import io.debezium.relational.ColumnEditor;
import io.debezium.relational.TableEditor;
import io.debezium.relational.ddl.DataType;
import io.debezium.util.Strings;
/**
* Parser listener for column definitions.
*
* @author Chris Cranford
*/
public class ColumnDefinitionParserListener extends MariaDBParserBaseListener {
private static final Logger LOGGER = LoggerFactory.getLogger(ColumnDefinitionParserListener.class);
private static final Pattern DOT = Pattern.compile("\\.");
private final MariaDbAntlrDdlParser parser;
private final DataTypeResolver dataTypeResolver;
private final TableEditor tableEditor;
private ColumnEditor columnEditor;
private boolean uniqueColumn;
private AtomicReference<Boolean> optionalColumn = new AtomicReference<>();
private DefaultValueParserListener defaultValueListener;
private final List<ParseTreeListener> listeners;
public ColumnDefinitionParserListener(TableEditor tableEditor,
ColumnEditor columnEditor,
MariaDbAntlrDdlParser parser,
List<ParseTreeListener> listeners) {
this.tableEditor = tableEditor;
this.columnEditor = columnEditor;
this.parser = parser;
this.dataTypeResolver = parser.dataTypeResolver();
this.listeners = listeners;
}
public void setColumnEditor(ColumnEditor columnEditor) {
this.columnEditor = columnEditor;
}
public ColumnEditor getColumnEditor() {
return columnEditor;
}
public Column getColumn() {
return columnEditor.create();
}
@Override
public void enterColumnDefinition(MariaDBParser.ColumnDefinitionContext ctx) {
uniqueColumn = false;
optionalColumn = new AtomicReference<>();
resolveColumnDataType(ctx.dataType());
parser.runIfNotNull(() -> {
defaultValueListener = new DefaultValueParserListener(columnEditor, optionalColumn);
listeners.add(defaultValueListener);
}, tableEditor);
super.enterColumnDefinition(ctx);
}
@Override
public void exitColumnDefinition(MariaDBParser.ColumnDefinitionContext ctx) {
if (optionalColumn.get() != null) {
columnEditor.optional(optionalColumn.get().booleanValue());
}
if (uniqueColumn && !tableEditor.hasPrimaryKey()) {
// take the first unique constrain if no primary key is set
tableEditor.addColumn(columnEditor.create());
tableEditor.setPrimaryKeyNames(columnEditor.name());
}
parser.runIfNotNull(() -> {
defaultValueListener.exitDefaultValue(false);
listeners.remove(defaultValueListener);
}, tableEditor);
super.exitColumnDefinition(ctx);
}
@Override
public void enterUniqueKeyColumnConstraint(MariaDBParser.UniqueKeyColumnConstraintContext ctx) {
uniqueColumn = true;
super.enterUniqueKeyColumnConstraint(ctx);
}
@Override
public void enterPrimaryKeyColumnConstraint(MariaDBParser.PrimaryKeyColumnConstraintContext ctx) {
// this rule will be parsed only if no primary key is set in a table
// otherwise the statement can't be executed due to multiple primary key error
optionalColumn.set(Boolean.FALSE);
tableEditor.addColumn(columnEditor.create());
tableEditor.setPrimaryKeyNames(columnEditor.name());
super.enterPrimaryKeyColumnConstraint(ctx);
}
@Override
public void enterCommentColumnConstraint(MariaDBParser.CommentColumnConstraintContext ctx) {
if (!parser.skipComments()) {
if (ctx.STRING_LITERAL() != null) {
columnEditor.comment(parser.withoutQuotes(ctx.STRING_LITERAL().getText()));
}
}
super.enterCommentColumnConstraint(ctx);
}
@Override
public void enterNullNotnull(MariaDBParser.NullNotnullContext ctx) {
optionalColumn.set(Boolean.valueOf(ctx.NOT() == null));
super.enterNullNotnull(ctx);
}
@Override
public void enterAutoIncrementColumnConstraint(MariaDBParser.AutoIncrementColumnConstraintContext ctx) {
columnEditor.autoIncremented(true);
columnEditor.generated(true);
super.enterAutoIncrementColumnConstraint(ctx);
}
@Override
public void enterSerialDefaultColumnConstraint(MariaDBParser.SerialDefaultColumnConstraintContext ctx) {
serialColumn();
super.enterSerialDefaultColumnConstraint(ctx);
}
private void resolveColumnDataType(MariaDBParser.DataTypeContext dataTypeContext) {
String charsetName = null;
DataType dataType = dataTypeResolver.resolveDataType(dataTypeContext);
if (dataTypeContext instanceof MariaDBParser.StringDataTypeContext) {
// Same as LongVarcharDataTypeContext but with dimension handling
MariaDBParser.StringDataTypeContext stringDataTypeContext = (MariaDBParser.StringDataTypeContext) dataTypeContext;
if (stringDataTypeContext.lengthOneDimension() != null) {
Integer length = parseLength(stringDataTypeContext.lengthOneDimension().decimalLiteral().getText());
columnEditor.length(length);
}
charsetName = parser.extractCharset(stringDataTypeContext.charsetName(), stringDataTypeContext.collationName());
}
else if (dataTypeContext instanceof MariaDBParser.LongVarcharDataTypeContext) {
// Same as StringDataTypeContext but without dimension handling
MariaDBParser.LongVarcharDataTypeContext longVarcharTypeContext = (MariaDBParser.LongVarcharDataTypeContext) dataTypeContext;
charsetName = parser.extractCharset(longVarcharTypeContext.charsetName(), longVarcharTypeContext.collationName());
}
else if (dataTypeContext instanceof MariaDBParser.NationalStringDataTypeContext) {
MariaDBParser.NationalStringDataTypeContext nationalStringDataTypeContext = (MariaDBParser.NationalStringDataTypeContext) dataTypeContext;
if (nationalStringDataTypeContext.lengthOneDimension() != null) {
Integer length = parseLength(nationalStringDataTypeContext.lengthOneDimension().decimalLiteral().getText());
columnEditor.length(length);
}
}
else if (dataTypeContext instanceof MariaDBParser.NationalVaryingStringDataTypeContext) {
MariaDBParser.NationalVaryingStringDataTypeContext nationalVaryingStringDataTypeContext = (MariaDBParser.NationalVaryingStringDataTypeContext) dataTypeContext;
if (nationalVaryingStringDataTypeContext.lengthOneDimension() != null) {
Integer length = parseLength(nationalVaryingStringDataTypeContext.lengthOneDimension().decimalLiteral().getText());
columnEditor.length(length);
}
}
else if (dataTypeContext instanceof MariaDBParser.DimensionDataTypeContext) {
MariaDBParser.DimensionDataTypeContext dimensionDataTypeContext = (MariaDBParser.DimensionDataTypeContext) dataTypeContext;
Integer length = null;
Integer scale = null;
if (dimensionDataTypeContext.lengthOneDimension() != null) {
length = parseLength(dimensionDataTypeContext.lengthOneDimension().decimalLiteral().getText());
}
if (dimensionDataTypeContext.lengthTwoDimension() != null) {
List<MariaDBParser.DecimalLiteralContext> decimalLiterals = dimensionDataTypeContext.lengthTwoDimension().decimalLiteral();
length = parseLength(decimalLiterals.get(0).getText());
scale = Integer.valueOf(decimalLiterals.get(1).getText());
}
if (dimensionDataTypeContext.lengthTwoOptionalDimension() != null) {
List<MariaDBParser.DecimalLiteralContext> decimalLiterals = dimensionDataTypeContext.lengthTwoOptionalDimension().decimalLiteral();
if (decimalLiterals.get(0).REAL_LITERAL() != null) {
String[] digits = DOT.split(decimalLiterals.get(0).getText());
if (Strings.isNullOrEmpty(digits[0]) || Integer.valueOf(digits[0]) == 0) {
// Set default value 10 according mariadb engine
length = 10;
}
else {
length = parseLength(digits[0]);
}
}
else {
length = parseLength(decimalLiterals.get(0).getText());
}
if (decimalLiterals.size() > 1) {
scale = Integer.valueOf(decimalLiterals.get(1).getText());
}
}
if (length != null) {
columnEditor.length(length);
}
if (scale != null) {
columnEditor.scale(scale);
}
}
else if (dataTypeContext instanceof MariaDBParser.CollectionDataTypeContext) {
MariaDBParser.CollectionDataTypeContext collectionDataTypeContext = (MariaDBParser.CollectionDataTypeContext) dataTypeContext;
if (collectionDataTypeContext.charsetName() != null) {
charsetName = collectionDataTypeContext.charsetName().getText();
}
if (dataType.name().equalsIgnoreCase("SET")) {
// After DBZ-132, it will always be comma separated
int optionsSize = collectionDataTypeContext.collectionOptions().collectionOption().size();
columnEditor.length(Math.max(0, optionsSize * 2 - 1)); // number of options + number of commas
}
else {
columnEditor.length(1);
}
}
String dataTypeName = dataType.name().toUpperCase();
if (dataTypeName.equals("ENUM") || dataTypeName.equals("SET")) {
// type expression has to be set, because the value converter needs to know the enum or set options
MariaDBParser.CollectionDataTypeContext collectionDataTypeContext = (MariaDBParser.CollectionDataTypeContext) dataTypeContext;
List<String> collectionOptions = collectionDataTypeContext.collectionOptions().collectionOption().stream()
.map(AntlrDdlParser::getText)
.collect(Collectors.toList());
columnEditor.type(dataTypeName);
columnEditor.enumValues(collectionOptions);
}
else if (dataTypeName.equals("SERIAL")) {
// SERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE
columnEditor.type("BIGINT UNSIGNED");
serialColumn();
}
else {
columnEditor.type(dataTypeName);
}
int jdbcDataType = dataType.jdbcType();
columnEditor.jdbcType(jdbcDataType);
if (columnEditor.length() == -1) {
columnEditor.length((int) dataType.length());
}
if (!columnEditor.scale().isPresent() && dataType.scale() != Column.UNSET_INT_VALUE) {
columnEditor.scale(dataType.scale());
}
if (Types.NCHAR == jdbcDataType || Types.NVARCHAR == jdbcDataType) {
// NCHAR and NVARCHAR columns always uses utf8 as charset
columnEditor.charsetName("utf8");
if (Types.NCHAR == jdbcDataType && columnEditor.length() == -1) {
// Explicitly set NCHAR column size as 1 when no length specified
columnEditor.length(1);
}
}
else {
columnEditor.charsetName(charsetName);
}
}
private Integer parseLength(String lengthStr) {
Long length = Long.parseLong(lengthStr);
if (length > Integer.MAX_VALUE) {
LOGGER.warn("The length '{}' of the column `{}`.`{}` is too large to be supported, truncating it to '{}'",
length, tableEditor.tableId(), columnEditor.name(), Integer.MAX_VALUE);
length = (long) Integer.MAX_VALUE;
}
return length.intValue();
}
private void serialColumn() {
if (optionalColumn.get() == null) {
optionalColumn.set(Boolean.FALSE);
}
uniqueColumn = true;
columnEditor.autoIncremented(true);
columnEditor.generated(true);
}
}

View File

@ -1,60 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import io.debezium.connector.binlog.jdbc.BinlogSystemVariables;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
/**
* Parser listener for CREATE DATABASE and ALTER DATABASE statements.
*
* @author Chris Cranford
*/
public class CreateAndAlterDatabaseParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
private String databaseName;
public CreateAndAlterDatabaseParserListener(MariaDbAntlrDdlParser parser) {
this.parser = parser;
}
@Override
public void enterCreateDatabase(MariaDBParser.CreateDatabaseContext ctx) {
databaseName = parser.parseName(ctx.uid());
super.enterCreateDatabase(ctx);
}
@Override
public void exitCreateDatabase(MariaDBParser.CreateDatabaseContext ctx) {
parser.signalCreateDatabase(databaseName, ctx);
super.exitCreateDatabase(ctx);
}
@Override
public void enterAlterSimpleDatabase(MariaDBParser.AlterSimpleDatabaseContext ctx) {
databaseName = ctx.uid() == null ? parser.currentSchema() : parser.parseName(ctx.uid());
super.enterAlterSimpleDatabase(ctx);
}
@Override
public void enterCreateDatabaseOption(MariaDBParser.CreateDatabaseOptionContext ctx) {
String charsetName = parser.extractCharset(ctx.charsetName(), ctx.collationName());
if (ctx.charsetName() != null) {
if ("DEFAULT".equalsIgnoreCase(charsetName)) {
charsetName = parser.systemVariables().getVariable(BinlogSystemVariables.CHARSET_NAME_SERVER);
}
parser.charsetNameForDatabase().put(databaseName, charsetName);
}
// Collation is used only if the database charset was not set by charset setting
else if (ctx.charsetName() != null && !parser.charsetNameForDatabase().containsKey(charsetName)) {
parser.charsetNameForDatabase().put(databaseName, charsetName);
}
super.enterCreateDatabaseOption(ctx);
}
}

View File

@ -1,100 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import java.util.List;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.relational.ColumnEditor;
import io.debezium.relational.Table;
import io.debezium.relational.TableId;
/**
* Parser listener for CREATE TABLE statements.
*
* @author Chris Cranford
*/
public class CreateTableParserListener extends TableCommonParserListener {
public CreateTableParserListener(MariaDbAntlrDdlParser parser, List<ParseTreeListener> listeners) {
super(parser, listeners);
}
@Override
public void enterColumnCreateTable(MariaDBParser.ColumnCreateTableContext ctx) {
TableId tableId = parser.parseQualifiedTableId(ctx.tableName().fullId());
if (parser.databaseTables().forTable(tableId) == null) {
tableEditor = parser.databaseTables().editOrCreateTable(tableId);
super.enterColumnCreateTable(ctx);
}
}
@Override
public void exitColumnCreateTable(MariaDBParser.ColumnCreateTableContext ctx) {
parser.runIfNotNull(() -> {
// Make sure that the table's character set has been set ...
if (!tableEditor.hasDefaultCharsetName()) {
tableEditor.setDefaultCharsetName(parser.charsetForTable(tableEditor.tableId()));
}
listeners.remove(columnDefinitionListener);
columnDefinitionListener = null;
// remove column definition parser listener
final String defaultCharsetName = tableEditor.create().defaultCharsetName();
tableEditor.setColumns(tableEditor.columns().stream()
.map(
column -> {
final ColumnEditor columnEditor = column.edit();
if (columnEditor.charsetNameOfTable() == null) {
columnEditor.charsetNameOfTable(defaultCharsetName);
}
return columnEditor;
})
.map(ColumnEditor::create)
.collect(Collectors.toList()));
parser.databaseTables().overwriteTable(tableEditor.create());
parser.signalCreateTable(tableEditor.tableId(), ctx);
}, tableEditor);
super.exitColumnCreateTable(ctx);
}
@Override
public void exitCopyCreateTable(MariaDBParser.CopyCreateTableContext ctx) {
TableId tableId = parser.parseQualifiedTableId(ctx.tableName(0).fullId());
TableId originalTableId = parser.parseQualifiedTableId(ctx.tableName(1).fullId());
Table original = parser.databaseTables().forTable(originalTableId);
if (original != null) {
parser.databaseTables().overwriteTable(tableId, original.columns(), original.primaryKeyColumnNames(), original.defaultCharsetName(), original.attributes());
parser.signalCreateTable(tableId, ctx);
}
super.exitCopyCreateTable(ctx);
}
@Override
public void enterTableOptionCharset(MariaDBParser.TableOptionCharsetContext ctx) {
parser.runIfNotNull(() -> {
if (ctx.charsetName() != null) {
tableEditor.setDefaultCharsetName(parser.withoutQuotes(ctx.charsetName()));
}
}, tableEditor);
super.enterTableOptionCharset(ctx);
}
@Override
public void enterTableOptionComment(MariaDBParser.TableOptionCommentContext ctx) {
if (!parser.skipComments()) {
parser.runIfNotNull(() -> {
if (ctx.COMMENT() != null) {
tableEditor.setComment(parser.withoutQuotes(ctx.STRING_LITERAL().getText()));
}
}, tableEditor);
}
super.enterTableOptionComment(ctx);
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import static io.debezium.antlr.AntlrDdlParser.getText;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.TableEditor;
import io.debezium.relational.TableId;
import io.debezium.text.ParsingException;
/**
* Parser listener for CREATE UNIQUE INDEX statements.
*
* @author Chris Cranford
*/
public class CreateUniqueIndexParserListener extends MariaDBParserBaseListener {
private final static Logger LOG = LoggerFactory.getLogger(AlterTableParserListener.class);
private final MariaDbAntlrDdlParser parser;
public CreateUniqueIndexParserListener(MariaDbAntlrDdlParser parser) {
this.parser = parser;
}
@Override
public void enterCreateIndex(MariaDBParser.CreateIndexContext ctx) {
if (ctx.UNIQUE() != null) {
TableId tableId = parser.parseQualifiedTableId(ctx.tableName().fullId());
if (!parser.getTableFilter().isIncluded(tableId)) {
LOG.debug("{} is not monitored, no need to process unique index", tableId);
return;
}
TableEditor tableEditor = parser.databaseTables().editTable(tableId);
if (tableEditor != null) {
if (!tableEditor.hasPrimaryKey() && parser.isTableUniqueIndexIncluded(ctx.indexColumnNames(), tableEditor)) {
parser.parseUniqueIndexColumnNames(ctx.indexColumnNames(), tableEditor);
parser.databaseTables().overwriteTable(tableEditor.create());
parser.signalCreateIndex(parser.parseName(ctx.uid()), tableId, ctx);
}
}
else {
throw new ParsingException(null, "Trying to create index on non existing table " + tableId.toString() + "."
+ "Query: " + getText(ctx));
}
}
super.enterCreateIndex(ctx);
}
}

View File

@ -1,67 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import java.util.List;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.Column;
import io.debezium.relational.TableEditor;
/**
* Parser listener for CREATE VIEW statements.
*
* @author Chris Cranford
*/
public class CreateViewParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
private final List<ParseTreeListener> listeners;
private TableEditor tableEditor;
private ViewSelectedColumnsParserListener selectColumnsListener;
public CreateViewParserListener(MariaDbAntlrDdlParser parser, List<ParseTreeListener> listeners) {
this.parser = parser;
this.listeners = listeners;
}
@Override
public void enterCreateView(MariaDBParser.CreateViewContext ctx) {
if (!parser.skipViews()) {
tableEditor = parser.databaseTables().editOrCreateTable(parser.parseQualifiedTableId(ctx.fullId()));
// create new columns just with specified name for now
if (ctx.uidList() != null) {
ctx.uidList().uid().stream().map(parser::parseName).forEach(columnName -> {
tableEditor.addColumn(Column.editor().name(columnName).create());
});
}
selectColumnsListener = new ViewSelectedColumnsParserListener(tableEditor, parser);
listeners.add(selectColumnsListener);
}
super.enterCreateView(ctx);
}
@Override
public void exitCreateView(MariaDBParser.CreateViewContext ctx) {
parser.runIfNotNull(() -> {
tableEditor.addColumns(selectColumnsListener.getSelectedColumns());
// Make sure that the table's character set has been set ...
if (!tableEditor.hasDefaultCharsetName()) {
tableEditor.setDefaultCharsetName(parser.charsetForTable(tableEditor.tableId()));
}
parser.databaseTables().overwriteTable(tableEditor.create());
listeners.remove(selectColumnsListener);
}, tableEditor);
// signal view even if it was skipped
parser.signalCreateView(parser.parseQualifiedTableId(ctx.fullId()), ctx);
super.exitCreateView(ctx);
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import java.util.concurrent.atomic.AtomicReference;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser.CurrentTimestampContext;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser.DefaultValueContext;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.ColumnEditor;
/**
* Parser listener that parses default value definitions.
*
* @author Chris Cranford
*/
public class DefaultValueParserListener extends MariaDBParserBaseListener {
private final ColumnEditor columnEditor;
private final AtomicReference<Boolean> optionalColumn;
private boolean converted;
public DefaultValueParserListener(ColumnEditor columnEditor, AtomicReference<Boolean> optionalColumn) {
this.columnEditor = columnEditor;
this.optionalColumn = optionalColumn;
this.converted = false;
}
@Override
public void enterDefaultValue(DefaultValueContext ctx) {
String sign = "";
if (ctx.NULL_LITERAL() != null) {
return;
}
if (ctx.unaryOperator() != null) {
sign = ctx.unaryOperator().getText();
}
if (ctx.constant() != null) {
if (ctx.constant().stringLiteral() != null) {
if (ctx.constant().stringLiteral().COLLATE() == null) {
columnEditor.defaultValueExpression(sign + unquote(ctx.constant().stringLiteral().getText()));
}
else {
columnEditor.defaultValueExpression(
sign + unquote(ctx.constant().stringLiteral().STRING_LITERAL(0).getText()));
}
}
else if (ctx.constant().decimalLiteral() != null) {
columnEditor.defaultValueExpression(sign + ctx.constant().decimalLiteral().getText());
}
else if (ctx.constant().BIT_STRING() != null) {
columnEditor.defaultValueExpression(unquoteBinary(ctx.constant().BIT_STRING().getText()));
}
else if (ctx.constant().booleanLiteral() != null) {
columnEditor.defaultValueExpression(ctx.constant().booleanLiteral().getText());
}
else if (ctx.constant().REAL_LITERAL() != null) {
columnEditor.defaultValueExpression(ctx.constant().REAL_LITERAL().getText());
}
}
else if (ctx.currentTimestamp() != null && !ctx.currentTimestamp().isEmpty()) {
if (ctx.currentTimestamp().size() > 1 || (ctx.ON() == null && ctx.UPDATE() == null)) {
final CurrentTimestampContext currentTimestamp = ctx.currentTimestamp(0);
if (currentTimestamp.CURRENT_TIMESTAMP() != null || currentTimestamp.NOW() != null) {
columnEditor.defaultValueExpression("1970-01-01 00:00:00");
}
else {
columnEditor.defaultValueExpression(currentTimestamp.getText());
}
}
}
// Default value is calculated.
// We thus handle it as NULL.
else if (ctx.expression() != null) {
columnEditor.defaultValueExpression(null);
}
exitDefaultValue(true);
super.enterDefaultValue(ctx);
}
public void exitDefaultValue(boolean skipIfUnknownOptional) {
boolean isOptionalColumn = optionalColumn.get() != null;
if (!converted && (isOptionalColumn || !skipIfUnknownOptional)) {
if (isOptionalColumn) {
columnEditor.optional(optionalColumn.get().booleanValue());
}
converted = true;
}
}
private String unquote(String stringLiteral) {
if (stringLiteral != null && ((stringLiteral.startsWith("'") && stringLiteral.endsWith("'"))
|| (stringLiteral.startsWith("\"") && stringLiteral.endsWith("\"")))) {
return stringLiteral.substring(1, stringLiteral.length() - 1);
}
return stringLiteral;
}
private String unquoteBinary(String stringLiteral) {
return stringLiteral.substring(2, stringLiteral.length() - 1);
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
/**
* Parser listener for DROP DATABASE statements.
*
* @author Chris Cranford
*/
public class DropDatabaseParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
public DropDatabaseParserListener(MariaDbAntlrDdlParser parser) {
this.parser = parser;
}
@Override
public void enterDropDatabase(MariaDBParser.DropDatabaseContext ctx) {
String databaseName = parser.parseName(ctx.uid());
parser.databaseTables().removeTablesForDatabase(databaseName);
parser.charsetNameForDatabase().remove(databaseName);
parser.signalDropDatabase(databaseName, ctx);
super.enterDropDatabase(ctx);
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import org.antlr.v4.runtime.misc.Interval;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.TableId;
/**
* Parser listener for parsing DROP TABLE statements.
*
* @author Chris Cranford
*/
public class DropTableParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
public DropTableParserListener(MariaDbAntlrDdlParser parser) {
this.parser = parser;
}
@Override
public void enterDropTable(MariaDBParser.DropTableContext ctx) {
Interval interval = new Interval(ctx.start.getStartIndex(), ctx.tables().start.getStartIndex() - 1);
String prefix = ctx.start.getInputStream().getText(interval);
ctx.tables().tableName().forEach(tableNameContext -> {
TableId tableId = parser.parseQualifiedTableId(tableNameContext.fullId());
parser.databaseTables().removeTable(tableId);
parser.signalDropTable(tableId, prefix + tableId.toQuotedString('`')
+ (ctx.dropType != null ? " " + ctx.dropType.getText() : ""));
});
super.enterDropTable(ctx);
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
/**
* Parser listener for parsing DROP VIEW statements.
*
* @author Chris Cranford
*/
public class DropViewParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
public DropViewParserListener(MariaDbAntlrDdlParser parser) {
this.parser = parser;
}
@Override
public void enterDropView(MariaDBParser.DropViewContext ctx) {
if (!parser.skipViews()) {
ctx.fullId().stream().map(parser::parseQualifiedTableId).forEach(tableId -> {
parser.databaseTables().removeTable(tableId);
parser.signalDropView(tableId, ctx);
});
}
super.enterDropView(ctx);
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.TerminalNode;
import io.debezium.antlr.AntlrDdlParserListener;
import io.debezium.antlr.ProxyParseTreeListenerUtil;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.text.ParsingException;
/**
* Parser listener for MariaDB column definition queries.<p></p>
*
* Its purpose is to delegate events to defined collections of concrete parser listeners. Each
* listener handles the specified type of DDL statement.<p></p>
*
* This listener is catching all parsing exceptions and implements a skip mechanism for BEGIN ... END
* statements. No event will be delegated during skipping phase.
*
* @author Chris Cranford
*/
public class MariaDbAntlrDdlParserListener extends MariaDBParserBaseListener implements AntlrDdlParserListener {
private final List<ParseTreeListener> listeners = new CopyOnWriteArrayList<>();
private final Collection<ParsingException> errors = new ArrayList<>();
private boolean skipNodes;
private int skippedNodesCount = 0;
public MariaDbAntlrDdlParserListener(MariaDbAntlrDdlParser parser) {
listeners.add(new CreateAndAlterDatabaseParserListener(parser));
listeners.add(new DropDatabaseParserListener(parser));
listeners.add(new CreateTableParserListener(parser, listeners));
listeners.add(new AlterTableParserListener(parser, listeners));
listeners.add(new DropTableParserListener(parser));
listeners.add(new RenameTableParserListener(parser));
listeners.add(new TruncateTableParserListener(parser));
listeners.add(new CreateViewParserListener(parser, listeners));
listeners.add(new AlterViewParserListener(parser, listeners));
listeners.add(new DropViewParserListener(parser));
listeners.add(new CreateUniqueIndexParserListener(parser));
listeners.add(new SetStatementParserListener(parser));
listeners.add(new UseStatementParserListener(parser));
}
@Override
public Collection<ParsingException> getErrors() {
return errors;
}
@Override
public void enterEveryRule(ParserRuleContext ctx) {
if (skipNodes) {
skippedNodesCount++;
}
else {
ProxyParseTreeListenerUtil.delegateEnterRule(ctx, listeners, errors);
}
}
@Override
public void exitEveryRule(ParserRuleContext ctx) {
if (skipNodes) {
if (skippedNodesCount == 0) {
// back in the node where skipping started
skipNodes = false;
}
else {
// going up in a tree, means decreasing a number of skipped nodes
skippedNodesCount--;
}
}
else {
ProxyParseTreeListenerUtil.delegateExitRule(ctx, listeners, errors);
}
}
@Override
public void visitErrorNode(ErrorNode node) {
ProxyParseTreeListenerUtil.visitErrorNode(node, listeners, errors);
}
@Override
public void visitTerminal(TerminalNode node) {
ProxyParseTreeListenerUtil.visitTerminal(node, listeners, errors);
}
@Override
public void enterRoutineBody(MariaDBParser.RoutineBodyContext ctx) {
// this is a grammar rule for BEGIN ... END part of statements. Skip it.
skipNodes = true;
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.TableId;
/**
* Parser listener for parsing RENAME TABLE statements.
*
* @author Chris Cranford
*/
public class RenameTableParserListener extends MariaDBParserBaseListener {
private final static Logger LOG = LoggerFactory.getLogger(RenameTableParserListener.class);
private final MariaDbAntlrDdlParser parser;
public RenameTableParserListener(MariaDbAntlrDdlParser parser) {
this.parser = parser;
}
@Override
public void enterRenameTableClause(MariaDBParser.RenameTableClauseContext ctx) {
TableId oldTable = parser.parseQualifiedTableId(ctx.tableName(0).fullId());
TableId newTable = parser.parseQualifiedTableId(ctx.tableName(1).fullId());
if (parser.getTableFilter().isIncluded(oldTable) && !parser.getTableFilter().isIncluded(newTable)) {
LOG.warn("Renaming included table {} to non-included table {}, this can lead to schema inconsistency", oldTable, newTable);
}
else if (!parser.getTableFilter().isIncluded(oldTable) && parser.getTableFilter().isIncluded(newTable)) {
LOG.warn("Renaming non-included table {} to included table {}, this can lead to schema inconsistency", oldTable, newTable);
}
parser.databaseTables().renameTable(oldTable, newTable);
parser.signalAlterTable(newTable, oldTable, ctx);
super.enterRenameTableClause(ctx);
}
}

View File

@ -1,116 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import io.debezium.connector.binlog.jdbc.BinlogSystemVariables;
import io.debezium.connector.binlog.jdbc.BinlogSystemVariables.BinlogScope;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
/**
* Parser listener for parsing SET statements, which define system variables.
*
* @author Chris Cranford
*/
public class SetStatementParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
public SetStatementParserListener(MariaDbAntlrDdlParser parser) {
this.parser = parser;
}
@Override
public void enterSetVariable(MariaDBParser.SetVariableContext ctx) {
// If you set multiple system variables, the most recent GLOBAL or SESSION modifier in the statement
// is used for following assignments that have no modifier specified.
BinlogScope scope = null;
for (int i = 0; i < ctx.variableClause().size(); i++) {
MariaDBParser.VariableClauseContext variableClauseContext = ctx.variableClause(i);
String variableName;
if (variableClauseContext.uid() == null) {
if (variableClauseContext.GLOBAL_ID() == null) {
// that mean that user variable is set, so do nothing with it
continue;
}
String variableIdentifier = variableClauseContext.GLOBAL_ID().getText();
if (variableIdentifier.startsWith("@@global.")) {
scope = BinlogScope.GLOBAL;
variableName = variableIdentifier.substring("@@global.".length());
}
else if (variableIdentifier.startsWith("@@session.")) {
scope = BinlogScope.SESSION;
variableName = variableIdentifier.substring("@@session.".length());
}
else if (variableIdentifier.startsWith("@@local.")) {
scope = BinlogScope.LOCAL;
variableName = variableIdentifier.substring("@@local.".length());
}
else {
scope = BinlogScope.SESSION;
variableName = variableIdentifier.substring("@@".length());
}
}
else {
if (variableClauseContext.GLOBAL() != null) {
scope = BinlogScope.GLOBAL;
}
else if (variableClauseContext.SESSION() != null) {
scope = BinlogScope.SESSION;
}
else if (variableClauseContext.LOCAL() != null) {
scope = BinlogScope.LOCAL;
}
variableName = parser.parseName(variableClauseContext.uid());
}
String value = parser.withoutQuotes(ctx.expression(i));
parser.systemVariables().setVariable(scope, variableName, value);
// If this is setting 'character_set_database', then we need to record the character set for
// the given database ...
if (BinlogSystemVariables.CHARSET_NAME_DATABASE.equalsIgnoreCase(variableName)) {
String currentDatabaseName = parser.currentSchema();
if (currentDatabaseName != null) {
parser.charsetNameForDatabase().put(currentDatabaseName, value);
}
}
// Signal that the variable was set ...
parser.signalSetVariable(variableName, value, i, ctx);
}
super.enterSetVariable(ctx);
}
@Override
public void enterSetCharset(MariaDBParser.SetCharsetContext ctx) {
String charsetName = ctx.charsetName() != null ? parser.withoutQuotes(ctx.charsetName()) : parser.currentDatabaseCharset();
// Sets variables according to documentation at
// https://mariadb.com/kb/en/set-character-set/
// Using default scope for these variables, because this type of set statement you cannot specify
// the scope manually
parser.systemVariables().setVariable(BinlogScope.SESSION, BinlogSystemVariables.CHARSET_NAME_CLIENT, charsetName);
parser.systemVariables().setVariable(BinlogScope.SESSION, BinlogSystemVariables.CHARSET_NAME_RESULT, charsetName);
parser.systemVariables().setVariable(BinlogScope.SESSION, BinlogSystemVariables.CHARSET_NAME_CONNECTION,
parser.systemVariables().getVariable(BinlogSystemVariables.CHARSET_NAME_DATABASE));
super.enterSetCharset(ctx);
}
@Override
public void enterSetNames(MariaDBParser.SetNamesContext ctx) {
String charsetName = ctx.charsetName() != null ? parser.withoutQuotes(ctx.charsetName()) : parser.currentDatabaseCharset();
// Sets variables according to documentation at
// https://mariadb.com/kb/en/set-names/
// Using default scope for these variables, because this type of set statement you cannot specify
// the scope manually
parser.systemVariables().setVariable(BinlogScope.SESSION, BinlogSystemVariables.CHARSET_NAME_CLIENT, charsetName);
parser.systemVariables().setVariable(BinlogScope.SESSION, BinlogSystemVariables.CHARSET_NAME_RESULT, charsetName);
parser.systemVariables().setVariable(BinlogScope.SESSION, BinlogSystemVariables.CHARSET_NAME_CONNECTION, charsetName);
super.enterSetNames(ctx);
}
}

View File

@ -1,79 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import java.util.List;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.Column;
import io.debezium.relational.ColumnEditor;
import io.debezium.relational.TableEditor;
/**
* Parser listener that parses CREATE TABLE and ALTER TABLE common statements.
*
* @author Chris Cranford
*/
public class TableCommonParserListener extends MariaDBParserBaseListener {
protected final MariaDbAntlrDdlParser parser;
protected final List<ParseTreeListener> listeners;
protected TableEditor tableEditor;
protected ColumnDefinitionParserListener columnDefinitionListener;
public TableCommonParserListener(MariaDbAntlrDdlParser parser, List<ParseTreeListener> listeners) {
this.parser = parser;
this.listeners = listeners;
}
@Override
public void enterColumnDeclaration(MariaDBParser.ColumnDeclarationContext ctx) {
parser.runIfNotNull(() -> {
MariaDBParser.UidContext fullColumnNameContext = ctx.uid();
String columnName = parser.parseName(fullColumnNameContext);
ColumnEditor columnEditor = Column.editor().name(columnName);
if (columnDefinitionListener == null) {
columnDefinitionListener = new ColumnDefinitionParserListener(tableEditor, columnEditor, parser, listeners);
listeners.add(columnDefinitionListener);
}
else {
columnDefinitionListener.setColumnEditor(columnEditor);
}
}, tableEditor);
super.enterColumnDeclaration(ctx);
}
@Override
public void exitColumnDeclaration(MariaDBParser.ColumnDeclarationContext ctx) {
parser.runIfNotNull(() -> {
tableEditor.addColumn(columnDefinitionListener.getColumn());
}, tableEditor, columnDefinitionListener);
super.exitColumnDeclaration(ctx);
}
@Override
public void enterPrimaryKeyTableConstraint(MariaDBParser.PrimaryKeyTableConstraintContext ctx) {
parser.runIfNotNull(() -> {
parser.parsePrimaryIndexColumnNames(ctx.indexColumnNames(), tableEditor);
}, tableEditor);
super.enterPrimaryKeyTableConstraint(ctx);
}
@Override
public void enterUniqueKeyTableConstraint(MariaDBParser.UniqueKeyTableConstraintContext ctx) {
parser.runIfNotNull(() -> {
if (!tableEditor.hasPrimaryKey() && parser.isTableUniqueIndexIncluded(ctx.indexColumnNames(), tableEditor)) {
parser.parseUniqueIndexColumnNames(ctx.indexColumnNames(), tableEditor);
}
}, tableEditor);
super.enterUniqueKeyTableConstraint(ctx);
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.TableId;
/**
* Parser listener that parses TRUNCATE TABLE statements.
*
* @author Chris Cranford
*/
public class TruncateTableParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
public TruncateTableParserListener(MariaDbAntlrDdlParser parser) {
this.parser = parser;
}
@Override
public void enterTruncateTable(MariaDBParser.TruncateTableContext ctx) {
TableId tableId = parser.parseQualifiedTableId(ctx.tableName().fullId());
// Be aware the legacy parser is not signaling truncate events
parser.signalTruncateTable(tableId, ctx);
super.enterTruncateTable(ctx);
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import io.debezium.connector.binlog.jdbc.BinlogSystemVariables;
import io.debezium.connector.binlog.jdbc.BinlogSystemVariables.BinlogScope;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
/**
* Parser listener that parses USE statements.<p></p>
*
* USE statements alter the current database/catalog for all changes that come thereafter.
*
* @author Chris Cranford
*/
public class UseStatementParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
public UseStatementParserListener(MariaDbAntlrDdlParser parser) {
this.parser = parser;
}
@Override
public void enterUseStatement(MariaDBParser.UseStatementContext ctx) {
String dbName = parser.parseName(ctx.uid());
parser.setCurrentSchema(dbName);
// Every time the database switches to a different database, it sets the "character_set_database" and
// "collation_database" system variables. We replicate that behavior here (or the variable we care about)
// so that these variables are always right for the current database.
String charsetForDb = parser.charsetNameForDatabase().get(dbName);
parser.systemVariables().setVariable(BinlogScope.SESSION, BinlogSystemVariables.CHARSET_NAME_DATABASE, charsetForDb);
// Signal that the variable was set ...
parser.signalUseDatabase(ctx);
super.enterUseStatement(ctx);
}
}

View File

@ -1,182 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.antlr.listener;
import static io.debezium.relational.ddl.AbstractDdlParser.withoutQuotes;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParser;
import io.debezium.ddl.parser.mariadb.generated.MariaDBParserBaseListener;
import io.debezium.relational.Column;
import io.debezium.relational.Table;
import io.debezium.relational.TableEditor;
import io.debezium.relational.TableId;
/**
* Parser listener that parses SELECT statements used for definitions of VIEWs.
*
* @author Chris Cranford
*/
public class ViewSelectedColumnsParserListener extends MariaDBParserBaseListener {
private final MariaDbAntlrDdlParser parser;
private final TableEditor tableEditor;
private TableEditor selectTableEditor;
private Map<TableId, Table> tableByAlias = new HashMap<>();
public ViewSelectedColumnsParserListener(TableEditor tableEditor, MariaDbAntlrDdlParser parser) {
this.tableEditor = tableEditor;
this.parser = parser;
}
public List<Column> getSelectedColumns() {
return selectTableEditor.columns();
}
@Override
public void exitQuerySpecification(MariaDBParser.QuerySpecificationContext ctx) {
if (ctx.fromClause() != null) {
parseQuerySpecification(ctx.selectElements());
}
super.exitQuerySpecification(ctx);
}
@Override
public void exitQuerySpecificationNointo(MariaDBParser.QuerySpecificationNointoContext ctx) {
if (ctx.fromClause() != null) {
parseQuerySpecification(ctx.selectElements());
}
super.exitQuerySpecificationNointo(ctx);
}
@Override
public void exitAtomTableItem(MariaDBParser.AtomTableItemContext ctx) {
parser.runIfNotNull(() -> {
parseAtomTableItem(ctx, tableByAlias);
}, tableEditor);
super.exitAtomTableItem(ctx);
}
@Override
public void exitSubqueryTableItem(MariaDBParser.SubqueryTableItemContext ctx) {
parser.runIfNotNull(() -> {
// parsing subselect
String tableAlias = parser.parseName(ctx.uid());
TableId aliasTableId = parser.resolveTableId(parser.currentSchema(), tableAlias);
selectTableEditor.tableId(aliasTableId);
tableByAlias.put(aliasTableId, selectTableEditor.create());
}, tableEditor);
super.exitSubqueryTableItem(ctx);
}
private void parseQuerySpecification(MariaDBParser.SelectElementsContext selectElementsContext) {
parser.runIfNotNull(() -> {
selectTableEditor = parseSelectElements(selectElementsContext);
}, tableEditor);
}
private void parseAtomTableItem(MariaDBParser.TableSourceItemContext ctx, Map<TableId, Table> tableByAlias) {
if (ctx instanceof MariaDBParser.AtomTableItemContext) {
MariaDBParser.AtomTableItemContext atomTableItemContext = (MariaDBParser.AtomTableItemContext) ctx;
TableId tableId = parser.parseQualifiedTableId(atomTableItemContext.tableName().fullId());
Table table = tableByAlias.get(tableId);
if (table == null) {
table = parser.databaseTables().forTable(tableId);
}
if (atomTableItemContext.alias != null) {
TableId aliasTableId = parser.resolveTableId(tableId.catalog(), parser.parseName(atomTableItemContext.alias));
tableByAlias.put(aliasTableId, table);
}
else {
tableByAlias.put(tableId, table);
}
}
}
private TableEditor parseSelectElements(MariaDBParser.SelectElementsContext ctx) {
TableEditor table = Table.editor();
if (ctx.star != null) {
tableByAlias.keySet().forEach(tableId -> {
table.addColumns(tableByAlias.get(tableId).columns());
});
}
else {
ctx.selectElement().forEach(selectElementContext -> {
if (selectElementContext instanceof MariaDBParser.SelectStarElementContext) {
TableId tableId = parser.parseQualifiedTableId(((MariaDBParser.SelectStarElementContext) selectElementContext).fullId());
Table selectedTable = tableByAlias.get(tableId);
table.addColumns(selectedTable.columns());
}
else if (selectElementContext instanceof MariaDBParser.SelectColumnElementContext) {
MariaDBParser.SelectColumnElementContext selectColumnElementContext = (MariaDBParser.SelectColumnElementContext) selectElementContext;
MariaDBParser.FullColumnNameContext fullColumnNameContext = selectColumnElementContext.fullColumnName();
String schemaName = parser.currentSchema();
String tableName = null;
String columnName;
columnName = parser.parseName(fullColumnNameContext.uid());
if (fullColumnNameContext.dottedId(0) != null) {
// shift by 1
tableName = columnName;
if (fullColumnNameContext.dottedId(1) != null) {
// shift by 2
// final look of fullColumnName e.q. inventory.Persons.FirstName
schemaName = tableName;
tableName = withoutQuotes(fullColumnNameContext.dottedId(0).getText().substring(1));
columnName = withoutQuotes(fullColumnNameContext.dottedId(1).getText().substring(1));
}
else {
// final look of fullColumnName e.g. Persons.FirstName
columnName = withoutQuotes(fullColumnNameContext.dottedId(0).getText().substring(1));
}
}
String alias = columnName;
if (selectColumnElementContext.uid() != null) {
alias = parser.parseName(selectColumnElementContext.uid());
}
if (tableName != null) {
Table selectedTable = tableByAlias.get(parser.resolveTableId(schemaName, tableName));
addColumnFromTable(table, columnName, alias, selectedTable);
}
else {
for (Table selectedTable : tableByAlias.values()) {
addColumnFromTable(table, columnName, alias, selectedTable);
}
}
}
});
}
tableByAlias.clear();
return table;
}
private MariaDBParser.TableSourceItemContext getTableSourceItemContext(MariaDBParser.TableSourceContext tableSourceContext) {
if (tableSourceContext instanceof MariaDBParser.TableSourceBaseContext) {
return ((MariaDBParser.TableSourceBaseContext) tableSourceContext).tableSourceItem();
}
else if (tableSourceContext instanceof MariaDBParser.TableSourceNestedContext) {
return ((MariaDBParser.TableSourceNestedContext) tableSourceContext).tableSourceItem();
}
return null;
}
private void addColumnFromTable(TableEditor table, String columnName, String newColumnName, Table selectedTable) {
for (Column column : selectedTable.columns()) {
if (column.name().equals(columnName)) {
table.addColumn(column.edit().name(newColumnName).create());
break;
}
}
}
}

View File

@ -1,211 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.charset;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.debezium.DebeziumException;
import io.debezium.connector.binlog.charset.BinlogCharsetRegistry;
/**
* A registry that stores character set mappings from {@code charset_mappings.json} for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbCharsetRegistry implements BinlogCharsetRegistry {
private static final String CHARSET_MAPPINGS = "charset_mappings.json";
private static final int MAP_SIZE = 1024;
private final List<String> collationIndexToCollationName = new ArrayList<>(Collections.nCopies(MAP_SIZE, null));
private final Map<Integer, CharacterSetMapping> collationIndexToCharacterSet = new TreeMap<>();
private final Map<String, CharacterSetMapping> characterSetNameToCharacterSet = new HashMap<>();
public MariaDbCharsetRegistry() {
loadCharacterSetMappingsFromFileResource();
}
@Override
public int getCharsetMapSize() {
return MAP_SIZE;
}
@Override
public String getCollationNameForCollationIndex(Integer collationIndex) {
String newValue = null;
if (!Objects.isNull(collationIndex) && isWithinRange(collationIndex)) {
newValue = collationIndexToCollationName.get(collationIndex);
}
return newValue;
}
@Override
public String getCharsetNameForCollationIndex(Integer collationIndex) {
String newValue = null;
if (!Objects.isNull(collationIndex)) {
CharacterSetMapping mapping = collationIndexToCharacterSet.get(collationIndex);
if (!Objects.isNull(mapping)) {
newValue = mapping.name;
}
}
return newValue;
}
@Override
public String getJavaEncodingForCharSet(String characterSetName) {
final CharacterSetMapping mapping = characterSetNameToCharacterSet.get(characterSetName);
if (!Objects.isNull(mapping)) {
return mapping.getFirstEncoding();
}
return null;
}
private void loadCharacterSetMappingsFromFileResource() {
try (InputStream stream = MariaDbCharsetRegistry.class.getClassLoader().getResourceAsStream(CHARSET_MAPPINGS)) {
final ObjectMapper mapper = new ObjectMapper();
final CharacterSetMappings mappings = mapper.readValue(stream, CharacterSetMappings.class);
loadCharacterSetMappings(mappings.characterSets);
loadCollationMappings(mappings.collations);
}
catch (Exception e) {
throw new DebeziumException("Failed to load character set mappings", e);
}
}
private void loadCharacterSetMappings(List<CharacterSetMapping> characterSetMappings) {
for (CharacterSetMapping charsetMapping : characterSetMappings) {
final String characterSetName = charsetMapping.name;
characterSetNameToCharacterSet.put(characterSetName, charsetMapping);
if (!Objects.isNull(charsetMapping.aliases)) {
for (String alias : charsetMapping.aliases) {
characterSetNameToCharacterSet.put(alias, charsetMapping);
}
}
}
}
private void loadCollationMappings(List<CollationMapping> collationMappings) {
for (CollationMapping collation : collationMappings) {
final CharacterSetMapping mapping = characterSetNameToCharacterSet.get(collation.charSetName);
collationIndexToCollationName.set(collation.index, collation.collations.get(0));
collationIndexToCharacterSet.put(collation.index, mapping);
}
}
private static boolean isWithinRange(int value) {
return value > 0 && value < MAP_SIZE;
}
/**
* Represents the data within the file {@code charset_mappings.json}.
*/
private static class CharacterSetMappings {
List<CharacterSetMapping> characterSets;
List<CollationMapping> collations;
@JsonCreator
CharacterSetMappings(@JsonProperty("character_sets") List<CharacterSetMapping> characterSets,
@JsonProperty("collation_mappings") List<CollationMapping> collationMappings) {
this.characterSets = characterSets;
this.collations = collationMappings;
}
}
/**
* Represents a character set mapping
*/
private static class CharacterSetMapping {
private static final String UTF8 = "UTF-8";
private static final String CP1252 = "Cp1252";
String name;
int multiByteLength;
int priority;
List<String> encodings;
List<String> aliases;
String comment;
@JsonCreator
CharacterSetMapping(@JsonProperty("name") String name,
@JsonProperty("mblen") int multiByteLength,
@JsonProperty("priority") int priority,
@JsonProperty("encodings") List<String> encodings,
@JsonProperty("aliases") List<String> aliases,
@JsonProperty("comment") String comment) {
this.name = name;
this.multiByteLength = multiByteLength;
this.priority = priority;
this.encodings = new ArrayList<>();
this.aliases = Objects.isNull(aliases) ? new ArrayList<>() : aliases;
this.comment = comment;
addEncodings(encodings);
}
private String getFirstEncoding() {
return encodings.get(0);
}
private void addEncodings(List<String> encodings) {
for (String encoding : encodings) {
try {
Charset charset = Charset.forName(encoding);
addEncodingMapping(charset.name());
charset.aliases().forEach(this::addEncodingMapping);
}
catch (Exception e) {
if (multiByteLength == 1) {
addEncodingMapping(encoding);
}
}
}
if (this.encodings.isEmpty()) {
addEncodingMapping(multiByteLength > 1 ? UTF8 : CP1252);
}
}
private void addEncodingMapping(String encoding) {
final String encodingValue = encoding.toUpperCase(Locale.ENGLISH);
if (!encodings.contains(encodingValue)) {
encodings.add(encodingValue);
}
}
}
/**
* Represents a collation mapping to a set of database character sets.
*/
private static class CollationMapping {
int index;
List<String> collations;
int priority;
String charSetName;
@JsonCreator
CollationMapping(@JsonProperty("index") int index,
@JsonProperty("collations") List<String> collations,
@JsonProperty("priority") int priority,
@JsonProperty("charset") String charSetName) {
this.index = index;
this.collations = collations;
this.priority = priority;
this.charSetName = charSetName;
}
}
}

View File

@ -1,26 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.charset;
import io.debezium.config.Configuration;
import io.debezium.connector.binlog.charset.BinlogCharsetRegistry;
import io.debezium.service.spi.ServiceProvider;
import io.debezium.service.spi.ServiceRegistry;
/**
* @author Chris Cranford
*/
public class MariaDbCharsetRegistryServiceProvider implements ServiceProvider<BinlogCharsetRegistry> {
@Override
public Class<BinlogCharsetRegistry> getServiceClass() {
return BinlogCharsetRegistry.class;
}
@Override
public BinlogCharsetRegistry createService(Configuration configuration, ServiceRegistry serviceRegistry) {
return new MariaDbCharsetRegistry();
}
}

View File

@ -1,57 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.converters;
import java.util.Set;
import io.debezium.connector.AbstractSourceInfo;
import io.debezium.converters.recordandmetadata.RecordAndMetadata;
import io.debezium.converters.spi.CloudEventsMaker;
import io.debezium.converters.spi.SerializerType;
import io.debezium.util.Collect;
/**
* A {@link CloudEventsMaker} implementation for records produced by the MariaDB connector.
*
* @author Chris Cranford
*/
public class MariaDbCloudEventsMaker extends CloudEventsMaker {
static final String TABLE_NAME_KEY = "table";
static final String SERVER_ID_KEY = "server_id";
static final String GTID_KEY = "gtid";
static final String BINLOG_FILENAME_OFFSET_KEY = "file";
static final String BINLOG_POSITION_OFFSET_KEY = "pos";
static final String BINLOG_ROW_IN_EVENT_OFFSET_KEY = "row";
static final String THREAD_KEY = "thread";
static final String QUERY_KEY = "query";
static final Set<String> MARIADB_SOURCE_FIELDS = Collect.unmodifiableSet(
TABLE_NAME_KEY,
SERVER_ID_KEY,
GTID_KEY,
BINLOG_FILENAME_OFFSET_KEY,
BINLOG_POSITION_OFFSET_KEY,
BINLOG_ROW_IN_EVENT_OFFSET_KEY,
THREAD_KEY,
QUERY_KEY);
public MariaDbCloudEventsMaker(RecordAndMetadata recordAndMetadata, SerializerType contentType, String dataSchemaUriBase, String schemaName) {
super(recordAndMetadata, contentType, dataSchemaUriBase, schemaName);
}
@Override
public String ceId() {
return "name:" + sourceField(AbstractSourceInfo.SERVER_NAME_KEY)
+ ";file:" + sourceField(BINLOG_FILENAME_OFFSET_KEY)
+ ";pos:" + sourceField(BINLOG_POSITION_OFFSET_KEY);
}
@Override
public Set<String> connectorSpecificSourceFields() {
return MARIADB_SOURCE_FIELDS;
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.converters;
import io.debezium.connector.mariadb.Module;
import io.debezium.converters.recordandmetadata.RecordAndMetadata;
import io.debezium.converters.spi.CloudEventsMaker;
import io.debezium.converters.spi.CloudEventsProvider;
import io.debezium.converters.spi.SerializerType;
/**
* An implementation of {@link CloudEventsProvider} for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbCloudEventsProvider implements CloudEventsProvider {
@Override
public String getName() {
return Module.name();
}
@Override
public CloudEventsMaker createMaker(RecordAndMetadata recordAndMetadata, SerializerType contentType, String dataSchemaUriBase, String cloudEventsSchemaName) {
return new MariaDbCloudEventsMaker(recordAndMetadata, contentType, dataSchemaUriBase, cloudEventsSchemaName);
}
}

View File

@ -1,372 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.gtid;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import com.github.shyiko.mysql.binlog.MariadbGtidSet;
import com.github.shyiko.mysql.binlog.MariadbGtidSet.MariaGtid;
import io.debezium.connector.binlog.gtid.GtidSet;
import io.debezium.util.Strings;
/**
* MariaDB-specific implementation of a Global Transaction Identifier set.
*
* @author Chris Cranford
*/
public class MariaDbGtidSet implements GtidSet {
private Map<MariaDbGtidStreamId, MariaDbStreamSet> streamSets = new TreeMap<>();
public MariaDbGtidSet(String gtidSet) {
if (gtidSet != null && !gtidSet.isEmpty()) {
String[] gtids = gtidSet.replaceAll("\n", "").split(",");
Arrays.stream(gtids).forEach(gtid -> {
if (MariadbGtidSet.isMariaGtidSet(gtid)) {
MariaDbGtid mariaGtid = MariaDbGtid.parse(gtid);
MariaDbGtidStreamId streamId = new MariaDbGtidStreamId(mariaGtid);
if (!streamSets.containsKey(streamId)) {
streamSets.put(streamId, new MariaDbStreamSet());
}
streamSets.get(streamId).add(mariaGtid);
}
});
}
}
protected MariaDbGtidSet(Map<MariaDbGtidStreamId, MariaDbStreamSet> streamSets) {
this.streamSets = streamSets;
}
@Override
public boolean isEmpty() {
return streamSets.isEmpty();
}
@Override
public boolean isContainedWithin(GtidSet other) {
if (!(other instanceof MariaDbGtidSet)) {
return false;
}
if (this.equals(other)) {
return true;
}
final MariaDbGtidSet theOther = (MariaDbGtidSet) other;
for (Map.Entry<MariaDbGtidStreamId, MariaDbStreamSet> entry : streamSets.entrySet()) {
MariaDbStreamSet thatSet = theOther.forStreamId(entry.getKey());
if (!entry.getValue().isContainedWith(thatSet)) {
return false;
}
}
return true;
}
@Override
public boolean contains(String gtid) {
if (!MariadbGtidSet.isMariaGtidSet(gtid)) {
return false;
}
final MariaDbGtid mariaGtid = MariaDbGtid.parse(gtid);
final Set<MariaDbGtid> streamSet = forGtidStream(mariaGtid);
if (streamSet == null) {
return false;
}
return streamSet.contains(mariaGtid);
}
@Override
public GtidSet retainAll(Predicate<String> sourceFilter) {
if (sourceFilter == null) {
return this;
}
Map<MariaDbGtidStreamId, MariaDbStreamSet> newSets = streamSets.entrySet()
.stream()
.filter(entry -> sourceFilter.test(entry.getKey().asSourceFilterValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return new MariaDbGtidSet(newSets);
}
@Override
public MariaDbGtidSet subtract(GtidSet other) {
if (other == null) {
return this;
}
final MariaDbGtidSet theOther = (MariaDbGtidSet) other;
Map<MariaDbGtidStreamId, MariaDbStreamSet> newSets = streamSets.entrySet()
.stream()
.filter(entry -> !entry.getValue().isContainedWith(theOther.forStreamId(entry.getKey())))
.map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue().subtract(theOther.forStreamId(entry.getKey()))))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return new MariaDbGtidSet(newSets);
}
@Override
public GtidSet with(GtidSet other) {
final MariaDbGtidSet theOther = (MariaDbGtidSet) other;
if (theOther == null || theOther.streamSets.isEmpty()) {
return this;
}
final Map<MariaDbGtidStreamId, MariaDbStreamSet> newSet = new HashMap<>();
newSet.putAll(streamSets);
newSet.putAll(theOther.streamSets);
return new MariaDbGtidSet(newSet);
}
public boolean isKnown(MariaDbGtid gtid) {
final MariaDbStreamSet streamSet = forGtidStream(gtid);
if (streamSet == null) {
return false;
}
return streamSet.hasSequence(gtid.getSequence());
}
public MariaDbStreamSet forGtidStream(MariaDbGtid gtid) {
return forStreamId(new MariaDbGtidStreamId(gtid));
}
public MariaDbStreamSet forStreamId(MariaDbGtidStreamId streamId) {
return streamSets.get(streamId);
}
public static MariaDbGtid parse(String gtid) {
if (Strings.isNullOrBlank(gtid)) {
throw new IllegalStateException("Cannot parse empty GTID");
}
return MariaDbGtid.parse(gtid);
}
@Override
public boolean equals(Object value) {
if (this == value) {
return true;
}
if (value == null || getClass() != value.getClass()) {
return false;
}
MariaDbGtidSet that = (MariaDbGtidSet) value;
return Objects.equals(streamSets, that.streamSets);
}
@Override
public int hashCode() {
return Objects.hash(streamSets);
}
@Override
public String toString() {
return streamSets.values().stream().map(MariaDbStreamSet::toString).collect(Collectors.joining(","));
}
/**
* Represents a MariaDB stream, which is a {@code domain-server} tuple.
*/
public static class MariaDbGtidStreamId implements Comparable<MariaDbGtidStreamId> {
private final long domainId;
private final long serverId;
public MariaDbGtidStreamId(long domainId, long serverId) {
this.domainId = domainId;
this.serverId = serverId;
}
public MariaDbGtidStreamId(MariaDbGtid gtid) {
this(gtid.getDomainId(), gtid.getServerId());
}
public long getDomainId() {
return domainId;
}
public long getServerId() {
return serverId;
}
public String asSourceFilterValue() {
return String.format("%d-%d", domainId, serverId);
}
public boolean isSameDomainAndServer(MariaGtid gtid) {
return gtid.getDomainId() == domainId && gtid.getServerId() == serverId;
}
@Override
public boolean equals(Object value) {
if (this == value) {
return true;
}
if (value == null || getClass() != value.getClass()) {
return false;
}
MariaDbGtidStreamId that = (MariaDbGtidStreamId) value;
return domainId == that.domainId && serverId == that.serverId;
}
@Override
public int hashCode() {
return Objects.hash(domainId, serverId);
}
@Override
public int compareTo(MariaDbGtidStreamId other) {
final int domainComparison = Long.compare(domainId, other.domainId);
if (domainComparison == 0) {
return Long.compare(serverId, other.serverId);
}
return domainComparison;
}
@Override
public String toString() {
return "MariaDbGtidStreamId{" +
"domainId=" + domainId +
", serverId=" + serverId +
'}';
}
}
/**
* Represents a stream set, which are global transaction identifiers that belong to the same domain
* and to the same server identifiers.
*/
public static class MariaDbStreamSet extends TreeSet<MariaDbGtid> {
public boolean hasSequence(long sequence) {
for (MariaDbGtid gtid : this) {
if (gtid.getSequence() == sequence) {
return true;
}
}
return false;
}
@SuppressWarnings("all")
public boolean isContainedWith(MariaDbStreamSet other) {
if (other == null) {
return false;
}
if (other.containsAll(this)) {
return true;
}
return isAllBefore(other);
}
public boolean isAllBefore(MariaDbStreamSet other) {
final Long otherMinSequence = other.stream().mapToLong(MariaDbGtid::getSequence).min().getAsLong();
final Long minSequence = stream().mapToLong(MariaDbGtid::getSequence).min().getAsLong();
return minSequence <= otherMinSequence;
}
public MariaDbStreamSet subtract(MariaDbStreamSet other) {
if (other == null) {
return this;
}
final MariaDbStreamSet streamSet = new MariaDbStreamSet();
streamSet.addAll(stream().filter(gtid -> !other.contains(gtid)).collect(Collectors.toSet()));
return streamSet;
}
public MariaDbStreamSet asBeginning() {
MariaDbStreamSet newSet = new MariaDbStreamSet();
if (!isEmpty()) {
newSet.add(newSet.first());
}
return newSet;
}
@Override
public String toString() {
return stream().map(MariaDbGtid::toString).collect(Collectors.joining(","));
}
}
/**
* Represents a logical MariaDB global transaction identifier.
*/
public static class MariaDbGtid implements Comparable<MariaDbGtid> {
private final long domainId;
private final long serverId;
private final long sequence;
public MariaDbGtid(MariaGtid gtid) {
this.domainId = gtid.getDomainId();
this.serverId = gtid.getServerId();
this.sequence = gtid.getSequence();
}
public long getDomainId() {
return domainId;
}
public long getServerId() {
return serverId;
}
public long getSequence() {
return sequence;
}
public static MariaDbGtid parse(String gtid) {
return new MariaDbGtid(MariaGtid.parse(gtid));
}
@Override
public boolean equals(Object value) {
if (this == value) {
return true;
}
if (value == null || getClass() != value.getClass()) {
return false;
}
MariaDbGtid that = (MariaDbGtid) value;
return domainId == that.domainId && serverId == that.serverId && sequence == that.sequence;
}
@Override
public int hashCode() {
return Objects.hash(domainId, serverId, sequence);
}
@Override
public int compareTo(MariaDbGtid other) {
final int domainComparison = Long.compare(domainId, other.domainId);
if (domainComparison == 0) {
final int serverComparison = Long.compare(serverId, other.serverId);
if (serverComparison == 0) {
return Long.compare(sequence, other.sequence);
}
return serverComparison;
}
return domainComparison;
}
@Override
public String toString() {
return domainId + "-" + serverId + "-" + sequence;
}
}
}

View File

@ -1,21 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.gtid;
import io.debezium.connector.binlog.gtid.GtidSet;
import io.debezium.connector.binlog.gtid.GtidSetFactory;
/**
* MariaDB-specific implementation of the {@link GtidSetFactory} for creating {@link GtidSet}s.
*
* @author Chris Cranford
*/
public class MariaDbGtidSetFactory implements GtidSetFactory {
@Override
public GtidSet createGtidSet(String gtid) {
return new MariaDbGtidSet(gtid);
}
}

View File

@ -1,22 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.history;
import java.util.function.Predicate;
import io.debezium.connector.binlog.gtid.GtidSetFactory;
import io.debezium.connector.binlog.history.BinlogHistoryRecordComparator;
/**
* Schema history record comparator implementation for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbHistoryRecordComparator extends BinlogHistoryRecordComparator {
public MariaDbHistoryRecordComparator(Predicate<String> gtidSourceFilter, GtidSetFactory gtidSetFactory) {
super(gtidSourceFilter, gtidSetFactory);
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.jdbc;
import java.sql.SQLException;
import java.util.function.Predicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.debezium.DebeziumException;
import io.debezium.connector.binlog.gtid.GtidSet;
import io.debezium.connector.binlog.jdbc.BinlogConnectorConnection;
import io.debezium.connector.binlog.jdbc.BinlogFieldReader;
import io.debezium.connector.binlog.jdbc.ConnectionConfiguration;
import io.debezium.connector.mariadb.gtid.MariaDbGtidSet;
import io.debezium.connector.mariadb.gtid.MariaDbGtidSet.MariaDbGtid;
/**
* A concrete implementation of {@link BinlogConnectorConnection} for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbConnection extends BinlogConnectorConnection {
private static final Logger LOGGER = LoggerFactory.getLogger(MariaDbConnection.class);
public MariaDbConnection(ConnectionConfiguration configuration, BinlogFieldReader fieldReader) {
super(configuration, fieldReader);
}
@Override
public boolean isGtidModeEnabled() {
// Always has GTID enabled.
// GTID_STRICT_MODE can be enabled or disabled.
return true;
}
@Override
public GtidSet knownGtidSet() {
// MariaDB does not store the executed GTID details in the SHOW MASTER STATUS output like MySQL;
// however, instead makes this information available as a variable. The GTID_BINLOG_POS gives
// the current GTID position of the binary log and can therefore be considered the equivalent to
// MySQL's executed GTID set.
try {
return queryAndMap("SHOW GLOBAL VARIABLES LIKE 'GTID_BINLOG_POS'", rs -> {
if (rs.next()) {
return new MariaDbGtidSet(rs.getString(2));
}
return new MariaDbGtidSet("");
});
}
catch (SQLException e) {
throw new DebeziumException("Unexpected error while looking at GTID_BINLOG_POS: ", e);
}
}
@Override
public GtidSet subtractGtidSet(GtidSet set1, GtidSet set2) {
return set1.subtract(set2);
}
@Override
public GtidSet purgedGtidSet() {
// The MariaDB community mentioned we could get the purged GTID values from the GTID_LIST_EVENT; however,
// this value is only available after we connect and would require a temporary binlog connection to get
// the data, so for now simply returning an empty set until we split the code base.
return new MariaDbGtidSet("");
}
@Override
public GtidSet filterGtidSet(Predicate<String> gtidSourceFilter, String offsetGtids, GtidSet availableServerGtidSet, GtidSet purgedServerGtidSet) {
String gtidStr = offsetGtids;
if (gtidStr == null) {
return null;
}
LOGGER.info("Attempting to generate a filtered GTID set");
LOGGER.info("GTID set from previous recorded offset: {}", gtidStr);
MariaDbGtidSet filteredGtidSet = new MariaDbGtidSet(gtidStr);
if (gtidSourceFilter != null) {
filteredGtidSet = (MariaDbGtidSet) filteredGtidSet.retainAll(gtidSourceFilter);
LOGGER.info("GTID set after applying GTID source includes/excludes to previous recorded offset: {}", filteredGtidSet);
}
LOGGER.info("GTID set available on server: {}", availableServerGtidSet);
final MariaDbGtidSet knownGtidSet = filteredGtidSet;
LOGGER.info("Using first available positions for new GTID channels");
final GtidSet relevantAvailableServerGtidSet = (gtidSourceFilter != null) ? availableServerGtidSet.retainAll(gtidSourceFilter) : availableServerGtidSet;
LOGGER.info("Relevant GTID set available on server: {}", relevantAvailableServerGtidSet);
GtidSet mergedGtidSet = relevantAvailableServerGtidSet
.retainAll(serverId -> {
// ServerId in this context is "<domain-id>-<server-id>"
final MariaDbGtid compliantGtid = MariaDbGtid.parse(serverId + "-0");
return knownGtidSet.forGtidStream(compliantGtid) != null;
})
.with(purgedServerGtidSet)
.with(filteredGtidSet);
LOGGER.info("Final merged GTID set to use when connecting to MariaDB: {}", mergedGtidSet);
return mergedGtidSet;
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.jdbc;
import io.debezium.config.Configuration;
import io.debezium.connector.binlog.jdbc.BinlogConnectionConfiguration;
import io.debezium.jdbc.JdbcConnection;
import io.debezium.util.Strings;
/**
* @author Chris Cranford
*/
public class MariaDbConnectionConfiguration extends BinlogConnectionConfiguration {
private static final String JDBC_PROPERTY_MARIADB_TIME_ZONE = "timezone";
private static final String URL_PATTERN = "jdbc:mariadb://${hostname}:${port}/?useInformationSchema=true&nullCatalogMeansCurrent=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=CONVERT_TO_NULL&connectTimeout=${connectTimeout}";
public MariaDbConnectionConfiguration(Configuration configuration) {
super(configuration);
}
@Override
protected String getConnectionTimeZonePropertyName() {
return JDBC_PROPERTY_MARIADB_TIME_ZONE;
}
@Override
protected String resolveConnectionTimeZone(Configuration configuration) {
// Debezium expects timezone data delivered in server timezone by default.
return Strings.defaultIfBlank(configuration.getString(JDBC_PROPERTY_MARIADB_TIME_ZONE), "auto");
}
@Override
protected JdbcConnection.ConnectionFactory createFactory(Configuration configuration) {
return JdbcConnection.patternBasedFactory(URL_PATTERN);
}
@Override
public String getUrlPattern() {
return URL_PATTERN;
}
}

View File

@ -1,17 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.jdbc;
import io.debezium.connector.binlog.jdbc.BinlogDefaultValueConverter;
/**
* @author Chris Cranford
*/
public class MariaDbDefaultValueConverter extends BinlogDefaultValueConverter {
public MariaDbDefaultValueConverter(MariaDbValueConverters valueConverter) {
super(valueConverter);
}
}

View File

@ -1,56 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Objects;
import io.debezium.connector.binlog.jdbc.BinlogFieldReader;
import io.debezium.connector.mariadb.MariaDbConnectorConfig;
import io.debezium.relational.Column;
import io.debezium.relational.Table;
/**
* A {@link BinlogFieldReader} implementation for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbFieldReader extends BinlogFieldReader {
public MariaDbFieldReader(MariaDbConnectorConfig connectorConfig) {
super(connectorConfig);
}
@Override
protected String getCharacterSet(Column column) {
return getCharsetRegistry().getJavaEncodingForCharSet(column.charsetName());
}
@Override
protected Object readTimeField(ResultSet rs, int columnIndex, Column column, Table table) throws SQLException {
final String value = rs.getString(columnIndex);
return Objects.isNull(value) ? null : MariaDbValueConverters.stringToDuration(value);
}
@Override
protected Object readDateField(ResultSet rs, int columnIndex, Column column, Table table) throws SQLException {
final String value = rs.getString(columnIndex);
return Objects.isNull(value) ? null : MariaDbValueConverters.stringToLocalDate(value, column, table);
}
@Override
protected Object readTimestampField(ResultSet rs, int columnIndex, Column column, Table table) throws SQLException {
final String value = rs.getString(columnIndex);
if (Objects.isNull(value)) {
return null;
}
return MariaDbValueConverters.containsZeroValuesInDatePart(value, column, table)
? null
: rs.getTimestamp(columnIndex, Calendar.getInstance());
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.jdbc;
import java.time.temporal.TemporalAdjuster;
import java.util.List;
import io.debezium.annotation.Immutable;
import io.debezium.config.CommonConnectorConfig.BinaryHandlingMode;
import io.debezium.config.CommonConnectorConfig.EventConvertingFailureHandlingMode;
import io.debezium.connector.binlog.jdbc.BinlogValueConverters;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.jdbc.TemporalPrecisionMode;
import io.debezium.relational.Column;
import io.debezium.service.spi.ServiceRegistry;
/**
* MariaDB specific converter handlers for JDBC values.<p></p>
*
* This class uses UTC for the default time zone when converting values without timezone details to values that
* require timezones. This is because MariaDB {@code TIMESTAMP} values are always stored in UTC, unlike types
* like {@code DATETIME}, and aare replicated as such. Meanwhile, the Binlog Client will deserialize these as
* {@link java.sql.Timestamp} which have no timezone; therefore, are presumed to be UTC.<p></p>
*
* If a column is {@link java.sql.Types#TIMESTAMP_WITH_TIMEZONE}, the converters will need to convert the value
* from a {@link java.sql.Timestamp} to an {@link java.time.OffsetDateTime} using the default time zone, which
* is always UTC.
*
* @author Chris Cranford
*/
@Immutable
public class MariaDbValueConverters extends BinlogValueConverters {
/**
* Create a new instance of the value converters that always uses UTC for the default time zone when
* converting values without timezone information to values that require timezones.
*
* @param decimalMode how {@code DECIMAL} and {@code NUMERIC} values are treated; can be null if {@link DecimalMode#PRECISE} is used
* @param temporalPrecisionMode temporal precision mode
* @param bigIntUnsignedMode how {@code BIGINT UNSIGNED} values are treated; may be null if {@link BigIntUnsignedMode#PRECISE} is used.
* @param binaryHandlingMode how binary columns should be treated
* @param adjuster a temporal adjuster to make a database specific time before conversion
* @param eventConvertingFailureHandlingMode how to handle conversion failures
* @param serviceRegistry the service registry, should not be {@code null}
*/
public MariaDbValueConverters(DecimalMode decimalMode,
TemporalPrecisionMode temporalPrecisionMode,
BigIntUnsignedMode bigIntUnsignedMode,
BinaryHandlingMode binaryHandlingMode,
TemporalAdjuster adjuster,
EventConvertingFailureHandlingMode eventConvertingFailureHandlingMode,
ServiceRegistry serviceRegistry) {
super(decimalMode, temporalPrecisionMode, bigIntUnsignedMode, binaryHandlingMode, adjuster, eventConvertingFailureHandlingMode, serviceRegistry);
}
@Override
protected List<String> extractEnumAndSetOptions(Column column) {
return MariaDbAntlrDdlParser.extractEnumAndSetOptions(column.enumValues());
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.metadata;
import io.debezium.config.Field;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.connector.mariadb.MariaDbConnectorConfig;
import io.debezium.connector.mariadb.Module;
import io.debezium.metadata.ConnectorDescriptor;
import io.debezium.metadata.ConnectorMetadata;
/**
* @author Chris Cranford
*/
public class MariaDbConnectorMetadata implements ConnectorMetadata {
@Override
public ConnectorDescriptor getConnectorDescriptor() {
return new ConnectorDescriptor(MariaDbConnector.class.getName(), Module.version());
}
@Override
public Field.Set getConnectorFields() {
return MariaDbConnectorConfig.ALL_FIELDS;
}
}

View File

@ -1,19 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.metadata;
import io.debezium.metadata.ConnectorMetadata;
import io.debezium.metadata.ConnectorMetadataProvider;
/**
* @author Chris Cranford
*/
public class MariaDbConnectorMetadataProvider implements ConnectorMetadataProvider {
@Override
public ConnectorMetadata getConnectorMetadata() {
return new MariaDbConnectorMetadata();
}
}

View File

@ -1,50 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.metrics;
import io.debezium.connector.base.ChangeEventQueueMetrics;
import io.debezium.connector.common.CdcSourceTaskContext;
import io.debezium.connector.mariadb.MariaDbPartition;
import io.debezium.connector.mariadb.MariaDbTaskContext;
import io.debezium.pipeline.metrics.DefaultChangeEventSourceMetricsFactory;
import io.debezium.pipeline.metrics.SnapshotChangeEventSourceMetrics;
import io.debezium.pipeline.metrics.StreamingChangeEventSourceMetrics;
import io.debezium.pipeline.source.spi.EventMetadataProvider;
/**
* Implementation of the {@link io.debezium.pipeline.metrics.DefaultStreamingChangeEventSourceMetrics} for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbChangeEventSourceMetricsFactory extends DefaultChangeEventSourceMetricsFactory<MariaDbPartition> {
public MariaDbStreamingChangeEventSourceMetrics streamingMetrics;
public MariaDbChangeEventSourceMetricsFactory(MariaDbStreamingChangeEventSourceMetrics streamingMetrics) {
this.streamingMetrics = streamingMetrics;
}
@Override
public <T extends CdcSourceTaskContext> SnapshotChangeEventSourceMetrics<MariaDbPartition> getSnapshotMetrics(
T taskContext,
ChangeEventQueueMetrics changeEventQueueMetrics,
EventMetadataProvider eventMetadataProvider) {
return new MariaDbSnapshotChangeEventSourceMetrics((MariaDbTaskContext) taskContext, changeEventQueueMetrics, eventMetadataProvider);
}
@Override
public <T extends CdcSourceTaskContext> StreamingChangeEventSourceMetrics<MariaDbPartition> getStreamingMetrics(
T taskContext,
ChangeEventQueueMetrics changeEventQueueMetrics,
EventMetadataProvider eventMetadataProvider) {
return streamingMetrics;
}
@Override
public boolean connectionMetricHandledByCoordinator() {
return false;
}
}

View File

@ -1,25 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.metrics;
import io.debezium.connector.base.ChangeEventQueueMetrics;
import io.debezium.connector.binlog.metrics.BinlogSnapshotChangeEventSourceMetrics;
import io.debezium.connector.mariadb.MariaDbPartition;
import io.debezium.connector.mariadb.MariaDbTaskContext;
import io.debezium.pipeline.source.spi.EventMetadataProvider;
/**
* Tracks the snapshot metrics specific for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbSnapshotChangeEventSourceMetrics extends BinlogSnapshotChangeEventSourceMetrics<MariaDbPartition> {
public MariaDbSnapshotChangeEventSourceMetrics(MariaDbTaskContext taskContext,
ChangeEventQueueMetrics changeEventQueueMetrics,
EventMetadataProvider metadataProvider) {
super(taskContext, changeEventQueueMetrics, metadataProvider);
}
}

View File

@ -1,27 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.metrics;
import io.debezium.connector.base.ChangeEventQueueMetrics;
import io.debezium.connector.binlog.metrics.BinlogStreamingChangeEventSourceMetrics;
import io.debezium.connector.mariadb.MariaDbDatabaseSchema;
import io.debezium.connector.mariadb.MariaDbPartition;
import io.debezium.connector.mariadb.MariaDbTaskContext;
import io.debezium.pipeline.source.spi.EventMetadataProvider;
/**
* Tracks the streaming metrics specific for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbStreamingChangeEventSourceMetrics
extends BinlogStreamingChangeEventSourceMetrics<MariaDbDatabaseSchema, MariaDbPartition> {
public MariaDbStreamingChangeEventSourceMetrics(MariaDbTaskContext taskContext,
ChangeEventQueueMetrics changeEventQueueMetrics,
EventMetadataProvider eventMetadataProvider) {
super(taskContext, changeEventQueueMetrics, eventMetadataProvider);
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.rest;
import java.util.Map;
import org.apache.kafka.common.utils.AppInfoParser;
import org.apache.kafka.connect.rest.ConnectRestExtension;
import org.apache.kafka.connect.rest.ConnectRestExtensionContext;
/**
*
* @author Chris Cranford
*/
public class DebeziumMariaDbConnectRestExtension implements ConnectRestExtension {
private Map<String, ?> config;
@Override
public void register(ConnectRestExtensionContext restPluginContext) {
restPluginContext.configurable().register(new DebeziumMariaDbConnectorResource(restPluginContext.clusterState()));
}
@Override
public void close() {
}
@Override
public void configure(Map<String, ?> configs) {
this.config = configs;
}
@Override
public String version() {
return AppInfoParser.getVersion();
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.rest;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.management.MalformedObjectNameException;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.kafka.connect.health.ConnectClusterState;
import io.debezium.config.Configuration;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.connector.mariadb.Module;
import io.debezium.rest.ConnectionValidationResource;
import io.debezium.rest.FilterValidationResource;
import io.debezium.rest.MetricsResource;
import io.debezium.rest.SchemaResource;
import io.debezium.rest.model.DataCollection;
import io.debezium.rest.model.MetricsDescriptor;
/**
* A JAX-RS resource class defining endpoints of the Debezium MariaDB Connect REST extension.
*
* @author Chris Cranford
*/
@Path(DebeziumMariaDbConnectorResource.BASE_PATH)
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class DebeziumMariaDbConnectorResource
implements SchemaResource, ConnectionValidationResource, FilterValidationResource, MetricsResource {
public static final String BASE_PATH = "/debezium/mariadb";
public static final String VERSION_ENDPOINT = "/version";
private final ConnectClusterState connectClusterState;
public DebeziumMariaDbConnectorResource(ConnectClusterState connectClusterState) {
this.connectClusterState = connectClusterState;
}
@Override
public String getSchemaFilePath() {
return "/META-INF/resources/mariadb.json";
}
@Override
public MariaDbConnector getConnector() {
return new MariaDbConnector();
}
@Override
public MetricsDescriptor getMetrics(String connectorName) throws MalformedObjectNameException {
Map<String, String> connectorConfig = connectClusterState.connectorConfig(connectorName);
return queryMetrics(connectorConfig, connectorName, Module.contextName().toLowerCase(), "streaming");
}
@GET
@Path(VERSION_ENDPOINT)
public String getConnectorVersion() {
return Module.version();
}
@Override
public List<DataCollection> getMatchingCollections(Configuration configuration) {
return getConnector().getMatchingCollections(configuration).stream()
.map(tableId -> new DataCollection(tableId.catalog(), tableId.table()))
.collect(Collectors.toList());
}
}

View File

@ -1,22 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.snapshot.lock;
import java.time.Duration;
import java.util.Optional;
import io.debezium.annotation.ConnectorSpecific;
import io.debezium.connector.mariadb.MariaDbConnector;
/**
* @author Chris Cranford
*/
@ConnectorSpecific(connector = MariaDbConnector.class)
public abstract class DefaultSnapshotLock {
public Optional<String> tableLockingStatement(Duration lockTimeout, String tableId) {
return Optional.of("FLUSH TABLES WITH READ LOCK");
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.snapshot.lock;
import java.util.Map;
import io.debezium.annotation.ConnectorSpecific;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.connector.mariadb.MariaDbConnectorConfig;
import io.debezium.snapshot.spi.SnapshotLock;
/**
* @author Chris Cranford
*/
@ConnectorSpecific(connector = MariaDbConnector.class)
public class ExtendedSnapshotLock extends DefaultSnapshotLock implements SnapshotLock {
@Override
public String name() {
return MariaDbConnectorConfig.SnapshotLockingMode.EXTENDED.getValue();
}
@Override
public void configure(Map<String, ?> properties) {
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.snapshot.lock;
import java.util.Map;
import io.debezium.annotation.ConnectorSpecific;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.connector.mariadb.MariaDbConnectorConfig;
import io.debezium.snapshot.spi.SnapshotLock;
/**
* @author Chris Cranford
*/
@ConnectorSpecific(connector = MariaDbConnector.class)
public class MinimalSnapshotLock extends DefaultSnapshotLock implements SnapshotLock {
@Override
public String name() {
return MariaDbConnectorConfig.SnapshotLockingMode.MINIMAL.getValue();
}
@Override
public void configure(Map<String, ?> properties) {
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.snapshot.lock;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import io.debezium.annotation.ConnectorSpecific;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.connector.mariadb.MariaDbConnectorConfig;
import io.debezium.snapshot.spi.SnapshotLock;
/**
* @author Chris Cranford
*/
@ConnectorSpecific(connector = MariaDbConnector.class)
public class NoneSnapshotLock implements SnapshotLock {
@Override
public String name() {
return MariaDbConnectorConfig.SnapshotLockingMode.NONE.getValue();
}
@Override
public void configure(Map<String, ?> properties) {
}
@Override
public Optional<String> tableLockingStatement(Duration lockTimeout, String tableId) {
return Optional.empty();
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.snapshot.query;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import io.debezium.annotation.ConnectorSpecific;
import io.debezium.config.CommonConnectorConfig;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.snapshot.spi.SnapshotQuery;
/**
* An implementation of {@link SnapshotQuery} for MariaDB.
*
* @author Chris Cranford
*/
@ConnectorSpecific(connector = MariaDbConnector.class)
public class SelectAllSnapshotQuery implements SnapshotQuery {
@Override
public String name() {
return CommonConnectorConfig.SnapshotQueryMode.SELECT_ALL.getValue();
}
@Override
public void configure(Map<String, ?> properties) {
}
@Override
public Optional<String> snapshotQuery(String tableId, List<String> snapshotSelectColumns) {
return Optional.of(snapshotSelectColumns.stream()
.collect(Collectors.joining(", ", "SELECT ", " FROM " + tableId)));
}
}

View File

@ -1 +0,0 @@
io.debezium.connector.mariadb.converters.MariaDbCloudEventsProvider

View File

@ -1 +0,0 @@
io.debezium.connector.mariadb.metadata.MariaDbConnectorMetadataProvider

View File

@ -1,3 +0,0 @@
io.debezium.connector.mariadb.snapshot.lock.ExtendedSnapshotLock
io.debezium.connector.mariadb.snapshot.lock.MinimalSnapshotLock
io.debezium.connector.mariadb.snapshot.lock.NoneSnapshotLock

View File

@ -1 +0,0 @@
io.debezium.connector.mariadb.snapshot.query.SelectAllSnapshotQuery

View File

@ -1 +0,0 @@
io.debezium.connector.mariadb.rest.DebeziumMariaDbConnectRestExtension

View File

@ -1 +0,0 @@
io.debezium.connector.mariadb.MariaDbConnector

View File

@ -1,1971 +0,0 @@
{
"character_sets": [
{
"name": "ascii",
"mblen": 1,
"priority": 0,
"encodings": [ "US-ASCII", "ASCII" ]
},
{
"name": "big5",
"mblen": 2,
"priority": 0,
"encodings": [ "Big5" ]
},
{
"name": "gbk",
"mblen": 2,
"priority": 0,
"encodings": [ "GBK" ]
},
{
"name": "sjis",
"mblen": 2,
"priority": 0,
"encodings": [ "SHIFT_JIS", "Cp943", "WINDOWS-31J" ]
},
{
"name": "cp932",
"mblen": 2,
"priority": 1,
"encodings": [ "GB2312" ]
},
{
"name": "gb2312",
"mblen": 2,
"priority": 0,
"encodings": [ "GB2312" ]
},
{
"name": "ujis",
"mblen": 3,
"priority": 0,
"encodings": [ "EUC_JP" ]
},
{
"name": "eucjpms",
"mblen": 3,
"priority": 0,
"encodings": [ "EUC_JP_Solaris" ],
"comment": "Added in MySQL 5.0.3"
},
{
"name": "gb18030",
"mblen": 4,
"priority": 0,
"encodings": [ "GB18030" ],
"comment": "Added in MySQL 5.74"
},
{
"name": "euckr",
"mblen": 2,
"priority": 0,
"encodings": [ "EUC-KR" ]
},
{
"name": "latin1",
"mblen": 1,
"priority": 1,
"encodings": [ "Cp1252", "ISO8859_1" ]
},
{
"name": "swe7",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp1252" ]
},
{
"name": "hp8",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp1252" ]
},
{
"name": "dec8",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp1252" ]
},
{
"name": "armscii8",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp1252" ]
},
{
"name": "geostd8",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp1252" ]
},
{
"name": "latin2",
"mblen": 1,
"priority": 0,
"encodings": [ "ISO8859_2" ]
},
{
"name": "greek",
"mblen": 1,
"priority": 0,
"encodings": [ "ISO8859_7", "greek" ]
},
{
"name": "latin7",
"mblen": 1,
"priority": 0,
"encodings": [ "ISO-8859-13" ]
},
{
"name": "hebrew",
"mblen": 1,
"priority": 0,
"encodings": [ "ISO8859_8" ]
},
{
"name": "latin5",
"mblen": 1,
"priority": 0,
"encodings": [ "ISO8859_9" ]
},
{
"name": "cp850",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp850", "Cp437" ]
},
{
"name": "cp852",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp852" ]
},
{
"name": "keybcs2",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp852" ]
},
{
"name": "cp866",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp866" ]
},
{
"name": "koi8r",
"mblen": 1,
"priority": 1,
"encodings": [ "KOI8_R" ]
},
{
"name": "koi8u",
"mblen": 1,
"priority": 0,
"encodings": [ "KOI8_R" ]
},
{
"name": "tis620",
"mblen": 1,
"priority": 0,
"encodings": [ "TIS620" ]
},
{
"name": "cp1250",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp1250" ]
},
{
"name": "cp1251",
"mblen": 1,
"priority": 1,
"encodings": [ "Cp1251" ]
},
{
"name": "cp1256",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp1256" ]
},
{
"name": "cp1257",
"mblen": 1,
"priority": 0,
"encodings": [ "Cp1257" ]
},
{
"name": "macroman",
"mblen": 1,
"priority": 0,
"encodings": [ "MacRoman" ]
},
{
"name": "macce",
"mblen": 1,
"priority": 0,
"encodings": [ "MacCentralEurope" ]
},
{
"name": "utf8mb3",
"mblen": 3,
"priority": 0,
"encodings": [ "UTF-8" ],
"aliases": [ "utf8" ]
},
{
"name": "utf8mb4",
"mblen": 4,
"priority": 1,
"encodings": [ "UTF-8" ]
},
{
"name": "binary",
"mblen": 1,
"priority": 1,
"encodings": [ "ISO8859_1" ]
},
{
"name": "ucs2",
"mblen": 2,
"priority": 0,
"encodings": [ "UnicodeBig" ]
},
{
"name": "utf16",
"mblen": 4,
"priority": 0,
"encodings": [ "UTF-16" ]
},
{
"name": "utf16le",
"mblen": 4,
"priority": 0,
"encodings": [ "UTF-16LE" ]
},
{
"name": "utf32",
"mblen": 4,
"priority": 0,
"encodings": [ "UTF-32" ]
}
],
"collation_mappings": [
{
"index": 1,
"collations": [ "big5_chinese_ci" ],
"priority": 1,
"charset": "big5"
},
{
"index": 2,
"collations": [ "latin2_czech_cs" ],
"priority": 0,
"charset": "latin2"
},
{
"index": 3,
"collations": [ "dec8_swedish_ci" ],
"priority": 0,
"charset": "dec8"
},
{
"index": 4,
"collations": [ "cp850_general_ci" ],
"priority": 1,
"charset": "cp850"
},
{
"index": 5,
"collations": [ "latin1_german1_ci" ],
"priority": 0,
"charset": "latin1"
},
{
"index": 6,
"collations": [ "hp8_english_ci" ],
"priority": 0,
"charset": "hp8"
},
{
"index": 7,
"collations": [ "koi8r_general_ci" ],
"priority": 0,
"charset": "koi8r"
},
{
"index": 8,
"collations": [ "latin1_swedish_ci" ],
"priority": 1,
"charset": "latin1"
},
{
"index": 9,
"collations": [ "latin2_general_ci" ],
"priority": 1,
"charset": "latin2"
},
{
"index": 10,
"collations": [ "swe7_swedish_ci" ],
"priority": 0,
"charset": "swe7"
},
{
"index": 11,
"collations": [ "ascii_general_ci" ],
"priority": 0,
"charset": "ascii"
},
{
"index": 12,
"collations": [ "ujis_japanese_ci" ],
"priority": 0,
"charset": "ujis"
},
{
"index": 13,
"collations": [ "sjis_japanese_ci" ],
"priority": 0,
"charset": "sjis"
},
{
"index": 14,
"collations": [ "cp1251_bulgarian_ci" ],
"priority": 0,
"charset": "cp1251"
},
{
"index": 15,
"collations": [ "latin1_danish_ci" ],
"priority": 0,
"charset": "latin1"
},
{
"index": 16,
"collations": [ "hebrew_general_ci" ],
"priority": 0,
"charset": "hebrew"
},
{
"index": 18,
"collations": [ "tis620_thai_ci" ],
"priority": 0,
"charset": "tis620"
},
{
"index": 19,
"collations": [ "euckr_korean_ci" ],
"priority": 0,
"charset": "euckr"
},
{
"index": 20,
"collations": [ "latin7_estonian_cs" ],
"priority": 0,
"charset": "latin7"
},
{
"index": 21,
"collations": [ "latin2_hungarian_ci" ],
"priority": 0,
"charset": "latin2"
},
{
"index": 22,
"collations": [ "koi8u_general_ci" ],
"priority": 0,
"charset": "koi8u"
},
{
"index": 23,
"collations": [ "cp1251_ukrainian_ci" ],
"priority": 0,
"charset": "cp1251"
},
{
"index": 24,
"collations": [ "gb2312_chinese_ci" ],
"priority": 0,
"charset": "gb2312"
},
{
"index": 25,
"collations": [ "greek_general_ci" ],
"priority": 0,
"charset": "greek"
},
{
"index": 26,
"collations": [ "cp1250_general_ci" ],
"priority": 1,
"charset": "cp1250"
},
{
"index": 27,
"collations": [ "latin2_croatian_ci" ],
"priority": 0,
"charset": "latin2"
},
{
"index": 28,
"collations": [ "gbk_chinese_ci" ],
"priority": 1,
"charset": "gbk"
},
{
"index": 29,
"collations": [ "cp1257_lithuanian_ci" ],
"priority": 0,
"charset": "cp1257"
},
{
"index": 30,
"collations": [ "latin5_turkish_ci" ],
"priority": 1,
"charset": "latin5"
},
{
"index": 31,
"collations": [ "latin1_german2_ci" ],
"priority": 0,
"charset": "latin1"
},
{
"index": 32,
"collations": [ "armscii8_general_ci" ],
"priority": 0,
"charset": "armscii8"
},
{
"index": 33,
"collations": [ "utf8mb3_general_ci", "utf8_general_ci" ],
"priority": 1,
"charset": "utf8mb3"
},
{
"index": 34,
"collations": [ "cp1250_czech_cs" ],
"priority": 0,
"charset": "cp1250"
},
{
"index": 35,
"collations": [ "ucs2_general_ci" ],
"priority": 1,
"charset": "ucs2"
},
{
"index": 36,
"collations": [ "cp866_general_ci" ],
"priority": 1,
"charset": "cp866"
},
{
"index": 37,
"collations": [ "keybcs2_general_ci" ],
"priority": 1,
"charset": "keybcs2"
},
{
"index": 38,
"collations": [ "macce_general_ci" ],
"priority": 1,
"charset": "macce"
},
{
"index": 39,
"collations": [ "macroman_general_ci" ],
"priority": 1,
"charset": "macroman"
},
{
"index": 40,
"collations": [ "cp852_general_ci" ],
"priority": 1,
"charset": "cp852"
},
{
"index": 41,
"collations": [ "latin7_general_ci" ],
"priority": 1,
"charset": "latin7"
},
{
"index": 42,
"collations": [ "latin7_general_cs" ],
"priority": 0,
"charset": "latin7"
},
{
"index": 43,
"collations": [ "macce_bin" ],
"priority": 0,
"charset": "macce"
},
{
"index": 44,
"collations": [ "cp1250_croatian_ci" ],
"priority": 0,
"charset": "cp1250"
},
{
"index": 45,
"collations": [ "utf8mb4_general_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 46,
"collations": [ "utf8mb4_bin" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 47,
"collations": [ "latin1_bin" ],
"priority": 0,
"charset": "latin1"
},
{
"index": 48,
"collations": [ "latin1_general_ci" ],
"priority": 0,
"charset": "latin1"
},
{
"index": 49,
"collations": [ "latin1_general_cs" ],
"priority": 0,
"charset": "latin1"
},
{
"index": 50,
"collations": [ "cp1251_bin" ],
"priority": 0,
"charset": "cp1251"
},
{
"index": 51,
"collations": [ "cp1251_general_ci" ],
"priority": 1,
"charset": "cp1251"
},
{
"index": 52,
"collations": [ "cp1251_general_cs" ],
"priority": 0,
"charset": "cp1251"
},
{
"index": 53,
"collations": [ "macroman_bin" ],
"priority": 0,
"charset": "macroman"
},
{
"index": 54,
"collations": [ "utf16_general_ci" ],
"priority": 1,
"charset": "utf16"
},
{
"index": 55,
"collations": [ "utf16_bin" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 56,
"collations": [ "utf16le_general_ci" ],
"priority": 1,
"charset": "utf16le"
},
{
"index": 57,
"collations": [ "cp1256_general_ci" ],
"priority": 1,
"charset": "cp1256"
},
{
"index": 58,
"collations": [ "cp1257_bin" ],
"priority": 0,
"charset": "cp1257"
},
{
"index": 59,
"collations": [ "cp1257_general_ci" ],
"priority": 1,
"charset": "cp1257"
},
{
"index": 60,
"collations": [ "utf32_general_ci" ],
"priority": 1,
"charset": "utf32"
},
{
"index": 61,
"collations": [ "utf32_bin" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 62,
"collations": [ "utf16le_bin" ],
"priority": 0,
"charset": "utf16le"
},
{
"index": 63,
"collations": [ "binary" ],
"priority": 1,
"charset": "binary"
},
{
"index": 64,
"collations": [ "armscii8_bin" ],
"priority": 0,
"charset": "armscii8"
},
{
"index": 65,
"collations": [ "ascii_bin" ],
"priority": 0,
"charset": "ascii"
},
{
"index": 66,
"collations": [ "cp1250_bin" ],
"priority": 0,
"charset": "cp1250"
},
{
"index": 67,
"collations": [ "cp1256_bin" ],
"priority": 0,
"charset": "cp1256"
},
{
"index": 68,
"collations": [ "cp866_bin" ],
"priority": 0,
"charset": "cp866"
},
{
"index": 69,
"collations": [ "dec8_bin" ],
"priority": 0,
"charset": "dec8"
},
{
"index": 70,
"collations": [ "greek_bin" ],
"priority": 0,
"charset": "greek"
},
{
"index": 71,
"collations": [ "hebrew_bin" ],
"priority": 0,
"charset": "hebrew"
},
{
"index": 72,
"collations": [ "hp8_bin" ],
"priority": 0,
"charset": "hp8"
},
{
"index": 73,
"collations": [ "keybcs2_bin" ],
"priority": 0,
"charset": "keybcs2"
},
{
"index": 74,
"collations": [ "koi8r_bin" ],
"priority": 0,
"charset": "koi8r"
},
{
"index": 75,
"collations": [ "koi8u_bin" ],
"priority": 0,
"charset": "koi8u"
},
{
"index": 76,
"collations": [ "utf8mb3_tolower_ci", "utf8_tolower_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 77,
"collations": [ "latin2_bin" ],
"priority": 0,
"charset": "latin2"
},
{
"index": 78,
"collations": [ "latin5_bin" ],
"priority": 0,
"charset": "latin5"
},
{
"index": 79,
"collations": [ "latin7_bin" ],
"priority": 0,
"charset": "latin7"
},
{
"index": 80,
"collations": [ "cp850_bin" ],
"priority": 0,
"charset": "cp850"
},
{
"index": 81,
"collations": [ "cp852_bin" ],
"priority": 0,
"charset": "cp852"
},
{
"index": 82,
"collations": [ "swe7_bin" ],
"priority": 0,
"charset": "swe7"
},
{
"index": 83,
"collations": [ "utf8mb3_bin", "utf8_bin" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 84,
"collations": [ "big5_bin" ],
"priority": 0,
"charset": "big5"
},
{
"index": 85,
"collations": [ "euckr_bin" ],
"priority": 0,
"charset": "euckr"
},
{
"index": 86,
"collations": [ "gb2312_bin" ],
"priority": 0,
"charset": "gb2312"
},
{
"index": 87,
"collations": [ "gbk_bin" ],
"priority": 0,
"charset": "gbk"
},
{
"index": 88,
"collations": [ "sjis_bin" ],
"priority": 0,
"charset": "sjis"
},
{
"index": 89,
"collations": [ "tis620_bin" ],
"priority": 0,
"charset": "tis620"
},
{
"index": 90,
"collations": [ "ucs2_bin" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 91,
"collations": [ "ujis_bin" ],
"priority": 0,
"charset": "ujis"
},
{
"index": 92,
"collations": [ "geostd8_general_ci" ],
"priority": 0,
"charset": "geostd8"
},
{
"index": 93,
"collations": [ "geostd8_bin" ],
"priority": 0,
"charset": "geostd8"
},
{
"index": 94,
"collations": [ "latin1_spanish_ci" ],
"priority": 0,
"charset": "latin1"
},
{
"index": 95,
"collations": [ "cp932_japanese_ci" ],
"priority": 1,
"charset": "cp932"
},
{
"index": 96,
"collations": [ "cp932_bin" ],
"priority": 0,
"charset": "cp932"
},
{
"index": 97,
"collations": [ "eucjpms_japanese_ci" ],
"priority": 1,
"charset": "eucjpms"
},
{
"index": 98,
"collations": [ "eucjpms_bin" ],
"priority": 0,
"charset": "eucjpms"
},
{
"index": 99,
"collations": [ "cp1250_polish_ci" ],
"priority": 0,
"charset": "cp1250"
},
{
"index": 101,
"collations": [ "utf16_unicode_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 102,
"collations": [ "utf16_icelandic_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 103,
"collations": [ "utf16_latvian_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 104,
"collations": [ "utf16_romanian_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 105,
"collations": [ "utf16_slovenian_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 106,
"collations": [ "utf16_polish_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 107,
"collations": [ "utf16_estonian_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 108,
"collations": [ "utf16_spanish_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 109,
"collations": [ "utf16_swedish_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 110,
"collations": [ "utf16_turkish_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 111,
"collations": [ "utf16_czech_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 112,
"collations": [ "utf16_danish_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 113,
"collations": [ "utf16_lithuanian_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 114,
"collations": [ "utf16_slovak_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 115,
"collations": [ "utf16_spanish2_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 116,
"collations": [ "utf16_roman_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 117,
"collations": [ "utf16_persian_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 118,
"collations": [ "utf16_esperanto_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 119,
"collations": [ "utf16_hungarian_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 120,
"collations": [ "utf16_sinhala_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 121,
"collations": [ "utf16_german2_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 122,
"collations": [ "utf16_croatian_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 123,
"collations": [ "utf16_unicode_520_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 124,
"collations": [ "utf16_vietnamese_ci" ],
"priority": 0,
"charset": "utf16"
},
{
"index": 128,
"collations": [ "ucs2_unicode_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 129,
"collations": [ "ucs2_icelandic_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 130,
"collations": [ "ucs2_latvian_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 131,
"collations": [ "ucs2_romanian_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 132,
"collations": [ "ucs2_slovenian_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 133,
"collations": [ "ucs2_polish_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 134,
"collations": [ "ucs2_estonian_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 135,
"collations": [ "ucs2_spanish_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 136,
"collations": [ "ucs2_swedish_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 137,
"collations": [ "ucs2_turkish_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 138,
"collations": [ "ucs2_czech_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 139,
"collations": [ "ucs2_danish_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 140,
"collations": [ "ucs2_lithuanian_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 141,
"collations": [ "ucs2_slovak_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 142,
"collations": [ "ucs2_spanish2_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 143,
"collations": [ "ucs2_roman_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 144,
"collations": [ "ucs2_persian_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 145,
"collations": [ "ucs2_esperanto_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 146,
"collations": [ "ucs2_hungarian_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 147,
"collations": [ "ucs2_sinhala_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 148,
"collations": [ "ucs2_german2_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 149,
"collations": [ "ucs2_croatian_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 150,
"collations": [ "ucs2_unicode_520_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 151,
"collations": [ "ucs2_vietnamese_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 159,
"collations": [ "ucs2_general_mysql500_ci" ],
"priority": 0,
"charset": "ucs2"
},
{
"index": 160,
"collations": [ "utf32_unicode_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 161,
"collations": [ "utf32_icelandic_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 162,
"collations": [ "utf32_latvian_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 163,
"collations": [ "utf32_romanian_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 164,
"collations": [ "utf32_slovenian_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 165,
"collations": [ "utf32_polish_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 166,
"collations": [ "utf32_estonian_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 167,
"collations": [ "utf32_spanish_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 168,
"collations": [ "utf32_swedish_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 169,
"collations": [ "utf32_turkish_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 170,
"collations": [ "utf32_czech_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 171,
"collations": [ "utf32_danish_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 172,
"collations": [ "utf32_lithuanian_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 173,
"collations": [ "utf32_slovak_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 174,
"collations": [ "utf32_spanish2_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 175,
"collations": [ "utf32_roman_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 176,
"collations": [ "utf32_persian_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 177,
"collations": [ "utf32_esperanto_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 178,
"collations": [ "utf32_hungarian_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 179,
"collations": [ "utf32_sinhala_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 180,
"collations": [ "utf32_german2_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 181,
"collations": [ "utf32_croatian_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 182,
"collations": [ "utf32_unicode_520_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 183,
"collations": [ "utf32_vietnamese_ci" ],
"priority": 0,
"charset": "utf32"
},
{
"index": 192,
"collations": [ "utf8mb3_unicode_ci", "utf8_unicode_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 193,
"collations": [ "utf8mb3_icelandic_ci", "utf8_icelandic_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 194,
"collations": [ "utf8mb3_latvian_ci", "utf8_latvian_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 195,
"collations": [ "utf8mb3_romanian_ci", "utf8_romanian_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 196,
"collations": [ "utf8mb3_slovenian_ci", "utf8_slovenian_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 197,
"collations": [ "utf8mb3_polish_ci", "utf8_polish_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 198,
"collations": [ "utf8mb3_estonian_ci", "utf8_estonian_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 199,
"collations": [ "utf8mb3_spanish_ci", "utf8_spanish_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 200,
"collations": [ "utf8mb3_swedish_ci", "utf8_swedish_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 201,
"collations": [ "utf8mb3_turkish_ci", "utf8_turkish_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 202,
"collations": [ "utf8mb3_czech_ci", "utf8_czech_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 203,
"collations": [ "utf8mb3_danish_ci", "utf8_danish_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 204,
"collations": [ "utf8mb3_lithuanian_ci", "utf8_lithuanian_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 205,
"collations": [ "utf8mb3_slovak_ci", "utf8_slovak_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 206,
"collations": [ "utf8mb3_spanish2_ci", "utf8_spanish2_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 207,
"collations": [ "utf8mb3_roman_ci", "utf8_roman_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 208,
"collations": [ "utf8mb3_persian_ci", "utf8_persian_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 209,
"collations": [ "utf8mb3_esperanto_ci", "utf8_esperanto_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 210,
"collations": [ "utf8mb3_hungarian_ci", "utf8_hungarian_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 211,
"collations": [ "utf8mb3_sinhala_ci", "utf8_sinhala_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 212,
"collations": [ "utf8mb3_german2_ci", "utf8_german2_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 213,
"collations": [ "utf8mb3_croatian_ci", "utf8_croatian_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 214,
"collations": [ "utf8mb3_unicode_520_ci", "utf8_unicode_520_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 215,
"collations": [ "utf8mb3_vietnamese_ci", "utf8_vietnamese_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 223,
"collations": [ "utf8mb3_general_mysql500_ci", "utf8_general_mysql500_ci" ],
"priority": 0,
"charset": "utf8mb3"
},
{
"index": 224,
"collations": [ "utf8mb4_unicode_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 225,
"collations": [ "utf8mb4_icelandic_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 226,
"collations": [ "utf8mb4_latvian_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 227,
"collations": [ "utf8mb4_romanian_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 228,
"collations": [ "utf8mb4_slovenian_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 229,
"collations": [ "utf8mb4_polish_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 230,
"collations": [ "utf8mb4_estonian_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 231,
"collations": [ "utf8mb4_spanish_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 232,
"collations": [ "utf8mb4_swedish_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 233,
"collations": [ "utf8mb4_turkish_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 234,
"collations": [ "utf8mb4_czech_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 235,
"collations": [ "utf8mb4_danish_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 236,
"collations": [ "utf8mb4_lithuanian_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 237,
"collations": [ "utf8mb4_slovak_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 238,
"collations": [ "utf8mb4_spanish2_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 239,
"collations": [ "utf8mb4_roman_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 240,
"collations": [ "utf8mb4_persian_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 241,
"collations": [ "utf8mb4_esperanto_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 242,
"collations": [ "utf8mb4_hungarian_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 243,
"collations": [ "utf8mb4_sinhala_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 244,
"collations": [ "utf8mb4_german2_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 245,
"collations": [ "utf8mb4_croatian_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 246,
"collations": [ "utf8mb4_unicode_520_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 247,
"collations": [ "utf8mb4_vietnamese_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 248,
"collations": [ "gb18030_chinese_ci" ],
"priority": 1,
"charset": "gb18030"
},
{
"index": 249,
"collations": [ "gb18030_bin" ],
"priority": 0,
"charset": "gb18030"
},
{
"index": 250,
"collations": [ "gb18030_unicode_520_ci" ],
"priority": 0,
"charset": "gb18030"
},
{
"index": 255,
"collations": [ "utf8mb4_0900_ai_ci" ],
"priority": 1,
"charset": "utf8mb4"
},
{
"index": 256,
"collations": [ "utf8mb4_de_pb_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 257,
"collations": [ "utf8mb4_is_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 258,
"collations": [ "utf8mb4_lv_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 259,
"collations": [ "utf8mb4_ro_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 260,
"collations": [ "utf8mb4_sl_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 261,
"collations": [ "utf8mb4_pl_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 262,
"collations": [ "utf8mb4_et_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 263,
"collations": [ "utf8mb4_es_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 264,
"collations": [ "utf8mb4_sv_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 265,
"collations": [ "utf8mb4_tr_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 266,
"collations": [ "utf8mb4_cs_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 267,
"collations": [ "utf8mb4_da_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 268,
"collations": [ "utf8mb4_lt_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 269,
"collations": [ "utf8mb4_sk_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 270,
"collations": [ "utf8mb4_es_trad_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 271,
"collations": [ "utf8mb4_la_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 273,
"collations": [ "utf8mb4_eo_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 274,
"collations": [ "utf8mb4_hu_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 275,
"collations": [ "utf8mb4_hr_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 277,
"collations": [ "utf8mb4_vi_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 278,
"collations": [ "utf8mb4_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 279,
"collations": [ "utf8mb4_de_pb_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 280,
"collations": [ "utf8mb4_is_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 281,
"collations": [ "utf8mb4_lv_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 282,
"collations": [ "utf8mb4_ro_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 283,
"collations": [ "utf8mb4_sl_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 284,
"collations": [ "utf8mb4_pl_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 285,
"collations": [ "utf8mb4_et_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 286,
"collations": [ "utf8mb4_es_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 287,
"collations": [ "utf8mb4_sv_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 288,
"collations": [ "utf8mb4_tr_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 289,
"collations": [ "utf8mb4_cs_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 290,
"collations": [ "utf8mb4_da_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 291,
"collations": [ "utf8mb4_lt_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 292,
"collations": [ "utf8mb4_sk_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 293,
"collations": [ "utf8mb4_es_trad_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 294,
"collations": [ "utf8mb4_la_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 296,
"collations": [ "utf8mb4_eo_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 297,
"collations": [ "utf8mb4_hu_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 298,
"collations": [ "utf8mb4_hr_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 300,
"collations": [ "utf8mb4_vi_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 303,
"collations": [ "utf8mb4_ja_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 304,
"collations": [ "utf8mb4_ja_0900_as_cs_ks" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 305,
"collations": [ "utf8mb4_0900_as_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 306,
"collations": [ "utf8mb4_ru_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 307,
"collations": [ "utf8mb4_ru_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 308,
"collations": [ "utf8mb4_zh_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 309,
"collations": [ "utf8mb4_0900_bin" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 310,
"collations": [ "utf8mb4_nb_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 311,
"collations": [ "utf8mb4_nb_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 312,
"collations": [ "utf8mb4_nn_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 313,
"collations": [ "utf8mb4_nn_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 314,
"collations": [ "utf8mb4_sr_latn_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 315,
"collations": [ "utf8mb4_sr_latn_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 316,
"collations": [ "utf8mb4_bs_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 317,
"collations": [ "utf8mb4_bs_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 318,
"collations": [ "utf8mb4_bg_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 319,
"collations": [ "utf8mb4_bg_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 320,
"collations": [ "utf8mb4_gl_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 321,
"collations": [ "utf8mb4_gl_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 322,
"collations": [ "utf8mb4_mn_cyrl_0900_ai_ci" ],
"priority": 0,
"charset": "utf8mb4"
},
{
"index": 323,
"collations": [ "utf8mb4_mn_cyrl_0900_as_cs" ],
"priority": 0,
"charset": "utf8mb4"
}
]
}

View File

@ -1,21 +0,0 @@
-- In production you would almost certainly limit the replication user must be on the follower (replica) machine,
-- to prevent other clients accessing the log from other machines. For example, 'replicator'@'follower.acme.com'.
-- However, in this database we'll grant 3 users different privileges:
--
-- 1) 'replicator' - all privileges required by the binlog reader (setup through 'readbinlog.sql')
-- 2) 'snapper' - all privileges required by the snapshot reader AND binlog reader
-- 3) 'mysqluser' - all privileges
--
CREATE USER 'replicator' IDENTIFIED BY 'replpass';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'replicator';
CREATE USER 'snapper' IDENTIFIED BY 'snapperpass';
GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'snapper'@'%';
CREATE USER 'cloud' IDENTIFIED BY 'cloudpass';
GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT, LOCK TABLES ON *.* TO 'cloud'@'%';
GRANT ALL PRIVILEGES ON *.* TO 'mysqlreplica'@'%';
-- Start the GTID-based replication ...
CHANGE MASTER TO MASTER_HOST='database-gtids', MASTER_PORT=3306, MASTER_USER='replicator', MASTER_PASSWORD = 'replpass', MASTER_USE_GTID=slave_pos;
-- And start the replica ...
START SLAVE;

View File

@ -1,2 +0,0 @@
-- Enforce client certificate validation for user 'snapper'
ALTER USER 'snapper' REQUIRE X509;

View File

@ -1,37 +0,0 @@
-- In production you would almost certainly limit the replication user must be on the follower (replica) machine,
-- to prevent other clients accessing the log from other machines. For example, 'replicator'@'follower.acme.com'.
-- However, in this database we'll grant 3 users different privileges:
--
-- 1) 'replicator' - all privileges required by the binlog reader (setup through 'readbinlog.sql')
-- 2) 'snapper' - all privileges required by the snapshot reader AND binlog reader
-- 3) 'mysqluser' - all privileges
--
CREATE USER 'replicator' IDENTIFIED BY 'replpass';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'replicator';
CREATE USER 'snapper' IDENTIFIED BY 'snapperpass';
GRANT SELECT, INSERT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'snapper'@'%';
CREATE USER 'cloud' IDENTIFIED BY 'cloudpass';
GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT, LOCK TABLES ON *.* TO 'cloud'@'%';
GRANT ALL PRIVILEGES ON *.* TO 'mysqluser'@'%';
-- ----------------------------------------------------------------------------------------------------------------
-- DATABASE: emptydb
-- ----------------------------------------------------------------------------------------------------------------
CREATE DATABASE emptydb;
RESET MASTER;
CREATE DATABASE testing;
CREATE TABLE testing.testing (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();
INSERT INTO testing.testing VALUES ();

View File

@ -1,24 +0,0 @@
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.2/en/server-configuration-defaults.html
# --------------------------------------------------------------------------------------------
# This section specifies 5.5 and cross-version common configurations
# --------------------------------------------------------------------------------------------
[mariadb]
skip-host-cache
skip-name-resolve
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Enable binary replication log and set the prefix, expiration, and log format.
# The prefix is arbitrary, expiration can be short for integration tests but would
# be longer on a production system. Row-level info is required for ingest to work.
# Server ID is required, but this will vary on production systems
server-id = 112233
log_bin = mysql-bin
binlog_format = row
log_slave_updates = on
log_bin_compress = off
default_authentication_plugin = mysql_native_password

View File

@ -1,19 +0,0 @@
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.2/en/server-configuration-defaults.html
# --------------------------------------------------------------------------------------------
# This section specifies 5.5 and cross-version common configurations
# --------------------------------------------------------------------------------------------
[mariadb]
skip-host-cache
skip-name-resolve
user = mysql
symbolic-links = 0
log_slave_updates = on
server-id = 445566
log_bin = mysql-bin-slave
binlog_format = row
read_only = 1
relay_log = mysql-relay-bin
log_bin_compress = off
default_authentication_plugin = mysql_native_password

View File

@ -1,48 +0,0 @@
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.2/en/server-configuration-defaults.html
# --------------------------------------------------------------------------------------------
# This section specifies 5.5 and cross-version common configurations
# --------------------------------------------------------------------------------------------
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
skip-host-cache
skip-name-resolve
#datadir=/var/lib/mysql
#socket=/var/lib/mysql/mysql.sock
#secure-file-priv=/var/lib/mysql-files
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#log-error=/var/log/mysqld.log
#pid-file=/var/run/mysqld/mysqld.pid
# Enable binary replication log and set the prefix, expiration, and log format.
# The prefix is arbitrary, expiration can be short for integration tests but would
# be longer on a production system. Row-level info is required for ingest to work.
# Server ID is required, but this will vary on production systems
server-id = 112233
log_bin = mysql-bin
binlog_format = row
log_bin_compress = off
ssl_ca=/etc/certs/ca.pem
ssl_cert=/etc/certs/server-cert.pem
ssl_key=/etc/certs/server-key.pem
require_secure_transport=ON

View File

@ -1,43 +0,0 @@
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.2/en/server-configuration-defaults.html
# --------------------------------------------------------------------------------------------
# This section specifies 5.5 and cross-version common configurations
# --------------------------------------------------------------------------------------------
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
skip-host-cache
skip-name-resolve
#datadir=/var/lib/mysql
#socket=/var/lib/mysql/mysql.sock
#secure-file-priv=/var/lib/mysql-files
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#log-error=/var/log/mysqld.log
#pid-file=/var/run/mysqld/mysqld.pid
# Enable binary replication log and set the prefix, expiration, and log format.
# The prefix is arbitrary, expiration can be short for integration tests but would
# be longer on a production system. Row-level info is required for ingest to work.
# Server ID is required, but this will vary on production systems
server-id = 112233
log_bin = mysql-bin
binlog_format = row
log_bin_compress = off

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogBinaryModeIT;
/**
* @author Chris Cranford
*/
public class BinaryModeIT extends BinlogBinaryModeIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogBlockingSnapshotIT;
/**
* @author Chris Cranford
*/
public class BlockingSnapshotIT extends BinlogBlockingSnapshotIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,23 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogCloudEventsConverterIT;
/**
* @author Chris Cranford
*/
public class CloudEventsConverterIT extends BinlogCloudEventsConverterIT<MariaDbConnector> implements MariaDbCommon {
@Override
public String getConnectorName() {
return Module.name();
}
@Override
public Class<MariaDbConnector> getConnectorClass() {
return MariaDbConnector.class;
}
}

View File

@ -1,17 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.config.ConfigDefinitionMetadataTest;
/**
* @author Chris Cranford
*/
public class ConfigDefTest extends ConfigDefinitionMetadataTest {
public ConfigDefTest() {
super(new MariaDbConnector());
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import java.sql.SQLException;
import java.sql.SQLTimeoutException;
import org.junit.Test;
import io.debezium.connector.binlog.BinlogConnectionIT;
import io.debezium.connector.binlog.util.BinlogTestConnection;
import io.debezium.connector.binlog.util.TestHelper;
import io.debezium.connector.binlog.util.UniqueDatabase;
/**
* @author Chris Cranford
*/
public class ConnectionIT extends BinlogConnectionIT<MariaDbConnector> implements MariaDbCommon {
@Test
public void whenQueryTakesMoreThenConfiguredQueryTimeoutAnExceptionMustBeThrown() throws SQLException {
final UniqueDatabase DATABASE = TestHelper.getUniqueDatabase("readbinlog", "readbinlog_test");
DATABASE.createAndInitialize();
try (BinlogTestConnection conn = getTestDatabaseConnection(DATABASE.getDatabaseName(), 1000)) {
conn.connect();
assertThatThrownBy(() -> conn.execute("SELECT SLEEP(10)"))
.isInstanceOf(SQLTimeoutException.class)
.hasMessageContaining("Query execution was interrupted (max_statement_time exceeded)");
}
}
}

View File

@ -1,24 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.config.Field;
import io.debezium.connector.binlog.BinlogConnectorConfigTest;
/**
* @author Chris Cranford
*/
public class ConnectorConfigTest extends BinlogConnectorConfigTest<MariaDbConnector> implements MariaDbCommon {
@Override
protected MariaDbConnector getConnectorInstance() {
return new MariaDbConnector();
}
@Override
protected Field.Set getAllFields() {
return MariaDbConnectorConfig.ALL_FIELDS;
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogConvertingFailureIT;
/**
* @author Chris Cranford
*/
public class ConvertingFailureIT extends BinlogConvertingFailureIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,18 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogCustomSnapshotterIT;
/**
* @author Chris Cranford
*/
public class CustomSnapshotterIT extends BinlogCustomSnapshotterIT<MariaDbConnector> implements MariaDbCommon {
@Override
protected String getCustomSnapshotClassName() {
return CustomTestSnapshot.class.getName();
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import io.debezium.bean.StandardBeanNames;
import io.debezium.bean.spi.BeanRegistry;
import io.debezium.bean.spi.BeanRegistryAware;
import io.debezium.connector.mariadb.snapshot.query.SelectAllSnapshotQuery;
import io.debezium.pipeline.spi.Offsets;
import io.debezium.spi.snapshot.Snapshotter;
/**
* This is a small class used in CustomSnapshotterIT to test a custom snapshot
*
* It is tightly coupled to the test there, but needs to be placed here in order
* to allow for class loading to work
*
*/
public class CustomTestSnapshot extends SelectAllSnapshotQuery implements Snapshotter, BeanRegistryAware {
private boolean hasState;
@Override
public String name() {
return CustomTestSnapshot.class.getName();
}
@Override
public void injectBeanRegistry(BeanRegistry beanRegistry) {
Offsets<MariaDbPartition, MariaDbOffsetContext> mariaDbOffsetContext = beanRegistry.lookupByName(StandardBeanNames.OFFSETS, Offsets.class);
hasState = mariaDbOffsetContext.getTheOnlyOffset() != null;
}
@Override
public boolean shouldSnapshotData(boolean offsetExists, boolean snapshotInProgress) {
return true;
}
@Override
public boolean shouldStream() {
return true;
}
@Override
public boolean shouldSnapshotSchema(boolean offsetExists, boolean snapshotInProgress) {
return true;
}
@Override
public boolean shouldSnapshotOnSchemaError() {
return false;
}
@Override
public boolean shouldSnapshotOnDataError() {
return false;
}
@Override
public Optional<String> snapshotQuery(String tableId, List<String> snapshotSelectColumns) {
if (!hasState && tableId.contains("`b`")) {
return Optional.empty();
}
else {
String query = snapshotSelectColumns.stream()
.collect(Collectors.joining(", ", "SELECT ", " FROM " + tableId));
return Optional.of(query);
}
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Set;
import io.debezium.config.CommonConnectorConfig;
import io.debezium.config.Configuration;
import io.debezium.connector.binlog.BinlogConnectorConfig;
import io.debezium.connector.binlog.BinlogDatabaseSchemaTest;
import io.debezium.connector.mariadb.jdbc.MariaDbValueConverters;
import io.debezium.connector.mariadb.util.MariaDbValueConvertersFactory;
import io.debezium.jdbc.TemporalPrecisionMode;
import io.debezium.relational.RelationalDatabaseConnectorConfig.DecimalHandlingMode;
import io.debezium.relational.history.AbstractSchemaHistory;
import io.debezium.schema.DefaultTopicNamingStrategy;
import io.debezium.schema.SchemaNameAdjuster;
import io.debezium.spi.topic.TopicNamingStrategy;
/**
* @author Chris Cranford
*/
public class DatabaseSchemaTest extends BinlogDatabaseSchemaTest<MariaDbConnectorConfig, MariaDbDatabaseSchema, MariaDbPartition, MariaDbOffsetContext> {
@Override
protected MariaDbConnectorConfig getConnectorConfig(Configuration config) {
config = config.edit().with(AbstractSchemaHistory.INTERNAL_PREFER_DDL, true).build();
return new MariaDbConnectorConfig(config);
}
@Override
protected MariaDbDatabaseSchema getSchema(Configuration config) {
this.connectorConfig = getConnectorConfig(config);
return new MariaDbDatabaseSchema(
connectorConfig,
new MariaDbValueConvertersFactory().create(
DecimalHandlingMode.PRECISE,
TemporalPrecisionMode.ADAPTIVE,
BinlogConnectorConfig.BigIntUnsignedHandlingMode.LONG,
CommonConnectorConfig.BinaryHandlingMode.BYTES,
MariaDbValueConverters::adjustTemporal,
CommonConnectorConfig.EventConvertingFailureHandlingMode.WARN),
(TopicNamingStrategy) DefaultTopicNamingStrategy.create(connectorConfig),
SchemaNameAdjuster.create(),
false);
}
@Override
protected MariaDbPartition initializePartition(MariaDbConnectorConfig connectorConfig, Configuration taskConfig) {
Set<MariaDbPartition> partitions = new MariaDbPartition.Provider(connectorConfig, taskConfig).getPartitions();
assertThat(partitions).hasSize(1);
return partitions.iterator().next();
}
@Override
protected MariaDbOffsetContext initializeOffset(MariaDbConnectorConfig connectorConfig) {
return MariaDbOffsetContext.initial(connectorConfig);
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogDateTimeInKeyIT;
/**
* @author Chris Cranford
*/
public class DateTimeInKeyIT extends BinlogDateTimeInKeyIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogDdlParserIT;
/**
* @author Chris Cranford
*/
public class DdlParserIT extends BinlogDdlParserIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogDecimalColumnIT;
/**
* @author Chris Cranford
*/
public class DecimalColumnIT extends BinlogDecimalColumnIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogDecimalIT;
/**
* @author Chris Cranford
*/
public class DecimalIT extends BinlogDecimalIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogDefaultDatabaseCharsetIT;
/**
* @author Chris Cranford
*/
public class DefaultDatabaseCharsetIT extends BinlogDefaultDatabaseCharsetIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogDefaultGeneratedValueIT;
/**
* @author Chris Cranford
*/
public class DefaultGeneratedValueIT extends BinlogDefaultGeneratedValueIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogDefaultValueAllZeroTimeIT;
/**
* @author Chris Cranford
*/
public class DefaultValueAllZeroTimeIT extends BinlogDefaultValueAllZeroTimeIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogDefaultValueIT;
/**
* @author Chris Cranford
*/
public class DefaultValueIT extends BinlogDefaultValueIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,48 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.config.CommonConnectorConfig.BinaryHandlingMode;
import io.debezium.config.CommonConnectorConfig.EventConvertingFailureHandlingMode;
import io.debezium.connector.binlog.BinlogConnectorConfig;
import io.debezium.connector.binlog.BinlogDefaultValueTest;
import io.debezium.connector.binlog.jdbc.BinlogDefaultValueConverter;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.connector.mariadb.jdbc.MariaDbDefaultValueConverter;
import io.debezium.connector.mariadb.jdbc.MariaDbValueConverters;
import io.debezium.connector.mariadb.util.MariaDbValueConvertersFactory;
import io.debezium.jdbc.JdbcValueConverters.BigIntUnsignedMode;
import io.debezium.jdbc.JdbcValueConverters.DecimalMode;
import io.debezium.jdbc.TemporalPrecisionMode;
import io.debezium.relational.RelationalDatabaseConnectorConfig;
/**
* @author Chris Cranford
*/
public class DefaultValueTest extends BinlogDefaultValueTest<MariaDbValueConverters, MariaDbAntlrDdlParser> {
@Override
protected MariaDbAntlrDdlParser getDdlParser(MariaDbValueConverters valueConverters) {
return new MariaDbAntlrDdlParser(valueConverters);
}
@Override
protected MariaDbValueConverters getValueConverter(DecimalMode decimalMode,
TemporalPrecisionMode temporalPrecisionMode,
BigIntUnsignedMode bigIntUnsignedMode,
BinaryHandlingMode binaryHandlingMode) {
return new MariaDbValueConvertersFactory().create(
RelationalDatabaseConnectorConfig.DecimalHandlingMode.parse(decimalMode.name()),
temporalPrecisionMode,
BinlogConnectorConfig.BigIntUnsignedHandlingMode.parse(bigIntUnsignedMode.name()),
binaryHandlingMode,
EventConvertingFailureHandlingMode.WARN);
}
@Override
protected BinlogDefaultValueConverter getDefaultValueConverter(MariaDbValueConverters valueConverters) {
return new MariaDbDefaultValueConverter(valueConverters);
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogEnumColumnIT;
/**
* @author Chris Cranford
*/
public class EnumColumnIT extends BinlogEnumColumnIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,19 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.config.Field;
import io.debezium.connector.binlog.BinlogFieldTest;
/**
* @author Chris Cranford
*/
public class FieldTest extends BinlogFieldTest<MariaDbConnector> implements MariaDbCommon {
@Override
protected Field.Set getAllFields() {
return MariaDbConnectorConfig.ALL_FIELDS;
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogFixedLengthBinaryColumnIT;
/**
* @author Chris Cranford
*/
public class FixedLengthBinaryColumnIT extends BinlogFixedLengthBinaryColumnIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogFloatIT;
/**
* @author Chris Cranford
*/
public class FloatIT extends BinlogFloatIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogGeometryIT;
/**
* @author Chris Cranford
*/
public class GeometryIT extends BinlogGeometryIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,19 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogIncrementalSnapshotIT;
import io.debezium.connector.mariadb.jdbc.MariaDbFieldReader;
/**
* @author Chris Cranford
*/
public class IncrementalSnapshotIT extends BinlogIncrementalSnapshotIT<MariaDbConnector> implements MariaDbCommon {
@Override
protected Class<?> getFieldReader() {
return MariaDbFieldReader.class;
}
}

View File

@ -1,17 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogJdbcSinkDataTypeConverterIT;
/**
* MariaDB-specific tests with the {@link io.debezium.connector.binlog.converters.JdbcSinkDataTypesConverter}.
*
* @author Chris Cranford
*/
public class JdbcSinkDataTypeConverterIT extends BinlogJdbcSinkDataTypeConverterIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogJsonIT;
/**
* @author Chris Cranford
*/
public class JsonIT extends BinlogJsonIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,91 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.util.List;
import io.debezium.config.CommonConnectorConfig;
import io.debezium.connector.binlog.BinlogAntlrDdlParserTest;
import io.debezium.connector.binlog.BinlogConnectorConfig;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.connector.mariadb.charset.MariaDbCharsetRegistry;
import io.debezium.connector.mariadb.jdbc.MariaDbDefaultValueConverter;
import io.debezium.connector.mariadb.jdbc.MariaDbValueConverters;
import io.debezium.connector.mariadb.util.MariaDbValueConvertersFactory;
import io.debezium.jdbc.TemporalPrecisionMode;
import io.debezium.relational.RelationalDatabaseConnectorConfig;
import io.debezium.relational.Tables;
import io.debezium.relational.ddl.DdlChanges;
import io.debezium.relational.ddl.SimpleDdlParserListener;
/**
* @author Chris Cranford
*/
public class MariaDbAntlrDdlParserTest extends BinlogAntlrDdlParserTest<MariaDbValueConverters, MariaDbDefaultValueConverter, MariaDbAntlrDdlParser> {
@Override
protected MariaDbAntlrDdlParser getParser(SimpleDdlParserListener listener, MariaDbValueConverters converters) {
return new MariaDbDdlParserWithSimpleTestListener(listener, converters);
}
@Override
protected MariaDbAntlrDdlParser getParser(SimpleDdlParserListener listener, MariaDbValueConverters converters, boolean includeViews) {
return new MariaDbDdlParserWithSimpleTestListener(listener, includeViews, converters);
}
@Override
protected MariaDbAntlrDdlParser getParser(SimpleDdlParserListener listener, MariaDbValueConverters converters, Tables.TableFilter tableFilter) {
return new MariaDbDdlParserWithSimpleTestListener(listener, tableFilter, converters);
}
@Override
protected MariaDbAntlrDdlParser getParser(SimpleDdlParserListener listener, MariaDbValueConverters converters, boolean includeViews, boolean includeComments) {
return new MariaDbDdlParserWithSimpleTestListener(listener, includeViews, includeComments, converters);
}
@Override
protected MariaDbValueConverters getValueConverters() {
return new MariaDbValueConvertersFactory().create(
RelationalDatabaseConnectorConfig.DecimalHandlingMode.DOUBLE,
TemporalPrecisionMode.ADAPTIVE_TIME_MICROSECONDS,
BinlogConnectorConfig.BigIntUnsignedHandlingMode.PRECISE,
CommonConnectorConfig.BinaryHandlingMode.BYTES,
CommonConnectorConfig.EventConvertingFailureHandlingMode.WARN);
}
@Override
protected MariaDbDefaultValueConverter getDefaultValueConverters(MariaDbValueConverters valueConverters) {
return new MariaDbDefaultValueConverter(valueConverters);
}
@Override
protected List<String> extractEnumAndSetOptions(List<String> enumValues) {
return MariaDbAntlrDdlParser.extractEnumAndSetOptions(enumValues);
}
public static class MariaDbDdlParserWithSimpleTestListener extends MariaDbAntlrDdlParser {
public MariaDbDdlParserWithSimpleTestListener(DdlChanges listener, MariaDbValueConverters converters) {
this(listener, false, converters);
}
public MariaDbDdlParserWithSimpleTestListener(DdlChanges listener, Tables.TableFilter tableFilter, MariaDbValueConverters converters) {
this(listener, false, false, tableFilter, converters);
}
public MariaDbDdlParserWithSimpleTestListener(DdlChanges listener, boolean includeViews, MariaDbValueConverters converters) {
this(listener, includeViews, false, Tables.TableFilter.includeAll(), converters);
}
public MariaDbDdlParserWithSimpleTestListener(DdlChanges listener, boolean includeViews, boolean includeComments, MariaDbValueConverters converters) {
this(listener, includeViews, includeComments, Tables.TableFilter.includeAll(), converters);
}
public MariaDbDdlParserWithSimpleTestListener(DdlChanges listener, boolean includeViews, boolean includeComments, Tables.TableFilter tableFilter,
MariaDbValueConverters converters) {
super(false, includeViews, includeComments, converters, tableFilter, new MariaDbCharsetRegistry());
this.ddlChanges = listener;
}
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogReaderBufferIT;
/**
* @author Chris Cranford
*/
public class MariaDbBinlogReaderBufferIT extends BinlogReaderBufferIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,50 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogConnectorTest;
import io.debezium.connector.binlog.util.BinlogTestConnection;
import io.debezium.connector.mariadb.util.MariaDbTestConnection;
/**
* Common implementation bits for MariaDB for a {@link BinlogConnectorTest}.<p></p>
*
* By using this common interface, we avoid needing to duplicate this information in each test, allowing for
* modifying or adding to the common interface in the future in a single location.
*
* @author Chris Cranford
*/
public interface MariaDbCommon extends BinlogConnectorTest<MariaDbConnector> {
@Override
default String getConnectorName() {
return Module.name();
}
@Override
default Class<MariaDbConnector> getConnectorClass() {
return MariaDbConnector.class;
}
@Override
default BinlogTestConnection getTestDatabaseConnection(String databaseName) {
return MariaDbTestConnection.forTestDatabase(databaseName);
}
@Override
default BinlogTestConnection getTestDatabaseConnection(String databaseName, int queryTimeout) {
return MariaDbTestConnection.forTestDatabase(databaseName, queryTimeout);
}
@Override
default BinlogTestConnection getTestReplicaDatabaseConnection(String databaseName) {
return MariaDbTestConnection.forTestReplicaDatabase(databaseName);
}
@Override
default boolean isMariaDb() {
return true;
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Map;
import org.apache.kafka.common.config.Config;
import io.debezium.config.Configuration;
import io.debezium.config.Field;
import io.debezium.connector.binlog.BinlogConnectorIT;
import io.debezium.connector.mariadb.MariaDbConnectorConfig.SnapshotLockingMode;
/**
* @author Chris Cranford
*/
public class MariaDbConnectorIT extends BinlogConnectorIT<MariaDbConnector, MariaDbPartition, MariaDbOffsetContext>
implements MariaDbCommon {
@Override
protected Config validateConfiguration(Configuration configuration) {
return new MariaDbConnector().validate(configuration.asMap());
}
@Override
protected void assertInvalidConfiguration(Config result) {
super.assertInvalidConfiguration(result);
assertNoConfigurationErrors(result, MariaDbConnectorConfig.SNAPSHOT_LOCKING_MODE);
}
@Override
protected void assertValidConfiguration(Config result) {
super.assertValidConfiguration(result);
validateConfigField(result, MariaDbConnectorConfig.SNAPSHOT_LOCKING_MODE, SnapshotLockingMode.MINIMAL);
}
@Override
protected Field getSnapshotLockingModeField() {
return MariaDbConnectorConfig.SNAPSHOT_LOCKING_MODE;
}
@Override
protected String getSnapshotLockingModeNone() {
return SnapshotLockingMode.NONE.getValue();
}
@Override
protected void assertSnapshotLockingModeIsNone(Configuration config) {
assertThat(new MariaDbConnectorConfig(config).getSnapshotLockingMode().get()).isEqualTo(SnapshotLockingMode.NONE);
}
@Override
protected MariaDbPartition createPartition(String serverName, String databaseName) {
return new MariaDbPartition(serverName, databaseName);
}
@Override
protected MariaDbOffsetContext loadOffsets(Configuration configuration, Map<String, ?> offsets) {
return new MariaDbOffsetContext.Loader(new MariaDbConnectorConfig(configuration)).load(offsets);
}
@Override
protected void assertBinlogPosition(long offsetPosition, long beforeInsertsPosition) {
assertThat(offsetPosition).isGreaterThanOrEqualTo(beforeInsertsPosition);
}
@Override
protected String getExpectedQuery(String statement) {
return "SET STATEMENT max_statement_time=600 FOR " + statement;
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import io.debezium.connector.mariadb.gtid.MariaDbGtidSet;
/**
* MariaDB-specific global transaction identifier tests.
*
* @author Chris Cranford
*/
public class MariaDbGtidSetTest {
private static final String DOMAIN_SERVER_ID = "1-2";
private MariaDbGtidSet gtids;
@Test
public void shouldParseGtid() {
gtids = new MariaDbGtidSet(DOMAIN_SERVER_ID + "-3");
assertThat(gtids.forStreamId(new MariaDbGtidSet.MariaDbGtidStreamId(1, 2)).hasSequence(3)).isTrue();
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogMetricsIT;
import io.debezium.connector.binlog.util.BinlogTestConnection;
/**
* @author Chris Cranford
*/
public class MariaDbMetricsIT extends BinlogMetricsIT<MariaDbConnector> implements MariaDbCommon {
@Override
public Class<MariaDbConnector> getConnectorClass() {
return MariaDbCommon.super.getConnectorClass();
}
@Override
public BinlogTestConnection getTestDatabaseConnection(String databaseName) {
return MariaDbCommon.super.getTestDatabaseConnection(databaseName);
}
@Override
public String getConnectorName() {
return MariaDbCommon.super.getConnectorName();
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogMetadataIT;
/**
* @author Chris Cranford
*/
public class MetadataIT extends BinlogMetadataIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogMultiTableStatementIT;
/**
* @author Chris Cranford
*/
public class MultiTableStatementIT extends BinlogMultiTableStatementIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogNonUtfDatabaseCharsetIT;
/**
* @author Chris Cranford
*/
public class NonUtfDatabaseCharsetIT extends BinlogNonUtfDatabaseCharsetIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogNotificationsIT;
/**
* @author Chris Cranford
*/
public class NotificationsIT extends BinlogNotificationsIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogNumericColumnIT;
/**
* @author Chris Cranford
*/
public class NumericColumnIT extends BinlogNumericColumnIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,23 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogPartitionTest;
/**
* @author Chris Cranford
*/
public class PartitionTest extends BinlogPartitionTest<MariaDbPartition> {
@Override
protected MariaDbPartition createPartition1() {
return new MariaDbPartition("server1", "database1");
}
@Override
protected MariaDbPartition createPartition2() {
return new MariaDbPartition("server2", "database1");
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogReadBinLogIT;
/**
* @author Chris Cranford
*/
public class ReadBinLogIT extends BinlogReadBinLogIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,19 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogReadOnlyIncrementalSnapshotIT;
import io.debezium.connector.mariadb.jdbc.MariaDbFieldReader;
/**
* @author Chris Cranford
*/
public class ReadOnlyIncrementalSnapshotIT extends BinlogReadOnlyIncrementalSnapshotIT<MariaDbConnector> implements MariaDbCommon {
@Override
protected Class<?> getFieldReader() {
return MariaDbFieldReader.class;
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogRegressionIT;
/**
* @author Chris Cranford
*/
public class RegressionIT extends BinlogRegressionIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,18 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogReselectColumnsProcessorIT;
/**
* @author Chris Cranford
*/
public class ReselectColumnsProcessorIT extends BinlogReselectColumnsProcessorIT<MariaDbConnector> implements MariaDbCommon {
@Override
public Class<MariaDbConnector> getConnectorClass() {
return MariaDbConnector.class;
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogRestartIT;
/**
* @author Chris Cranford
*/
public class RestartIT extends BinlogRestartIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogSchemaHistoryIT;
/**
* @author Chris Cranford
*/
public class SchemaHistoryIT extends BinlogSchemaHistoryIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,19 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogSchemaMigrationIT;
import io.debezium.connector.mariadb.antlr.listener.RenameTableParserListener;
/**
* @author Chris Cranford
*/
public class SchemaMigrationIT extends BinlogSchemaMigrationIT<MariaDbConnector> implements MariaDbCommon {
@Override
protected Class<?> getRenameTableParserListenerClass() {
return RenameTableParserListener.class;
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogSchemaNameAdjustmentModeIT;
/**
* @author Chris Cranford
*/
public class SchemaNameAdjustmentModeIT extends BinlogSchemaNameAdjustmentModeIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogSchemaValidateIT;
/**
* @author Chris Cranford
*/
public class SchemaValidateIT extends BinlogSchemaValidateIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogSignalsIT;
/**
* @author Chris Cranford
*/
public class SignalsIT extends BinlogSignalsIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,16 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogSkipMessagesWithoutChangeConfigIT;
/**
* @author Chris Cranford
*/
public class SkipMessagesWithoutChangeConfigIT extends BinlogSkipMessagesWithoutChangeConfigIT<MariaDbConnector>
implements MariaDbCommon {
}

View File

@ -1,29 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.config.Field;
import io.debezium.connector.binlog.BinlogSnapshotParallelSourceIT;
/**
* @author Chris Cranford
*/
public class SnapshotParallelSourceIT extends BinlogSnapshotParallelSourceIT<MariaDbConnector> implements MariaDbCommon {
@Override
protected Field getSnapshotLockingModeField() {
return MariaDbConnectorConfig.SNAPSHOT_LOCKING_MODE;
}
@Override
protected String getSnapshotLockingModeMinimal() {
return MariaDbConnectorConfig.SnapshotLockingMode.MINIMAL.getValue();
}
@Override
protected String getSnapshotLockingModeNone() {
return MariaDbConnectorConfig.SnapshotLockingMode.NONE.getValue();
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.config.Field;
import io.debezium.connector.binlog.BinlogSnapshotSourceIT;
/**
* @author Chris Cranford
*/
public class SnapshotSourceIT extends BinlogSnapshotSourceIT<MariaDbConnector> implements MariaDbCommon {
@Override
protected Field getSnapshotLockingModeField() {
return MariaDbConnectorConfig.SNAPSHOT_LOCKING_MODE;
}
@Override
protected String getSnapshotLockingModeMinimal() {
return MariaDbConnectorConfig.SnapshotLockingMode.MINIMAL.getValue();
}
@Override
protected String getSnapshotLockingModeNone() {
return MariaDbConnectorConfig.SnapshotLockingMode.NONE.getValue();
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.util.Map;
import java.util.function.Predicate;
import io.debezium.config.Configuration;
import io.debezium.connector.binlog.BinlogSourceInfoTest;
import io.debezium.connector.binlog.history.BinlogHistoryRecordComparator;
import io.debezium.connector.mariadb.gtid.MariaDbGtidSetFactory;
import io.debezium.connector.mariadb.history.MariaDbHistoryRecordComparator;
/**
* @author Chris Cranford
*/
public class SourceInfoTest extends BinlogSourceInfoTest<SourceInfo, MariaDbOffsetContext> {
@Override
protected String getModuleName() {
return Module.name();
}
@Override
protected String getModuleVersion() {
return Module.version();
}
@Override
protected BinlogHistoryRecordComparator getHistoryRecordComparator(Predicate<String> gtidFilter) {
return new MariaDbHistoryRecordComparator(gtidFilter, new MariaDbGtidSetFactory());
}
@Override
protected MariaDbOffsetContext createInitialOffsetContext(Configuration configuration) {
return MariaDbOffsetContext.initial(new MariaDbConnectorConfig(configuration));
}
@Override
protected MariaDbOffsetContext loadOffsetContext(Configuration configuration, Map<String, ?> offsets) {
return new MariaDbOffsetContext.Loader(new MariaDbConnectorConfig(configuration)).load(offsets);
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogSourceTypeInSchemaIT;
/**
* @author Chris Cranford
*/
public class SourceTypeInSchemaIT extends BinlogSourceTypeInSchemaIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogStreamingSourceIT;
/**
* @author Chris Cranford
*/
public class StreamingSourceIT extends BinlogStreamingSourceIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogTableAndColumnCommentIT;
/**
* @author Chris Cranford
*/
public class TableAndColumnCommentIT extends BinlogTableAndColumnCommentIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogTableMaintenanceStatementsIT;
/**
* @author Chris Cranford
*/
public class TableMaintenanceStatementsIT extends BinlogTableMaintenanceStatementsIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogTimestampColumnIT;
/**
* @author Chris Cranford
*/
public class TimestampColumnIT extends BinlogTimestampColumnIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,19 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.config.Field;
import io.debezium.connector.binlog.BinlogTinyIntIT;
/**
* @author Chris Cranford
*/
public class TinyIntIT extends BinlogTinyIntIT<MariaDbConnector> implements MariaDbCommon {
@Override
protected Field getSnapshotLockingField() {
return MariaDbConnectorConfig.SNAPSHOT_LOCKING_MODE;
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogTopicNameSanitizationIT;
/**
* @author Chris Cranford
*/
public class TopicNameSanitizationIT extends BinlogTopicNameSanitizationIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogTopicNamingStrategyIT;
/**
* @author Chris Cranford
*/
public class TopicNamingStrategyIT extends BinlogTopicNamingStrategyIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogTransactionMetadataIT;
/**
* @author Chris Cranford
*/
public class TransactionMetadataIT extends BinlogTransactionMetadataIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogTransactionPayloadIT;
/**
* @author Chris Cranford
*/
public class TransactionPayloadIT extends BinlogTransactionPayloadIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogUnsignedIntegerIT;
/**
* @author Chris Cranford
*/
public class UnsignedIntegerIT extends BinlogUnsignedIntegerIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,47 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import java.time.temporal.TemporalAdjuster;
import io.debezium.config.CommonConnectorConfig.BinaryHandlingMode;
import io.debezium.config.CommonConnectorConfig.EventConvertingFailureHandlingMode;
import io.debezium.connector.binlog.BinlogConnectorConfig;
import io.debezium.connector.binlog.BinlogValueConvertersTest;
import io.debezium.connector.binlog.jdbc.BinlogValueConverters;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.connector.mariadb.util.MariaDbValueConvertersFactory;
import io.debezium.jdbc.JdbcValueConverters.BigIntUnsignedMode;
import io.debezium.jdbc.JdbcValueConverters.DecimalMode;
import io.debezium.jdbc.TemporalPrecisionMode;
import io.debezium.relational.RelationalDatabaseConnectorConfig;
import io.debezium.relational.ddl.DdlParser;
/**
* @author Chris Cranford
*/
public class ValueConvertersTest extends BinlogValueConvertersTest<MariaDbConnector> implements MariaDbCommon {
@Override
protected BinlogValueConverters getValueConverters(DecimalMode decimalMode,
TemporalPrecisionMode temporalPrecisionMode,
BigIntUnsignedMode bigIntUnsignedMode,
BinaryHandlingMode binaryHandlingMode,
TemporalAdjuster temporalAdjuster,
EventConvertingFailureHandlingMode eventConvertingFailureHandlingMode) {
return new MariaDbValueConvertersFactory().create(
RelationalDatabaseConnectorConfig.DecimalHandlingMode.parse(decimalMode.name()),
temporalPrecisionMode,
BinlogConnectorConfig.BigIntUnsignedHandlingMode.parse(bigIntUnsignedMode.name()),
binaryHandlingMode,
temporalAdjuster,
eventConvertingFailureHandlingMode);
}
@Override
protected DdlParser getDdlParser() {
return new MariaDbAntlrDdlParser();
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb;
import io.debezium.connector.binlog.BinlogYearIT;
/**
* @author Chris Cranford
*/
public class YearIT extends BinlogYearIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,258 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.rest;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.Matchers.notNullValue;
import java.util.Locale;
import java.util.Map;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.connector.mariadb.MariaDbConnectorConfig;
import io.debezium.connector.mariadb.Module;
import io.debezium.storage.kafka.history.KafkaSchemaHistory;
import io.debezium.testing.testcontainers.Connector;
import io.debezium.testing.testcontainers.ConnectorConfiguration;
import io.debezium.testing.testcontainers.testhelper.TestInfrastructureHelper;
import io.restassured.http.ContentType;
/**
* @author Chris Cranford
*/
public class DebeziumMariaDbConnectorResourceIT {
@BeforeClass
public static void checkCondition() {
Assume.assumeThat(
"Skipping DebeziumMariaDbConnectorResourceIT tests when assembly profile is not active!",
System.getProperty("isAssemblyProfileActive", "false"),
is("true"));
}
@Before
public void start() {
TestInfrastructureHelper.setupDebeziumContainer(Module.version(), DebeziumMariaDbConnectRestExtension.class.getName());
TestInfrastructureHelper.startContainers(TestInfrastructureHelper.DATABASE.MARIADB);
}
@After
public void stop() {
TestInfrastructureHelper.stopContainers();
}
@Test
public void testValidConnection() {
ConnectorConfiguration config = getMariaDbConnectorConfiguration(1);
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when().contentType(ContentType.JSON).accept(ContentType.JSON).body(config.toJson())
.put(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.VALIDATE_CONNECTION_ENDPOINT)
.then().log().all()
.statusCode(200)
.assertThat().body("status", equalTo("VALID"))
.body("validationResults.size()", is(0));
}
@Test
public void testInvalidHostnameConnection() {
ConnectorConfiguration config = getMariaDbConnectorConfiguration(1).with(MariaDbConnectorConfig.HOSTNAME.name(), "zzzzzzzzzz");
Locale.setDefault(new Locale("en", "US")); // to enforce errormessages in English
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when().contentType(ContentType.JSON).accept(ContentType.JSON).body(config.toJson())
.put(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.VALIDATE_CONNECTION_ENDPOINT)
.then().log().all()
.statusCode(200)
.assertThat().body("status", equalTo("INVALID"))
.body("validationResults.size()", is(1))
.rootPath("validationResults[0]")
.body("property", equalTo(MariaDbConnectorConfig.HOSTNAME.name()))
.body("message", startsWith("Unable to connect: Socket fail to connect"));
}
@Test
public void testInvalidConnection() {
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when().contentType(ContentType.JSON).accept(ContentType.JSON).body("{\"connector.class\": \"" + MariaDbConnector.class.getName() + "\"}")
.put(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.VALIDATE_CONNECTION_ENDPOINT)
.then().log().all()
.statusCode(200)
.assertThat().body("status", equalTo("INVALID"))
.body("validationResults.size()", is(4))
.body("validationResults",
hasItems(
Map.of("property", MariaDbConnectorConfig.USER.name(), "message", "The 'database.user' value is invalid: A value is required"),
Map.of("property", MariaDbConnectorConfig.TOPIC_PREFIX.name(), "message", "The 'topic.prefix' value is invalid: A value is required"),
Map.of("property", MariaDbConnectorConfig.SERVER_ID.name(), "message", "The 'database.server.id' value is invalid: A value is required"),
Map.of("property", MariaDbConnectorConfig.HOSTNAME.name(), "message", "The 'database.hostname' value is invalid: A value is required")));
}
@Test
public void testFiltersWithEmptyFilters() {
ConnectorConfiguration config = getMariaDbConnectorConfiguration(1);
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when().contentType(ContentType.JSON).accept(ContentType.JSON).body(config.toJson())
.put(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.VALIDATE_FILTERS_ENDPOINT)
.then().log().all()
.statusCode(200)
.assertThat().body("status", equalTo("VALID"))
.body("validationResults.size()", is(0))
.body("matchingCollections.size()", is(6))
.body("matchingCollections",
hasItems(
Map.of("namespace", "inventory", "name", "geom", "identifier", "inventory.geom"),
Map.of("namespace", "inventory", "name", "products_on_hand", "identifier", "inventory.products_on_hand"),
Map.of("namespace", "inventory", "name", "customers", "identifier", "inventory.customers"),
Map.of("namespace", "inventory", "name", "addresses", "identifier", "inventory.addresses"),
Map.of("namespace", "inventory", "name", "orders", "identifier", "inventory.orders"),
Map.of("namespace", "inventory", "name", "products", "identifier", "inventory.products")));
}
@Test
public void testFiltersWithValidTableIncludeList() {
ConnectorConfiguration config = getMariaDbConnectorConfiguration(1)
.with("table.include.list", "inventory\\.product.*");
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when().contentType(ContentType.JSON).accept(ContentType.JSON).body(config.toJson())
.put(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.VALIDATE_FILTERS_ENDPOINT)
.then().log().all()
.statusCode(200)
.assertThat().body("status", equalTo("VALID"))
.body("validationResults.size()", is(0))
.body("matchingCollections.size()", is(2))
.body("matchingCollections",
hasItems(
Map.of("namespace", "inventory", "name", "products_on_hand", "identifier", "inventory.products_on_hand"),
Map.of("namespace", "inventory", "name", "products", "identifier", "inventory.products")));
}
@Test
public void testFiltersWithValidDatabaseIncludeList() {
ConnectorConfiguration config = getMariaDbConnectorConfiguration(1)
.with("database.include.list", "inventory");
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when().contentType(ContentType.JSON).accept(ContentType.JSON).body(config.toJson())
.put(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.VALIDATE_FILTERS_ENDPOINT)
.then().log().all()
.statusCode(200)
.assertThat().body("status", equalTo("VALID"))
.body("validationResults.size()", is(0))
.body("matchingCollections.size()", is(6))
.body("matchingCollections",
hasItems(
Map.of("namespace", "inventory", "name", "geom", "identifier", "inventory.geom"),
Map.of("namespace", "inventory", "name", "products_on_hand", "identifier", "inventory.products_on_hand"),
Map.of("namespace", "inventory", "name", "customers", "identifier", "inventory.customers"),
Map.of("namespace", "inventory", "name", "addresses", "identifier", "inventory.addresses"),
Map.of("namespace", "inventory", "name", "orders", "identifier", "inventory.orders"),
Map.of("namespace", "inventory", "name", "products", "identifier", "inventory.products")));
}
@Test
public void testFiltersWithInvalidDatabaseIncludeListPattern() {
ConnectorConfiguration config = getMariaDbConnectorConfiguration(1)
.with("database.include.list", "+");
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when().contentType(ContentType.JSON).accept(ContentType.JSON).body(config.toJson())
.put(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.VALIDATE_FILTERS_ENDPOINT)
.then().log().all()
.statusCode(200)
.assertThat().body("status", equalTo("INVALID"))
.body("matchingCollections.size()", is(0))
.body("validationResults.size()", is(1))
.rootPath("validationResults[0]")
.body("property", equalTo("database.include.list"))
.body("message", equalTo(
"The 'database.include.list' value is invalid: A comma-separated list of valid regular expressions is expected, but Dangling meta character '+' near index 0\n+\n^"));
}
@Test
public void testFiltersWithInvalidDatabaseExcludeListPattern() {
ConnectorConfiguration config = getMariaDbConnectorConfiguration(1)
.with("database.exclude.list", "+");
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when().contentType(ContentType.JSON).accept(ContentType.JSON).body(config.toJson())
.put(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.VALIDATE_FILTERS_ENDPOINT)
.then().log().all()
.statusCode(200)
.assertThat().body("status", equalTo("INVALID"))
.body("matchingCollections.size()", is(0))
.body("validationResults.size()", is(1))
.rootPath("validationResults[0]")
.body("property", equalTo("database.exclude.list"))
.body("message", equalTo(
"The 'database.exclude.list' value is invalid: A comma-separated list of valid regular expressions is expected, but Dangling meta character '+' near index 0\n+\n^"));
}
@Test
public void testMetricsEndpoint() throws InterruptedException {
ConnectorConfiguration config = getMariaDbConnectorConfiguration(1);
var connectorName = "my-mariadb-connector";
TestInfrastructureHelper.getDebeziumContainer().registerConnector(
connectorName,
config);
TestInfrastructureHelper.getDebeziumContainer().ensureConnectorState(connectorName, Connector.State.RUNNING);
TestInfrastructureHelper.waitForConnectorTaskStatus(connectorName, 0, Connector.State.RUNNING);
TestInfrastructureHelper.getDebeziumContainer().waitForStreamingRunning("mariadb", config.asProperties().getProperty("topic.prefix"));
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when().contentType(ContentType.JSON).accept(ContentType.JSON).body(config.toJson())
.get(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.CONNECTOR_METRICS_ENDPOINT, connectorName)
.then().log().all()
.statusCode(200)
.body("name", equalTo(connectorName))
.body("connector.metrics.Connected", equalTo("true"))
.body("tasks[0].id", equalTo(0))
.body("tasks[0].namespaces[0].metrics.MilliSecondsSinceLastEvent", equalTo("0"))
.body("tasks[0].namespaces[0].metrics.TotalNumberOfEventsSeen", is(notNullValue()));
}
public static ConnectorConfiguration getMariaDbConnectorConfiguration(int id, String... options) {
final ConnectorConfiguration config = ConnectorConfiguration.forJdbcContainer(TestInfrastructureHelper.getMariaDbContainer())
.with(MariaDbConnectorConfig.USER.name(), "debezium")
.with(MariaDbConnectorConfig.PASSWORD.name(), "dbz")
.with(MariaDbConnectorConfig.SNAPSHOT_MODE.name(), "never") // temporarily disable snapshot mode globally until we can check if connectors inside testcontainers are in SNAPSHOT or STREAMING mode (wait for snapshot finished!)
.with(MariaDbConnectorConfig.TOPIC_PREFIX.name(), "dbserver" + id)
.with(KafkaSchemaHistory.BOOTSTRAP_SERVERS.name(), TestInfrastructureHelper.KAFKA_HOSTNAME + ":9092")
.with(KafkaSchemaHistory.TOPIC.name(), "dbhistory.inventory")
.with(MariaDbConnectorConfig.SERVER_ID.name(), Long.valueOf(5555 + id - 1))
// basic container does not support SSL out of the box
.with(MariaDbConnectorConfig.SSL_MODE.name(), "disabled");
if (options != null && options.length > 0) {
for (int i = 0; i < options.length; i += 2) {
config.with(options[i], options[i + 1]);
}
}
return config;
}
}

View File

@ -1,75 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.rest;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasKey;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.connector.mariadb.Module;
import io.debezium.testing.testcontainers.testhelper.TestInfrastructureHelper;
/**
* @author Chris Cranford
*/
public class DebeziumMariaDbConnectorResourceNoDatabaseIT {
@BeforeClass
public static void checkCondition() {
Assume.assumeThat(
"Skipping DebeziumMariaDbConnectorResourceIT tests when assembly profile is not active!",
System.getProperty("isAssemblyProfileActive", "false"),
is("true"));
}
@Before
public void start() {
TestInfrastructureHelper.setupDebeziumContainer(Module.version(), DebeziumMariaDbConnectRestExtension.class.getName());
TestInfrastructureHelper.startContainers(TestInfrastructureHelper.DATABASE.NONE);
}
@After
public void stop() {
TestInfrastructureHelper.stopContainers();
}
@Test
public void testVersionEndpoint() {
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when()
.get(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.VERSION_ENDPOINT)
.then().log().all()
.statusCode(200)
.body(is(Module.version()));
}
@Test
public void testSchemaEndpoint() {
given()
.port(TestInfrastructureHelper.getDebeziumContainer().getFirstMappedPort())
.when()
.get(DebeziumMariaDbConnectorResource.BASE_PATH + DebeziumMariaDbConnectorResource.SCHEMA_ENDPOINT)
.then().log().all()
.statusCode(200)
.body("components.schemas.size()", is(1))
.rootPath("components.schemas.values()[0]")
.body("title", is("Debezium MariaDB Connector"))
.body("properties.isEmpty()", is(false))
.body("x-connector-id", is("mariadb"))
.body("x-version", is(Module.version()))
.body("x-className", is(MariaDbConnector.class.getName()))
.body("properties", hasKey("topic.prefix"))
.body("properties", hasKey("database.server.id"))
.body("properties", hasKey("snapshot.mode"));
}
}

View File

@ -1,123 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.util;
import java.sql.SQLException;
import java.util.Map;
import io.debezium.connector.binlog.util.BinlogTestConnection;
import io.debezium.jdbc.JdbcConfiguration;
import io.debezium.jdbc.JdbcConnection;
/**
* @author Chris Cranford
*/
public class MariaDbTestConnection extends BinlogTestConnection {
protected static ConnectionFactory FACTORY = JdbcConnection.patternBasedFactory("jdbc:mariadb://${hostname}:${port}/${dbname}");
/**
* Create a new instance with the given configuration.
*
* @param config the configuration; may not be null
*/
public MariaDbTestConnection(JdbcConfiguration config) {
super(config, FACTORY);
}
@Override
public boolean isGtidEnabled() {
return true;
}
@Override
public boolean isMariaDb() {
return true;
}
@Override
public boolean isMySQL5() {
return false;
}
@Override
public boolean isPercona() {
return false;
}
@Override
public String currentDateTimeDefaultOptional(String isoString) {
return null;
}
@Override
public void setBinlogCompressionOff() throws SQLException {
execute("set global log_bin_compress=OFF;");
}
@Override
public void setBinlogCompressionOn() throws SQLException {
execute("set global log_bin_compress=ON;");
}
@Override
public void setBinlogRowQueryEventsOff() throws SQLException {
execute("set binlog_annotate_row_events=OFF;");
}
@Override
public void setBinlogRowQueryEventsOn() throws SQLException {
execute("set binlog_annotate_row_events=ON;");
}
@Override
public boolean isCurrentDateTimeDefaultGenerated() {
return false;
}
/**
* Obtain a connection instance to the named test database.
*
* @param databaseName the database name
* @return the connection instance; never null
*/
public static MariaDbTestConnection forTestDatabase(String databaseName) {
return new MariaDbTestConnection(getDefaultJdbcConfig(databaseName).build());
}
/**
* Obtain a connection instance to the named test database.
*
*
* @param databaseName the name of the test database
* @param queryTimeout the seconds to wait for query execution
* @return the connection instance; never null
*/
public static MariaDbTestConnection forTestDatabase(String databaseName, int queryTimeout) {
return new MariaDbTestConnection(getDefaultJdbcConfig(databaseName)
.withQueryTimeoutMs(queryTimeout)
.build());
}
/**
* Obtain a connection instance to the named test database.
*
* @param databaseName the name of the test database
* @param urlProperties url properties
* @return the connection instance; never null
*/
public static MariaDbTestConnection forTestDatabase(String databaseName, Map<String, Object> urlProperties) {
final JdbcConfiguration.Builder builder = getDefaultJdbcConfig(databaseName);
urlProperties.forEach(builder::with);
return new MariaDbTestConnection(builder.build());
}
public static MariaDbTestConnection forTestReplicaDatabase(String databaseName) {
return new MariaDbTestConnection(getReplicaJdbcConfig(databaseName).build());
}
}

View File

@ -1,19 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.util;
import io.debezium.connector.binlog.util.BinlogTestConnection;
import io.debezium.connector.binlog.util.TestConnectionProvider;
/**
* @author Chris Cranford
*/
public class MariaDbTestConnectionProvider implements TestConnectionProvider {
@Override
public BinlogTestConnection forTestDatabase(String databaseName) {
return MariaDbTestConnection.forTestDatabase(databaseName);
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.util;
import java.util.Map;
import java.util.Random;
import io.debezium.connector.binlog.util.UniqueDatabase;
import io.debezium.jdbc.JdbcConnection;
/**
* An implementation of {@link UniqueDatabase} for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbUniqueDatabase extends UniqueDatabase {
public MariaDbUniqueDatabase(String serverName, String databaseName) {
this(serverName, databaseName, Integer.toUnsignedString(new Random().nextInt(), 36), null);
}
public MariaDbUniqueDatabase(String serverName, String databaseName, String identifier, String charSet) {
super(serverName, databaseName, identifier, charSet);
}
@Override
protected JdbcConnection forTestDatabase(String databaseName, Map<String, Object> urlProperties) {
return MariaDbTestConnection.forTestDatabase(databaseName, urlProperties);
}
}

View File

@ -1,22 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.util;
import io.debezium.connector.binlog.util.UniqueDatabase;
import io.debezium.connector.binlog.util.UniqueDatabaseProvider;
/**
* A Java ServiceLoader contract of {@link UniqueDatabaseProvider} to supply the test suite with the class
* reference to the MariaDB connector's specific {@link UniqueDatabase} implementation.
*
* @author Chris Cranford
*/
public class MariaDbUniqueDatabaseProvider implements UniqueDatabaseProvider {
@Override
public Class<? extends UniqueDatabase> getUniqueDatabase() {
return MariaDbUniqueDatabase.class;
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.util;
import java.time.temporal.TemporalAdjuster;
import io.debezium.config.Configuration;
import io.debezium.connector.binlog.util.BinlogValueConvertersFactory;
import io.debezium.connector.mariadb.MariaDbConnectorConfig;
import io.debezium.connector.mariadb.jdbc.MariaDbValueConverters;
/**
* Implementation of {@link BinlogValueConvertersFactory} for MariaDB.
*
* @author Chris Cranford
*/
public class MariaDbValueConvertersFactory implements BinlogValueConvertersFactory<MariaDbValueConverters> {
@Override
public MariaDbValueConverters create(Configuration configuration, TemporalAdjuster temporalAdjuster) {
final MariaDbConnectorConfig connectorConfig = new MariaDbConnectorConfig(configuration);
return new MariaDbValueConverters(
connectorConfig.getDecimalMode(),
connectorConfig.getTemporalPrecisionMode(),
connectorConfig.getBigIntUnsignedHandlingMode().asBigIntUnsignedMode(),
connectorConfig.binaryHandlingMode(),
temporalAdjuster,
connectorConfig.getEventConvertingFailureHandlingMode(),
connectorConfig.getServiceRegistry());
}
}

View File

@ -1,17 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.connector.mariadb.zzz;
import io.debezium.connector.binlog.zzz.ZZZBinlogGtidSetIT;
import io.debezium.connector.mariadb.MariaDbCommon;
import io.debezium.connector.mariadb.MariaDbConnector;
/**
* @author Chris Cranford
*/
public class ZZZMariaDbGtidSetIT extends ZZZBinlogGtidSetIT<MariaDbConnector> implements MariaDbCommon {
}

View File

@ -1,20 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.relational.history;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.relational.ddl.DdlParser;
/**
* @author Chris Cranford
*/
public class FileSchemaHistoryTest extends AbstractFileSchemaHistoryTest<MariaDbConnector> {
@Override
protected DdlParser getDdlParser() {
return new MariaDbAntlrDdlParser();
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.relational.history;
import io.debezium.config.Configuration;
import io.debezium.connector.mariadb.MariaDbConnectorConfig;
import io.debezium.connector.mariadb.MariaDbOffsetContext;
import io.debezium.connector.mariadb.MariaDbPartition;
import io.debezium.connector.mariadb.MariaDbReadOnlyIncrementalSnapshotContext;
import io.debezium.connector.mariadb.SourceInfo;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.pipeline.txmetadata.TransactionContext;
import io.debezium.relational.ddl.DdlParser;
/**
* @author Chris Cranford
*/
public class KafkaSchemaHistoryTest extends AbstractKafkaSchemaHistoryTest<MariaDbPartition, MariaDbOffsetContext> {
@Override
protected MariaDbPartition createPartition(String serverName, String databaseName) {
return new MariaDbPartition(serverName, databaseName);
}
@Override
protected MariaDbOffsetContext createOffsetContext(Configuration config) {
return new MariaDbOffsetContext(
false,
true,
new TransactionContext(),
new MariaDbReadOnlyIncrementalSnapshotContext<>(),
new SourceInfo(new MariaDbConnectorConfig(config)));
}
@Override
protected DdlParser getDdlParser() {
return new MariaDbAntlrDdlParser();
}
}

View File

@ -1,20 +0,0 @@
/*
* Copyright Debezium Authors.
*
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package io.debezium.relational.history;
import io.debezium.connector.mariadb.MariaDbConnector;
import io.debezium.connector.mariadb.antlr.MariaDbAntlrDdlParser;
import io.debezium.relational.ddl.DdlParser;
/**
* @author Chris Cranford
*/
public class MemorySchemaHistoryTest extends AbstractMemorySchemaHistoryTest<MariaDbConnector> {
@Override
protected DdlParser getDdlParser() {
return new MariaDbAntlrDdlParser();
}
}

View File

@ -1,29 +0,0 @@
ARG BASE_IMAGE
ARG DEBEZIUM_VERSION
FROM ${BASE_IMAGE}
ARG DEBEZIUM_VERSION
ENV CONNECTOR="mariadb"
RUN echo "Installing Debezium connectors version: ${DEBEZIUM_VERSION}" ; \
MAVEN_REPOSITORY="https://repo1.maven.org/maven2/io/debezium" ; \
if [[ "${DEBEZIUM_VERSION}" == *-SNAPSHOT ]] ; then \
MAVEN_REPOSITORY="https://s01.oss.sonatype.org/content/repositories/snapshots/io/debezium" ; \
fi ; \
CONNECTOR_VERSION="${DEBEZIUM_VERSION}" ; \
for PACKAGE in {scripting,}; do \
local CONNECTOR_VERSION="${DEBEZIUM_VERSION}" ; \
if [[ "${DEBEZIUM_VERSION}" == *-SNAPSHOT ]] ; then \
CONNECTOR_VERSION=$(curl --silent -fSL "${MAVEN_REPOSITORY}/debezium-${PACKAGE}/${DEBEZIUM_VERSION}/maven-metadata.xml" | awk -F'<[^>]+>' '/<extension>tar.gz<\/extension>/ {getline; print $2; exit}'); \
fi ; \
echo "Downloading and installing debezium-${PACKAGE}-${CONNECTOR_VERSION}.tar.gz ..." ; \
curl --silent -fSL -o /tmp/package.tar.gz "${MAVEN_REPOSITORY}/debezium-${PACKAGE}/${DEBEZIUM_VERSION}/debezium-${PACKAGE}-${CONNECTOR_VERSION}.tar.gz" && \
echo "Extracting debezium-${PACKAGE}-${CONNECTOR_VERSION}.tar.gz ..." && \
tar -xzf /tmp/package.tar.gz -C $EXTERNAL_LIBS_DIR && \
echo "Successfully installed debezium-${PACKAGE}-${CONNECTOR_VERSION}!" ; \
rm -f /tmp/package.tar.gz ; \
done
COPY --chown=kafka:kafka debezium-connector-${CONNECTOR}-${DEBEZIUM_VERSION}-plugin.tar.gz /tmp/plugin.tar.gz
RUN tar -xvzf /tmp/plugin.tar.gz -C ${KAFKA_CONNECT_PLUGINS_DIR}/ ; rm -f /tmp/plugin.tar.gz

View File

@ -1 +0,0 @@
io.debezium.connector.mariadb.util.MariaDbTestConnectionProvider

View File

@ -1 +0,0 @@
io.debezium.connector.mariadb.util.MariaDbUniqueDatabaseProvider

View File

@ -1 +0,0 @@
io.debezium.connector.mariadb.CustomTestSnapshot

View File

@ -1 +0,0 @@
io.debezium.connector.mariadb.CustomTestSnapshot

View File

@ -1,49 +0,0 @@
# For advice on how to change settings please see
# https://dev.mysql.com/doc/refman/8.2/en/server-configuration-defaults.html
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
skip-host-cache
skip-name-resolve
#datadir=/var/lib/mysql
#socket=/var/lib/mysql/mysql.sock
#secure-file-priv=/var/lib/mysql-files
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#log-error=/var/log/mysqld.log
#pid-file=/var/run/mysqld/mysqld.pid
# ----------------------------------------------
# Enable the binlog for replication & CDC
# ----------------------------------------------
# Enable binary replication log and set the prefix, expiration, and log format.
# The prefix is arbitrary, expiration can be short for integration tests but would
# be longer on a production system. Row-level info is required for ingest to work.
# Server ID is required, but this will vary on production systems
server-id = 223344
log_bin = mysql-bin
binlog_format = row
# Configures the amount of table metadata added to the binary log when using row-based logging
binlog_row_metadata = FULL
default_authentication_plugin = mysql_native_password
binlog_expire_logs_seconds = 86400

View File

@ -1,58 +0,0 @@
<configuration>
<appender name="CONSOLE"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} %-5p %X{dbz.connectorType}|%X{dbz.connectorName}|%X{dbz.taskId}|%X{dbz.connectorContext}|%X{dbz.databaseName} %m [%c]%n</pattern>
</encoder>
</appender>
<root level="warn">
<appender-ref ref="CONSOLE" />
</root>
<!-- Set up the default logging to be INFO level, then override specific
units -->
<logger name="io.debezium" level="info" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<!-- Reduced to manage verbosity on CI -->
<logger name="io.debezium.connector.mariadb.MariaDbSnapshotChangeEventSource" level="debug" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<logger name="io.debezium.connector.binlog.BinlogSnapshotChangeEventSource" level="debug" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<logger name="io.debezium.relational.RelationalSnapshotChangeEventSource" level="debug" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<!-- This is to reduce the "context is null" error -->
<logger name="io.debezium.connector.binlog.BinlogReadOnlyIncrementalSnapshotChangeEventSource" level="error" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<logger
name="io.debezium.embedded.EmbeddedWorkerConfig"
level="warn" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<logger
name="org.reflections"
level="error" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<!-- For debug purpose -->
<logger
name="io.debezium.pipeline.ChangeEventSourceCoordinator"
level="off" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<logger
name="io.debezium.pipeline.EventDispatcher"
level="off" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
</configuration>

View File

@ -1,19 +0,0 @@
This directory contains the truststore (used for validating DB server certificate) and keystore (contains the client
certificate) for running the test suite with SSL enabled and two-way authentication.
The files are generated based on the certificates in src/test/resources/ssl-certs, which in turn were taken from the
MySQL container image (which generates them by default with a validity of 10 years, see /var/lib/mysql; the currently
used certificates were created on March 8 2022, i.e. expect SSL-enabled tests to fail after March 8 2032 due to the
expired certificates). The server used for SSL authentication testing uses those pre-generated certificates (see configuration in
src/test/docker/server-ssl/my.cnf) instead of generating new ones.
To regenerate the truststore/keystore files, run the following commands:
```
keytool -importcert -alias MySQLCACert -file debezium-connector-mysql/src/test/resources/ssl-certs/ca.pem -keystore debezium-connector-mysql/src/test/resources/ssl/truststore -storepass debezium -noprompt
```
```
openssl pkcs12 -export -in debezium-connector-mysql/src/test/resources/ssl-certs/client-cert.pem -inkey debezium-connector-mysql/src/test/resources/ssl-certs/client-key.pem -name "mysqlclient" -passout pass:debezium -out client-keystore.p12
keytool -importkeystore -srckeystore client-keystore.p12 -srcstoretype pkcs12 -srcstorepass debezium -destkeystore debezium-connector-mysql/src/test/resources/ssl/keystore -deststoretype pkcs12 -deststorepass debezium
```

1
debezium-examples Submodule

@ -0,0 +1 @@
Subproject commit a2a530bc390a9334c60d9409df714c9108e3708a