├── gradle.properties ├── settings.gradle.kts ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── master_push_workflow.yml │ ├── pull_request_workflow.yml │ ├── release_pr_workflow.yml │ ├── create_release.yml │ └── codeql-analysis.yml ├── src ├── test │ ├── resources │ │ ├── io.aiven.connect.jdbc.dialect │ │ │ ├── SybaseDatabaseDialectTest │ │ │ │ ├── drop_table-nonquoted.txt │ │ │ │ ├── drop_table-quoted.txt │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── drop_table_if_exists-nonquoted.txt │ │ │ │ ├── drop_table_if_exists-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── drop_table_with_schema_if_exists-nonquoted.txt │ │ │ │ ├── drop_table_with_schema_if_exists-quoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ ├── alter_table-quoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ ├── create_table-quoted.txt │ │ │ │ ├── upsert1-nonquoted.txt │ │ │ │ ├── upsert1-quoted.txt │ │ │ │ ├── upsert2-nonquoted.txt │ │ │ │ ├── upsert2-quoted.txt │ │ │ │ ├── upsert0-nonquoted.txt │ │ │ │ └── upsert0-quoted.txt │ │ │ ├── Db2DatabaseDialectTest │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── insert-nonquoted.txt │ │ │ │ ├── insert-quoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── update-nonquoted.txt │ │ │ │ ├── update-quoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── upsert_only_key_cols-nonquoted.txt │ │ │ │ ├── upsert_only_key_cols-quoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ ├── alter_table-quoted.txt │ │ │ │ ├── create_table-quoted.txt │ │ │ │ ├── upsert1-nonquoted.txt │ │ │ │ ├── upsert1-quoted.txt │ │ │ │ ├── upsert0-nonquoted.txt │ │ │ │ └── upsert0-quoted.txt │ │ │ ├── MySqlDatabaseDialectTest │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── insert-nonquoted.txt │ │ │ │ ├── insert-quoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── update-nonquoted.txt │ │ │ │ ├── update-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── upsert_only_key_cols-nonquoted.txt │ │ │ │ ├── upsert_only_key_cols-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── upsert1-nonquoted.txt │ │ │ │ ├── upsert1-quoted.txt │ │ │ │ ├── upsert0-nonquoted.txt │ │ │ │ ├── upsert0-quoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ ├── alter_table-quoted.txt │ │ │ │ └── create_table-quoted.txt │ │ │ ├── VerticaDatabaseDialectTest │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ ├── create_table-quoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ └── alter_table-quoted.txt │ │ │ ├── DerbyDatabaseDialectTest │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── insert-nonquoted.txt │ │ │ │ ├── insert-quoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── update-nonquoted.txt │ │ │ │ ├── update-quoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── upsert_only_key_cols-nonquoted.txt │ │ │ │ ├── upsert_only_key_cols-quoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ ├── create_table-quoted.txt │ │ │ │ ├── alter_table-quoted.txt │ │ │ │ ├── upsert1-nonquoted.txt │ │ │ │ ├── upsert1-quoted.txt │ │ │ │ ├── upsert0-nonquoted.txt │ │ │ │ └── upsert0-quoted.txt │ │ │ ├── PostgreSqlDatabaseDialectTest │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── update0-nonquoted.txt │ │ │ │ ├── insert0-nonquoted.txt │ │ │ │ ├── update0-quoted.txt │ │ │ │ ├── insert0-quoted.txt │ │ │ │ ├── upsert2-nonquoted.txt │ │ │ │ ├── upsert2-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── upsert1-nonquoted.txt │ │ │ │ ├── upsert1-quoted.txt │ │ │ │ ├── upsert0-nonquoted.txt │ │ │ │ ├── upsert_cast_types0-nonquoted.txt │ │ │ │ ├── upsert_cast_types0-quoted.txt │ │ │ │ ├── upsert0-quoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ ├── alter_table-quoted.txt │ │ │ │ └── create_table-quoted.txt │ │ │ ├── SqlServerDatabaseDialectTest │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── create_table_one_col_one_varchar_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_varchar_pk-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ ├── alter_table-quoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ ├── create_table-quoted.txt │ │ │ │ ├── upsert1-nonquoted.txt │ │ │ │ ├── upsert1-quoted.txt │ │ │ │ ├── upsert2-nonquoted.txt │ │ │ │ ├── upsert2-quoted.txt │ │ │ │ ├── upsert0-nonquoted.txt │ │ │ │ └── upsert0-quoted.txt │ │ │ ├── SqliteDatabaseDialectTest │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── upsert1-nonquoted.txt │ │ │ │ ├── upsert1-quoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── upsert0-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── upsert0-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ ├── create_table-quoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ └── alter_table-quoted.txt │ │ │ ├── SapHanaDatabaseDialectTest │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── upsert1-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── upsert1-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── upsert0-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── upsert0-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ ├── alter_table-quoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ └── create_table-quoted.txt │ │ │ └── OracleDatabaseDialectTest │ │ │ │ ├── alter_add_one_col-nonquoted.txt │ │ │ │ ├── alter_add_one_col-quoted.txt │ │ │ │ ├── create_table_one_col_no_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_no_pk-quoted.txt │ │ │ │ ├── create_table_one_col_one_pk-nonquoted.txt │ │ │ │ ├── create_table_one_col_one_pk-quoted.txt │ │ │ │ ├── alter_add_two_cols-nonquoted.txt │ │ │ │ ├── alter_add_two_cols-quoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-nonquoted.txt │ │ │ │ ├── create_table_three_cols_two_pks-quoted.txt │ │ │ │ ├── alter_table-nonquoted.txt │ │ │ │ ├── alter_table-quoted.txt │ │ │ │ ├── create_table-nonquoted.txt │ │ │ │ ├── create_table-quoted.txt │ │ │ │ ├── upsert1-nonquoted.txt │ │ │ │ ├── upsert1-quoted.txt │ │ │ │ ├── upsert0-nonquoted.txt │ │ │ │ └── upsert0-quoted.txt │ │ ├── META-INF │ │ │ └── services │ │ │ │ └── io.aiven.connect.jdbc.dialect.DatabaseDialectProvider │ │ └── log4j.properties │ └── java │ │ └── io │ │ └── aiven │ │ └── connect │ │ └── jdbc │ │ ├── dialect │ │ └── MockDatabaseDialect.java │ │ ├── util │ │ ├── TimeZoneValidatorTest.java │ │ ├── CachedConnectionProviderTest.java │ │ └── DatabaseHelper.java │ │ ├── source │ │ ├── MockTime.java │ │ ├── NumericMappingConfigTest.java │ │ └── JdbcSourceTaskConfigTest.java │ │ └── sink │ │ ├── DbStructureTest.java │ │ └── SqliteHelper.java ├── main │ ├── resources │ │ ├── META-INF │ │ │ └── services │ │ │ │ ├── org.apache.kafka.connect.sink.SinkConnector │ │ │ │ ├── org.apache.kafka.connect.source.SourceConnector │ │ │ │ └── io.aiven.connect.jdbc.dialect.DatabaseDialectProvider │ │ └── jdbc-connector-for-apache-kafka-version.properties │ └── java │ │ └── io │ │ └── aiven │ │ └── connect │ │ └── jdbc │ │ ├── util │ │ ├── CollectionUtils.java │ │ ├── BytesUtil.java │ │ ├── Version.java │ │ ├── TimeZoneValidator.java │ │ ├── StringUtils.java │ │ ├── ConnectionProvider.java │ │ ├── DateTimeUtils.java │ │ ├── ColumnId.java │ │ ├── TableDefinition.java │ │ └── TableDefinitions.java │ │ ├── source │ │ ├── JdbcSourceConnectorConstants.java │ │ ├── SourceConnectionProvider.java │ │ ├── JdbcSourceTaskConfig.java │ │ ├── OffsetProtocols.java │ │ ├── ColumnMapping.java │ │ └── TimestampIncrementingOffset.java │ │ ├── sink │ │ └── metadata │ │ │ ├── SchemaPair.java │ │ │ └── SinkRecordField.java │ │ ├── config │ │ └── DatabaseDialectRecommender.java │ │ ├── JdbcSinkConnector.java │ │ └── dialect │ │ ├── DropOptions.java │ │ └── VerticaDatabaseDialect.java └── integrationTest │ ├── resources │ └── log4j.properties │ └── java │ └── io │ └── aiven │ └── kafka │ └── connect │ └── jdbc │ ├── SchemaRegistryContainer.java │ ├── oracle │ └── AbstractOracleIT.java │ └── postgres │ └── AbstractPostgresIT.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── checkstyle ├── java.header └── suppressions.xml ├── NOTICE ├── cve-list.md ├── licenses ├── LICENSE-mssql-jdbc-8-2-1.txt └── LICENSE-postgresql-42-2-10.txt ├── config ├── sink-quickstart-sqlite.properties └── source-quickstart-sqlite.properties ├── licenses.html ├── SECURITY.md ├── README.md ├── gradlew.bat └── CONTRIBUTING.md /gradle.properties: -------------------------------------------------------------------------------- 1 | group=io.aiven 2 | version=6.12.0-SNAPSHOT 3 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "jdbc-connector-for-apache-kafka" 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @aiven-open/team-helpful-husky @aiven-open/aiven-open-source 2 | -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/drop_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | DROP TABLE myTable -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/drop_table-quoted.txt: -------------------------------------------------------------------------------- 1 | DROP TABLE "myTable" -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/org.apache.kafka.connect.sink.SinkConnector: -------------------------------------------------------------------------------- 1 | io.aiven.connect.jdbc.JdbcSinkConnector -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/org.apache.kafka.connect.source.SourceConnector: -------------------------------------------------------------------------------- 1 | io.aiven.connect.jdbc.JdbcSourceConnector -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aiven-Open/jdbc-connector-for-apache-kafka/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/test/resources/META-INF/services/io.aiven.connect.jdbc.dialect.DatabaseDialectProvider: -------------------------------------------------------------------------------- 1 | io.aiven.connect.jdbc.dialect.MockDatabaseDialect$Provider -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD newcol1 INTEGER NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD "newcol1" INTEGER NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD newcol1 INT NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE `myTable` ADD `newcol1` INT NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD newcol1 INT NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD "newcol1" INT NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/insert-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO customers(age,firstName,lastName) VALUES(?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD newcol1 INTEGER NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD "newcol1" INTEGER NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/insert-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO customers(age,firstName,lastName) VALUES(?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/insert-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO customers(age,firstName,lastName) VALUES(?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD newcol1 INT NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD "newcol1" INT NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD 2 | newcol1 int NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD newcol1 INTEGER NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD "newcol1" INTEGER NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD 2 | newcol1 int NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD 2 | "newcol1" int NULL -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gradle" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/insert-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO "customers"("age","firstName","lastName") VALUES(?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/insert-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO "customers"("age","firstName","lastName") VALUES(?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/insert-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO `customers`(`age`,`firstName`,`lastName`) VALUES(?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD( 2 | newcol1 INTEGER NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD( 2 | "newcol1" INTEGER NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE [myTable] ADD 2 | [newcol1] int NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | col1 INTEGER NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "col1" INTEGER NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/update-nonquoted.txt: -------------------------------------------------------------------------------- 1 | UPDATE customers SET age = ?, firstName = ?, lastName = ? WHERE id = ? -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | col1 INTEGER NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | col1 INT NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE `myTable` ( 2 | `col1` INT NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/alter_add_one_col-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD( 2 | newcol1 NUMBER(10,0) NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/alter_add_one_col-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD( 2 | "newcol1" NUMBER(10,0) NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | col1 int NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | col1 int NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "col1" int NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | col1 INT NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "col1" INT NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "col1" INTEGER NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/update-nonquoted.txt: -------------------------------------------------------------------------------- 1 | UPDATE customers SET age = ?, firstName = ?, lastName = ? WHERE id = ? -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/update-nonquoted.txt: -------------------------------------------------------------------------------- 1 | UPDATE customers SET age = ?, firstName = ?, lastName = ? WHERE id = ? -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | col1 INT NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "col1" INT NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/upsert1-nonquoted.txt: -------------------------------------------------------------------------------- 1 | UPSERT tableA(col1,col2,col3,col4) VALUES(?,?,?,?) WITH PRIMARY KEY -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE [myTable] ( 2 | [col1] int NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | col1 INTEGER NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "col1" INTEGER NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/update-quoted.txt: -------------------------------------------------------------------------------- 1 | UPDATE "customers" SET "age" = ?, "firstName" = ?, "lastName" = ? WHERE "id" = ? -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/update-quoted.txt: -------------------------------------------------------------------------------- 1 | UPDATE "customers" SET "age" = ?, "firstName" = ?, "lastName" = ? WHERE "id" = ? -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/update-quoted.txt: -------------------------------------------------------------------------------- 1 | UPDATE `customers` SET `age` = ?, `firstName` = ?, `lastName` = ? WHERE `id` = ? -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | col1 NUMBER(10,0) NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "col1" NUMBER(10,0) NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/create_table_one_col_no_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE COLUMN TABLE myTable ( 2 | col1 INTEGER NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/create_table_one_col_no_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE COLUMN TABLE "myTable" ( 2 | "col1" INTEGER NOT NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/upsert1-quoted.txt: -------------------------------------------------------------------------------- 1 | UPSERT "tableA"("col1","col2","col3","col4") VALUES(?,?,?,?) WITH PRIMARY KEY -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/upsert1-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT OR REPLACE INTO Book(author,title,ISBN,year,pages) VALUES(?,?,?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INTEGER NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable 2 | ADD newcol1 INT NULL, 3 | ADD newcol2 INT DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INT NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD 2 | newcol1 int NULL, 3 | newcol2 int DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/upsert1-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT OR REPLACE INTO "Book"("author","title","ISBN","year","pages") VALUES(?,?,?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD 2 | newcol1 int NULL, 3 | newcol2 int DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD 2 | "newcol1" int NULL, 3 | "newcol2" int DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 int NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INT NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INTEGER NOT NULL, 3 | PRIMARY KEY("pk1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INTEGER NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INTEGER NOT NULL, 3 | PRIMARY KEY("pk1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE `myTable` 2 | ADD `newcol1` INT NULL, 3 | ADD `newcol2` INT DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE `myTable` ( 2 | `pk1` INT NOT NULL, 3 | PRIMARY KEY(`pk1`)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable 2 | ADD newcol1 INT NULL, 3 | ADD newcol2 INT DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INT NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE [myTable] ADD 2 | [newcol1] int NULL, 3 | [newcol2] int DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 int NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE [myTable] ( 2 | [pk1] int NOT NULL, 3 | PRIMARY KEY([pk1])) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INTEGER NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/upsert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT OR REPLACE INTO myTable(id1,id2,columnA,columnB,columnC,columnD) VALUES(?,?,?,?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" int NOT NULL, 3 | PRIMARY KEY("pk1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INT NOT NULL, 3 | PRIMARY KEY("pk1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable 2 | ADD newcol1 INTEGER NULL, 3 | ADD newcol2 INTEGER DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 NUMBER(10,0) NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" 2 | ADD "newcol1" INT NULL, 3 | ADD "newcol2" INT DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INT NOT NULL, 3 | PRIMARY KEY("pk1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/update0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | UPDATE cast_types_table SET uuid_col=?::uuid,json_col=?::json,jsonb_col=?::jsonb WHERE pk = ? -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD( 2 | newcol1 INTEGER NULL, 3 | newcol2 INTEGER DEFAULT 42) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD( 2 | "newcol1" INTEGER NULL, 3 | "newcol2" INTEGER DEFAULT 42) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/upsert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | UPSERT myTable(id1,id2,columnA,columnB,columnC,columnD) VALUES(?,?,?,?,?,?) WITH PRIMARY KEY -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INTEGER NOT NULL, 3 | PRIMARY KEY("pk1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable | 2 | ADD newcol1 INTEGER NULL, 3 | ADD newcol2 INTEGER DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" | 2 | ADD "newcol1" INTEGER NULL, 3 | ADD "newcol2" INTEGER DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" 2 | ADD "newcol1" INTEGER NULL, 3 | ADD "newcol2" INTEGER DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/upsert_only_key_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | insert into actor(actor_id) values(?) on duplicate key update actor_id=values(actor_id) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" NUMBER(10,0) NOT NULL, 3 | PRIMARY KEY("pk1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/insert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO cast_types_table(pk,uuid_col,json_col,jsonb_col) VALUES(?,?::uuid,?::json,?::jsonb) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/update0-quoted.txt: -------------------------------------------------------------------------------- 1 | UPDATE "cast_types_table" SET uuid_col=?::uuid,json_col=?::json,jsonb_col=?::jsonb WHERE "pk" = ? -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/create_table_one_col_one_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE COLUMN TABLE myTable ( 2 | pk1 INTEGER NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/create_table_one_col_one_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE COLUMN TABLE "myTable" ( 2 | "pk1" INTEGER NOT NULL, 3 | PRIMARY KEY("pk1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/upsert0-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT OR REPLACE INTO "myTable"("id1","id2","columnA","columnB","columnC","columnD") VALUES(?,?,?,?,?,?) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/drop_table_if_exists-nonquoted.txt: -------------------------------------------------------------------------------- 1 | IF EXISTS (SELECT 1 FROM sysobjects WHERE name='myTable' AND type='U') DROP TABLE myTable -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/drop_table_if_exists-quoted.txt: -------------------------------------------------------------------------------- 1 | IF EXISTS (SELECT 1 FROM sysobjects WHERE name='myTable' AND type='U') DROP TABLE "myTable" -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/upsert_only_key_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | insert into `actor`(`actor_id`) values(?) on duplicate key update `actor_id`=values(`actor_id`) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD( 2 | newcol1 NUMBER(10,0) NULL, 3 | newcol2 NUMBER(10,0) DEFAULT 42) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD( 2 | "newcol1" NUMBER(10,0) NULL, 3 | "newcol2" NUMBER(10,0) DEFAULT 42) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/insert0-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO "cast_types_table"("pk","uuid_col","json_col","jsonb_col") VALUES(?,?::uuid,?::json,?::jsonb) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/upsert0-quoted.txt: -------------------------------------------------------------------------------- 1 | UPSERT "myTable"("id1","id2","columnA","columnB","columnC","columnD") VALUES(?,?,?,?,?,?) WITH PRIMARY KEY -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table_one_col_one_varchar_pk-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 varchar(900) NOT NULL, 3 | PRIMARY KEY(pk1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD newcol1 INT NULL 2 | ALTER TABLE myTable ADD newcol2 INT DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table_one_col_one_varchar_pk-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE [myTable] ( 2 | [pk1] varchar(900) NOT NULL, 3 | PRIMARY KEY([pk1])) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/alter_add_two_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD newcol1 INTEGER NULL 2 | ALTER TABLE myTable ADD newcol2 INTEGER DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD "newcol1" INT NULL 2 | ALTER TABLE "myTable" ADD "newcol2" INT DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/upsert2-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO Customer (id,name,salary,address) VALUES (?,?,?,?) ON CONFLICT (id,name,salary,address) DO NOTHING -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/alter_add_two_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD "newcol1" INTEGER NULL 2 | ALTER TABLE "myTable" ADD "newcol2" INTEGER DEFAULT 42 -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/upsert2-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO "Customer" ("id","name","salary","address") VALUES (?,?,?,?) ON CONFLICT ("id","name","salary","address") DO NOTHING -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INT NOT NULL, 3 | pk2 INT NOT NULL, 4 | col1 INT NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 int NOT NULL, 3 | pk2 int NOT NULL, 4 | col1 int NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 int NOT NULL, 3 | pk2 int NOT NULL, 4 | col1 int NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INT NOT NULL, 3 | pk2 INT NOT NULL, 4 | col1 INT NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE `myTable` ( 2 | `pk1` INT NOT NULL, 3 | `pk2` INT NOT NULL, 4 | `col1` INT NOT NULL, 5 | PRIMARY KEY(`pk1`,`pk2`)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INT NOT NULL, 3 | pk2 INT NOT NULL, 4 | col1 INT NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INTEGER NOT NULL, 3 | pk2 INTEGER NOT NULL, 4 | col1 INTEGER NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INTEGER NOT NULL, 3 | pk2 INTEGER NOT NULL, 4 | col1 INTEGER NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INT NOT NULL, 3 | "pk2" INT NOT NULL, 4 | "col1" INT NOT NULL, 5 | PRIMARY KEY("pk1","pk2")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE [myTable] ( 2 | [pk1] int NOT NULL, 3 | [pk2] int NOT NULL, 4 | [col1] int NOT NULL, 5 | PRIMARY KEY([pk1],[pk2])) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 INTEGER NOT NULL, 3 | pk2 INTEGER NOT NULL, 4 | col1 INTEGER NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" int NOT NULL, 3 | "pk2" int NOT NULL, 4 | "col1" int NOT NULL, 5 | PRIMARY KEY("pk1","pk2")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INT NOT NULL, 3 | "pk2" INT NOT NULL, 4 | "col1" INT NOT NULL, 5 | PRIMARY KEY("pk1","pk2")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INTEGER NOT NULL, 3 | "pk2" INTEGER NOT NULL, 4 | "col1" INTEGER NOT NULL, 5 | PRIMARY KEY("pk1","pk2")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/upsert_only_key_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into actor using (values(?)) as DAT(actor_id) on actor.actor_id=DAT.actor_id when not matched then insert(actor.actor_id) values(DAT.actor_id) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INTEGER NOT NULL, 3 | "pk2" INTEGER NOT NULL, 4 | "col1" INTEGER NOT NULL, 5 | PRIMARY KEY("pk1","pk2")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/upsert_only_key_cols-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into actor using (values(?)) as DAT(actor_id) on actor.actor_id=DAT.actor_id when not matched then insert(actor.actor_id) values(DAT.actor_id) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE COLUMN TABLE myTable ( 2 | pk1 INTEGER NOT NULL, 3 | pk2 INTEGER NOT NULL, 4 | col1 INTEGER NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" INTEGER NOT NULL, 3 | "pk2" INTEGER NOT NULL, 4 | "col1" INTEGER NOT NULL, 5 | PRIMARY KEY("pk1","pk2")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/create_table_three_cols_two_pks-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | pk1 NUMBER(10,0) NOT NULL, 3 | pk2 NUMBER(10,0) NOT NULL, 4 | col1 NUMBER(10,0) NOT NULL, 5 | PRIMARY KEY(pk1,pk2)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/upsert1-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO Customer (id,name,salary,address) VALUES (?,?,?,?) ON CONFLICT (id) DO UPDATE SET name=EXCLUDED.name,salary=EXCLUDED.salary,address=EXCLUDED.address -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/upsert_only_key_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "actor" using (values(?)) as DAT("actor_id") on "actor"."actor_id"=DAT."actor_id" when not matched then insert("actor"."actor_id") values(DAT."actor_id") -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/upsert1-nonquoted.txt: -------------------------------------------------------------------------------- 1 | insert into actor(actor_id,first_name,last_name,score) values(?,?,?,?) on duplicate key update first_name=values(first_name),last_name=values(last_name),score=values(score) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE COLUMN TABLE "myTable" ( 2 | "pk1" INTEGER NOT NULL, 3 | "pk2" INTEGER NOT NULL, 4 | "col1" INTEGER NOT NULL, 5 | PRIMARY KEY("pk1","pk2")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/upsert_only_key_cols-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "actor" using (values(?)) as DAT("actor_id") on "actor"."actor_id"=DAT."actor_id" when not matched then insert("actor"."actor_id") values(DAT."actor_id") -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/create_table_three_cols_two_pks-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "pk1" NUMBER(10,0) NOT NULL, 3 | "pk2" NUMBER(10,0) NOT NULL, 4 | "col1" NUMBER(10,0) NOT NULL, 5 | PRIMARY KEY("pk1","pk2")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/upsert1-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO "Customer" ("id","name","salary","address") VALUES (?,?,?,?) ON CONFLICT ("id") DO UPDATE SET "name"=EXCLUDED."name","salary"=EXCLUDED."salary","address"=EXCLUDED."address" -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/upsert1-quoted.txt: -------------------------------------------------------------------------------- 1 | insert into `actor`(`actor_id`,`first_name`,`last_name`,`score`) values(?,?,?,?) on duplicate key update `first_name`=values(`first_name`),`last_name`=values(`last_name`),`score`=values(`score`) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/upsert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | insert into myTable(id1,id2,columnA,columnB,columnC,columnD) values(?,?,?,?,?,?) on duplicate key update columnA=values(columnA),columnB=values(columnB),columnC=values(columnC),columnD=values(columnD) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/drop_table_with_schema_if_exists-nonquoted.txt: -------------------------------------------------------------------------------- 1 | IF EXISTS (SELECT 1 FROM sysobjects INNER JOIN sysusers ON sysobjects.uid=sysusers.uid WHERE sysusers.name='dbo' AND sysobjects.name='myTable' AND type='U') DROP TABLE dbName.dbo.myTable -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/drop_table_with_schema_if_exists-quoted.txt: -------------------------------------------------------------------------------- 1 | IF EXISTS (SELECT 1 FROM sysobjects INNER JOIN sysusers ON sysobjects.uid=sysusers.uid WHERE sysusers.name='dbo' AND sysobjects.name='myTable' AND type='U') DROP TABLE "dbName"."dbo"."myTable" -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/upsert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO myTable (id1,id2,columnA,columnB,columnC,columnD) VALUES (?,?,?,?,?,?) ON CONFLICT (id1,id2) DO UPDATE SET columnA=EXCLUDED.columnA,columnB=EXCLUDED.columnB,columnC=EXCLUDED.columnC,columnD=EXCLUDED.columnD -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/upsert0-quoted.txt: -------------------------------------------------------------------------------- 1 | insert into `myTable`(`id1`,`id2`,`columnA`,`columnB`,`columnC`,`columnD`) values(?,?,?,?,?,?) on duplicate key update `columnA`=values(`columnA`),`columnB`=values(`columnB`),`columnC`=values(`columnC`),`columnD`=values(`columnD`) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/upsert_cast_types0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO cast_types_table (pk,uuid_col,json_col,jsonb_col) VALUES (?,?::uuid,?::json,?::jsonb) ON CONFLICT (pk) DO UPDATE SET uuid_col=EXCLUDED.uuid_col,json_col=EXCLUDED.json_col,jsonb_col=EXCLUDED.jsonb_col -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/upsert_cast_types0-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO "cast_types_table" ("pk","uuid_col","json_col","jsonb_col") VALUES (?,?::uuid,?::json,?::jsonb) ON CONFLICT ("pk") DO UPDATE SET "uuid_col"=EXCLUDED."uuid_col","json_col"=EXCLUDED."json_col","jsonb_col"=EXCLUDED."jsonb_col" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build products 2 | target/ 3 | bin 4 | 5 | # IntelliJ data 6 | *.iml 7 | .idea/ 8 | .ipr 9 | 10 | # Documentation build output 11 | /docs/_build 12 | 13 | .DS_Store 14 | 15 | derby.log 16 | 17 | # Test databases 18 | __test_database_* 19 | test.sqlite 20 | *.db-journal 21 | 22 | # Gradle 23 | /build 24 | /.gradle 25 | -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/upsert0-quoted.txt: -------------------------------------------------------------------------------- 1 | INSERT INTO "myTable" ("id1","id2","columnA","columnB","columnC","columnD") VALUES (?,?,?,?,?,?) ON CONFLICT ("id1","id2") DO UPDATE SET "columnA"=EXCLUDED."columnA","columnB"=EXCLUDED."columnB","columnC"=EXCLUDED."columnC","columnD"=EXCLUDED."columnD" -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD 2 | c1 int NOT NULL, 3 | c2 bigint NOT NULL, 4 | c3 text NOT NULL, 5 | c4 text NULL, 6 | c5 date DEFAULT '2001-03-15', 7 | c6 time DEFAULT '00:00:00.000', 8 | c7 datetime DEFAULT '2001-03-15 00:00:00.000', 9 | c8 decimal(38,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD( 2 | c1 NUMBER(10,0) NOT NULL, 3 | c2 NUMBER(19,0) NOT NULL, 4 | c3 CLOB NOT NULL, 5 | c4 CLOB NULL, 6 | c5 DATE DEFAULT '2001-03-15', 7 | c6 DATE DEFAULT '00:00:00.000', 8 | c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | c8 NUMBER(*,4) NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD 2 | "c1" int NOT NULL, 3 | "c2" bigint NOT NULL, 4 | "c3" text NOT NULL, 5 | "c4" text NULL, 6 | "c5" date DEFAULT '2001-03-15', 7 | "c6" time DEFAULT '00:00:00.000', 8 | "c7" datetime DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" decimal(38,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD( 2 | c1 INTEGER NOT NULL, 3 | c2 BIGINT NOT NULL, 4 | c3 VARCHAR(1000) NOT NULL, 5 | c4 VARCHAR(1000) NULL, 6 | c5 DATE DEFAULT '2001-03-15', 7 | c6 DATE DEFAULT '00:00:00.000', 8 | c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | c8 DECIMAL NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD 2 | c1 int NOT NULL, 3 | c2 bigint NOT NULL, 4 | c3 varchar(max) NOT NULL, 5 | c4 varchar(max) NULL, 6 | c5 date DEFAULT '2001-03-15', 7 | c6 time DEFAULT '00:00:00.000', 8 | c7 datetime2 DEFAULT '2001-03-15 00:00:00.000', 9 | c8 decimal(38,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable 2 | ADD c1 INT NOT NULL, 3 | ADD c2 BIGINT NOT NULL, 4 | ADD c3 TEXT NOT NULL, 5 | ADD c4 TEXT NULL, 6 | ADD c5 DATE DEFAULT '2001-03-15', 7 | ADD c6 TIME DEFAULT '00:00:00.000', 8 | ADD c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | ADD c8 DECIMAL NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD( 2 | "c1" NUMBER(10,0) NOT NULL, 3 | "c2" NUMBER(19,0) NOT NULL, 4 | "c3" CLOB NOT NULL, 5 | "c4" CLOB NULL, 6 | "c5" DATE DEFAULT '2001-03-15', 7 | "c6" DATE DEFAULT '00:00:00.000', 8 | "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" NUMBER(*,4) NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | c1 INT NOT NULL, 3 | c2 BIGINT NOT NULL, 4 | c3 TEXT NOT NULL, 5 | c4 TEXT NULL, 6 | c5 DATE DEFAULT '2001-03-15', 7 | c6 TIME DEFAULT '00:00:00.000', 8 | c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | c8 DECIMAL NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | c1 int NOT NULL, 3 | c2 bigint NOT NULL, 4 | c3 text NOT NULL, 5 | c4 text NULL, 6 | c5 date DEFAULT '2001-03-15', 7 | c6 time DEFAULT '00:00:00.000', 8 | c7 datetime DEFAULT '2001-03-15 00:00:00.000', 9 | c8 decimal(38,4) NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD( 2 | "c1" INTEGER NOT NULL, 3 | "c2" BIGINT NOT NULL, 4 | "c3" VARCHAR(1000) NOT NULL, 5 | "c4" VARCHAR(1000) NULL, 6 | "c5" DATE DEFAULT '2001-03-15', 7 | "c6" DATE DEFAULT '00:00:00.000', 8 | "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" DECIMAL NULL) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE [myTable] ADD 2 | [c1] int NOT NULL, 3 | [c2] bigint NOT NULL, 4 | [c3] varchar(max) NOT NULL, 5 | [c4] varchar(max) NULL, 6 | [c5] date DEFAULT '2001-03-15', 7 | [c6] time DEFAULT '00:00:00.000', 8 | [c7] datetime2 DEFAULT '2001-03-15 00:00:00.000', 9 | [c8] decimal(38,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | c1 INTEGER NOT NULL, 3 | c2 INTEGER NOT NULL, 4 | c3 TEXT NOT NULL, 5 | c4 TEXT NULL, 6 | c5 NUMERIC DEFAULT '2001-03-15', 7 | c6 NUMERIC DEFAULT '00:00:00.000', 8 | c7 NUMERIC DEFAULT '2001-03-15 00:00:00.000', 9 | c8 NUMERIC NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" 2 | ADD "c1" INT NOT NULL, 3 | ADD "c2" BIGINT NOT NULL, 4 | ADD "c3" TEXT NOT NULL, 5 | ADD "c4" TEXT NULL, 6 | ADD "c5" DATE DEFAULT '2001-03-15', 7 | ADD "c6" TIME DEFAULT '00:00:00.000', 8 | ADD "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | ADD "c8" DECIMAL NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | c1 NUMBER(10,0) NOT NULL, 3 | c2 NUMBER(19,0) NOT NULL, 4 | c3 CLOB NOT NULL, 5 | c4 CLOB NULL, 6 | c5 DATE DEFAULT '2001-03-15', 7 | c6 DATE DEFAULT '00:00:00.000', 8 | c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | c8 NUMBER(*,4) NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/PostgreSqlDatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "c1" INT NOT NULL, 3 | "c2" BIGINT NOT NULL, 4 | "c3" TEXT NOT NULL, 5 | "c4" TEXT NULL, 6 | "c5" DATE DEFAULT '2001-03-15', 7 | "c6" TIME DEFAULT '00:00:00.000', 8 | "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" DECIMAL NULL, 10 | PRIMARY KEY("c1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable 2 | ADD c1 INT NOT NULL, 3 | ADD c2 BIGINT NOT NULL, 4 | ADD c3 VARCHAR(256) NOT NULL, 5 | ADD c4 VARCHAR(256) NULL, 6 | ADD c5 DATE DEFAULT '2001-03-15', 7 | ADD c6 TIME(3) DEFAULT '00:00:00.000', 8 | ADD c7 DATETIME(3) DEFAULT '2001-03-15 00:00:00.000', 9 | ADD c8 DECIMAL(65,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | c1 INT NOT NULL, 3 | c2 BIGINT NOT NULL, 4 | c3 VARCHAR(256) NOT NULL, 5 | c4 VARCHAR(256) NULL, 6 | c5 DATE DEFAULT '2001-03-15', 7 | c6 TIME(3) DEFAULT '00:00:00.000', 8 | c7 DATETIME(3) DEFAULT '2001-03-15 00:00:00.000', 9 | c8 DECIMAL(65,4) NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | c1 int NOT NULL, 3 | c2 bigint NOT NULL, 4 | c3 varchar(max) NOT NULL, 5 | c4 varchar(max) NULL, 6 | c5 date DEFAULT '2001-03-15', 7 | c6 time DEFAULT '00:00:00.000', 8 | c7 datetime2 DEFAULT '2001-03-15 00:00:00.000', 9 | c8 decimal(38,4) NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "c1" INTEGER NOT NULL, 3 | "c2" INTEGER NOT NULL, 4 | "c3" TEXT NOT NULL, 5 | "c4" TEXT NULL, 6 | "c5" NUMERIC DEFAULT '2001-03-15', 7 | "c6" NUMERIC DEFAULT '00:00:00.000', 8 | "c7" NUMERIC DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" NUMERIC NULL, 10 | PRIMARY KEY("c1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "c1" int NOT NULL, 3 | "c2" bigint NOT NULL, 4 | "c3" text NOT NULL, 5 | "c4" text NULL, 6 | "c5" date DEFAULT '2001-03-15', 7 | "c6" time DEFAULT '00:00:00.000', 8 | "c7" datetime DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" decimal(38,4) NULL, 10 | PRIMARY KEY("c1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | c1 INT NOT NULL, 3 | c2 INT NOT NULL, 4 | c3 VARCHAR(1024) NOT NULL, 5 | c4 VARCHAR(1024) NULL, 6 | c5 DATE DEFAULT '2001-03-15', 7 | c6 TIME DEFAULT '00:00:00.000', 8 | c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | c8 DECIMAL(18,4) NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=85719317abd2112f021d4f41f09ec370534ba288432065f4b477b6a3b652910d 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip 5 | networkTimeout=10000 6 | validateDistributionUrl=true 7 | zipStoreBase=GRADLE_USER_HOME 8 | zipStorePath=wrapper/dists 9 | -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable | 2 | ADD c1 INTEGER NOT NULL, 3 | ADD c2 BIGINT NOT NULL, 4 | ADD c3 VARCHAR(32672) NOT NULL, 5 | ADD c4 VARCHAR(32672) NULL, 6 | ADD c5 DATE DEFAULT '2001-03-15', 7 | ADD c6 TIME DEFAULT '00:00:00.000', 8 | ADD c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | ADD c8 DECIMAL(31,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | c1 INTEGER NOT NULL, 3 | c2 BIGINT NOT NULL, 4 | c3 VARCHAR(32672) NOT NULL, 5 | c4 VARCHAR(32672) NULL, 6 | c5 DATE DEFAULT '2001-03-15', 7 | c6 TIME DEFAULT '00:00:00.000', 8 | c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | c8 DECIMAL(31,4) NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE myTable ( 2 | c1 INTEGER NOT NULL, 3 | c2 BIGINT NOT NULL, 4 | c3 VARCHAR(32672) NOT NULL, 5 | c4 VARCHAR(32672) NULL, 6 | c5 DATE DEFAULT '2001-03-15', 7 | c6 TIME DEFAULT '00:00:00.000', 8 | c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | c8 DECIMAL(31,4) NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/create_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | CREATE COLUMN TABLE myTable ( 2 | c1 INTEGER NOT NULL, 3 | c2 BIGINT NOT NULL, 4 | c3 VARCHAR(1000) NOT NULL, 5 | c4 VARCHAR(1000) NULL, 6 | c5 DATE DEFAULT '2001-03-15', 7 | c6 DATE DEFAULT '00:00:00.000', 8 | c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | c8 DECIMAL NULL, 10 | PRIMARY KEY(c1)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable | 2 | ADD c1 INTEGER NOT NULL, 3 | ADD c2 BIGINT NOT NULL, 4 | ADD c3 VARCHAR(32672) NOT NULL, 5 | ADD c4 VARCHAR(32672) NULL, 6 | ADD c5 DATE DEFAULT '2001-03-15', 7 | ADD c6 TIME DEFAULT '00:00:00.000', 8 | ADD c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | ADD c8 DECIMAL(31,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "c1" NUMBER(10,0) NOT NULL, 3 | "c2" NUMBER(19,0) NOT NULL, 4 | "c3" CLOB NOT NULL, 5 | "c4" CLOB NULL, 6 | "c5" DATE DEFAULT '2001-03-15', 7 | "c6" DATE DEFAULT '00:00:00.000', 8 | "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" NUMBER(*,4) NULL, 10 | PRIMARY KEY("c1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE `myTable` 2 | ADD `c1` INT NOT NULL, 3 | ADD `c2` BIGINT NOT NULL, 4 | ADD `c3` VARCHAR(256) NOT NULL, 5 | ADD `c4` VARCHAR(256) NULL, 6 | ADD `c5` DATE DEFAULT '2001-03-15', 7 | ADD `c6` TIME(3) DEFAULT '00:00:00.000', 8 | ADD `c7` DATETIME(3) DEFAULT '2001-03-15 00:00:00.000', 9 | ADD `c8` DECIMAL(65,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/upsert1-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into ARTICLE using (select ? title, ? author, ? body FROM dual) incoming on(ARTICLE.title=incoming.title and ARTICLE.author=incoming.author) when matched then update set ARTICLE.body=incoming.body when not matched then insert(ARTICLE.body,ARTICLE.title,ARTICLE.author) values(incoming.body,incoming.title,incoming.author) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "c1" INT NOT NULL, 3 | "c2" INT NOT NULL, 4 | "c3" VARCHAR(1024) NOT NULL, 5 | "c4" VARCHAR(1024) NULL, 6 | "c5" DATE DEFAULT '2001-03-15', 7 | "c6" TIME DEFAULT '00:00:00.000', 8 | "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" DECIMAL(18,4) NULL, 10 | PRIMARY KEY("c1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" | 2 | ADD "c1" INTEGER NOT NULL, 3 | ADD "c2" BIGINT NOT NULL, 4 | ADD "c3" VARCHAR(32672) NOT NULL, 5 | ADD "c4" VARCHAR(32672) NULL, 6 | ADD "c5" DATE DEFAULT '2001-03-15', 7 | ADD "c6" TIME DEFAULT '00:00:00.000', 8 | ADD "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | ADD "c8" DECIMAL(31,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "c1" INTEGER NOT NULL, 3 | "c2" BIGINT NOT NULL, 4 | "c3" VARCHAR(32672) NOT NULL, 5 | "c4" VARCHAR(32672) NULL, 6 | "c5" DATE DEFAULT '2001-03-15', 7 | "c6" TIME DEFAULT '00:00:00.000', 8 | "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" DECIMAL(31,4) NULL, 10 | PRIMARY KEY("c1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE "myTable" ( 2 | "c1" INTEGER NOT NULL, 3 | "c2" BIGINT NOT NULL, 4 | "c3" VARCHAR(32672) NOT NULL, 5 | "c4" VARCHAR(32672) NULL, 6 | "c5" DATE DEFAULT '2001-03-15', 7 | "c6" TIME DEFAULT '00:00:00.000', 8 | "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" DECIMAL(31,4) NULL, 10 | PRIMARY KEY("c1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/MySqlDatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE `myTable` ( 2 | `c1` INT NOT NULL, 3 | `c2` BIGINT NOT NULL, 4 | `c3` VARCHAR(256) NOT NULL, 5 | `c4` VARCHAR(256) NULL, 6 | `c5` DATE DEFAULT '2001-03-15', 7 | `c6` TIME(3) DEFAULT '00:00:00.000', 8 | `c7` DATETIME(3) DEFAULT '2001-03-15 00:00:00.000', 9 | `c8` DECIMAL(65,4) NULL, 10 | PRIMARY KEY(`c1`)) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE TABLE [myTable] ( 2 | [c1] int NOT NULL, 3 | [c2] bigint NOT NULL, 4 | [c3] varchar(max) NOT NULL, 5 | [c4] varchar(max) NULL, 6 | [c5] date DEFAULT '2001-03-15', 7 | [c6] time DEFAULT '00:00:00.000', 8 | [c7] datetime2 DEFAULT '2001-03-15 00:00:00.000', 9 | [c8] decimal(38,4) NULL, 10 | PRIMARY KEY([c1])) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" | 2 | ADD "c1" INTEGER NOT NULL, 3 | ADD "c2" BIGINT NOT NULL, 4 | ADD "c3" VARCHAR(32672) NOT NULL, 5 | ADD "c4" VARCHAR(32672) NULL, 6 | ADD "c5" DATE DEFAULT '2001-03-15', 7 | ADD "c6" TIME DEFAULT '00:00:00.000', 8 | ADD "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | ADD "c8" DECIMAL(31,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SapHanaDatabaseDialectTest/create_table-quoted.txt: -------------------------------------------------------------------------------- 1 | CREATE COLUMN TABLE "myTable" ( 2 | "c1" INTEGER NOT NULL, 3 | "c2" BIGINT NOT NULL, 4 | "c3" VARCHAR(1000) NOT NULL, 5 | "c4" VARCHAR(1000) NULL, 6 | "c5" DATE DEFAULT '2001-03-15', 7 | "c6" DATE DEFAULT '00:00:00.000', 8 | "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000', 9 | "c8" DECIMAL NULL, 10 | PRIMARY KEY("c1")) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/upsert1-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into Customer with (HOLDLOCK) AS target using (select ? AS id, ? AS name, ? AS salary, ? AS address) AS incoming on (target.id=incoming.id) when matched then update set name=incoming.name,salary=incoming.salary,address=incoming.address when not matched then insert (name, salary, address, id) values (incoming.name,incoming.salary,incoming.address,incoming.id); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/upsert1-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "ARTICLE" using (select ? "title", ? "author", ? "body" FROM dual) incoming on("ARTICLE"."title"=incoming."title" and "ARTICLE"."author"=incoming."author") when matched then update set "ARTICLE"."body"=incoming."body" when not matched then insert("ARTICLE"."body","ARTICLE"."title","ARTICLE"."author") values(incoming."body",incoming."title",incoming."author") -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/upsert1-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into Customer with (HOLDLOCK) AS target using (select ? AS id, ? AS name, ? AS salary, ? AS address) AS incoming on (target.id=incoming.id) when matched then update set name=incoming.name,salary=incoming.salary,address=incoming.address when not matched then insert (name, salary, address, id) values (incoming.name,incoming.salary,incoming.address,incoming.id); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/upsert1-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into actor using (values(?, ?, ?, ?)) as DAT(actor_id, first_name, last_name, score) on actor.actor_id=DAT.actor_id when matched then update set actor.first_name=DAT.first_name, actor.last_name=DAT.last_name, actor.score=DAT.score when not matched then insert(actor.first_name,actor.last_name,actor.score,actor.actor_id) values(DAT.first_name,DAT.last_name,DAT.score,DAT.actor_id) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/upsert1-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into actor using (values(?, ?, ?, ?)) as DAT(actor_id, first_name, last_name, score) on actor.actor_id=DAT.actor_id when matched then update set actor.first_name=DAT.first_name, actor.last_name=DAT.last_name, actor.score=DAT.score when not matched then insert(actor.first_name,actor.last_name,actor.score,actor.actor_id) values(DAT.first_name,DAT.last_name,DAT.score,DAT.actor_id) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/upsert1-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "Customer" with (HOLDLOCK) AS target using (select ? AS "id", ? AS "name", ? AS "salary", ? AS "address") AS incoming on (target."id"=incoming."id") when matched then update set "name"=incoming."name","salary"=incoming."salary","address"=incoming."address" when not matched then insert ("name", "salary", "address", "id") values (incoming."name",incoming."salary",incoming."address",incoming."id"); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/upsert1-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into [Customer] with (HOLDLOCK) AS target using (select ? AS [id], ? AS [name], ? AS [salary], ? AS [address]) AS incoming on (target.[id]=incoming.[id]) when matched then update set [name]=incoming.[name],[salary]=incoming.[salary],[address]=incoming.[address] when not matched then insert ([name], [salary], [address], [id]) values (incoming.[name],incoming.[salary],incoming.[address],incoming.[id]); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD c1 INTEGER NOT NULL 2 | ALTER TABLE myTable ADD c2 INTEGER NOT NULL 3 | ALTER TABLE myTable ADD c3 TEXT NOT NULL 4 | ALTER TABLE myTable ADD c4 TEXT NULL 5 | ALTER TABLE myTable ADD c5 NUMERIC DEFAULT '2001-03-15' 6 | ALTER TABLE myTable ADD c6 NUMERIC DEFAULT '00:00:00.000' 7 | ALTER TABLE myTable ADD c7 NUMERIC DEFAULT '2001-03-15 00:00:00.000' 8 | ALTER TABLE myTable ADD c8 NUMERIC NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/upsert2-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into Book with (HOLDLOCK) AS target using (select ? AS author, ? AS title, ? AS ISBN, ? AS year, ? AS pages) AS incoming on (target.author=incoming.author and target.title=incoming.title) when matched then update set ISBN=incoming.ISBN,year=incoming.year,pages=incoming.pages when not matched then insert (ISBN, year, pages, author, title) values (incoming.ISBN,incoming.year,incoming.pages,incoming.author,incoming.title); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/upsert2-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into Book with (HOLDLOCK) AS target using (select ? AS author, ? AS title, ? AS ISBN, ? AS year, ? AS pages) AS incoming on (target.author=incoming.author and target.title=incoming.title) when matched then update set ISBN=incoming.ISBN,year=incoming.year,pages=incoming.pages when not matched then insert (ISBN, year, pages, author, title) values (incoming.ISBN,incoming.year,incoming.pages,incoming.author,incoming.title); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/alter_table-nonquoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE myTable ADD c1 INT NOT NULL 2 | ALTER TABLE myTable ADD c2 INT NOT NULL 3 | ALTER TABLE myTable ADD c3 VARCHAR(1024) NOT NULL 4 | ALTER TABLE myTable ADD c4 VARCHAR(1024) NULL 5 | ALTER TABLE myTable ADD c5 DATE DEFAULT '2001-03-15' 6 | ALTER TABLE myTable ADD c6 TIME DEFAULT '00:00:00.000' 7 | ALTER TABLE myTable ADD c7 TIMESTAMP DEFAULT '2001-03-15 00:00:00.000' 8 | ALTER TABLE myTable ADD c8 DECIMAL(18,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/upsert1-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "actor" using (values(?, ?, ?, ?)) as DAT("actor_id", "first_name", "last_name", "score") on "actor"."actor_id"=DAT."actor_id" when matched then update set "actor"."first_name"=DAT."first_name", "actor"."last_name"=DAT."last_name", "actor"."score"=DAT."score" when not matched then insert("actor"."first_name","actor"."last_name","actor"."score","actor"."actor_id") values(DAT."first_name",DAT."last_name",DAT."score",DAT."actor_id") -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/upsert1-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "actor" using (values(?, ?, ?, ?)) as DAT("actor_id", "first_name", "last_name", "score") on "actor"."actor_id"=DAT."actor_id" when matched then update set "actor"."first_name"=DAT."first_name", "actor"."last_name"=DAT."last_name", "actor"."score"=DAT."score" when not matched then insert("actor"."first_name","actor"."last_name","actor"."score","actor"."actor_id") values(DAT."first_name",DAT."last_name",DAT."score",DAT."actor_id") -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqliteDatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD "c1" INTEGER NOT NULL 2 | ALTER TABLE "myTable" ADD "c2" INTEGER NOT NULL 3 | ALTER TABLE "myTable" ADD "c3" TEXT NOT NULL 4 | ALTER TABLE "myTable" ADD "c4" TEXT NULL 5 | ALTER TABLE "myTable" ADD "c5" NUMERIC DEFAULT '2001-03-15' 6 | ALTER TABLE "myTable" ADD "c6" NUMERIC DEFAULT '00:00:00.000' 7 | ALTER TABLE "myTable" ADD "c7" NUMERIC DEFAULT '2001-03-15 00:00:00.000' 8 | ALTER TABLE "myTable" ADD "c8" NUMERIC NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/VerticaDatabaseDialectTest/alter_table-quoted.txt: -------------------------------------------------------------------------------- 1 | ALTER TABLE "myTable" ADD "c1" INT NOT NULL 2 | ALTER TABLE "myTable" ADD "c2" INT NOT NULL 3 | ALTER TABLE "myTable" ADD "c3" VARCHAR(1024) NOT NULL 4 | ALTER TABLE "myTable" ADD "c4" VARCHAR(1024) NULL 5 | ALTER TABLE "myTable" ADD "c5" DATE DEFAULT '2001-03-15' 6 | ALTER TABLE "myTable" ADD "c6" TIME DEFAULT '00:00:00.000' 7 | ALTER TABLE "myTable" ADD "c7" TIMESTAMP DEFAULT '2001-03-15 00:00:00.000' 8 | ALTER TABLE "myTable" ADD "c8" DECIMAL(18,4) NULL -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/upsert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into myTable using (values(?, ?, ?, ?, ?, ?)) as DAT(id1, id2, columnA, columnB, columnC, columnD) on myTable.id1=DAT.id1 and myTable.id2=DAT.id2 when matched then update set myTable.columnA=DAT.columnA, myTable.columnB=DAT.columnB, myTable.columnC=DAT.columnC, myTable.columnD=DAT.columnD when not matched then insert(myTable.columnA,myTable.columnB,myTable.columnC,myTable.columnD,myTable.id1,myTable.id2) values(DAT.columnA,DAT.columnB,DAT.columnC,DAT.columnD,DAT.id1,DAT.id2) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/upsert2-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into [Book] with (HOLDLOCK) AS target using (select ? AS [author], ? AS [title], ? AS [ISBN], ? AS [year], ? AS [pages]) AS incoming on (target.[author]=incoming.[author] and target.[title]=incoming.[title]) when matched then update set [ISBN]=incoming.[ISBN],[year]=incoming.[year],[pages]=incoming.[pages] when not matched then insert ([ISBN], [year], [pages], [author], [title]) values (incoming.[ISBN],incoming.[year],incoming.[pages],incoming.[author],incoming.[title]); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/upsert2-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "Book" with (HOLDLOCK) AS target using (select ? AS "author", ? AS "title", ? AS "ISBN", ? AS "year", ? AS "pages") AS incoming on (target."author"=incoming."author" and target."title"=incoming."title") when matched then update set "ISBN"=incoming."ISBN","year"=incoming."year","pages"=incoming."pages" when not matched then insert ("ISBN", "year", "pages", "author", "title") values (incoming."ISBN",incoming."year",incoming."pages",incoming."author",incoming."title"); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/upsert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into myTable using (values(?, ?, ?, ?, ?, ?)) as DAT(id1, id2, columnA, columnB, columnC, columnD) on myTable.id1=DAT.id1 and myTable.id2=DAT.id2 when matched then update set myTable.columnA=DAT.columnA, myTable.columnB=DAT.columnB, myTable.columnC=DAT.columnC, myTable.columnD=DAT.columnD when not matched then insert(myTable.columnA,myTable.columnB,myTable.columnC,myTable.columnD,myTable.id1,myTable.id2) values(DAT.columnA,DAT.columnB,DAT.columnC,DAT.columnD,DAT.id1,DAT.id2) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/upsert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into myTable with (HOLDLOCK) AS target using (select ? AS id1, ? AS id2, ? AS columnA, ? AS columnB, ? AS columnC, ? AS columnD) AS incoming on (target.id1=incoming.id1 and target.id2=incoming.id2) when matched then update set columnA=incoming.columnA,columnB=incoming.columnB,columnC=incoming.columnC,columnD=incoming.columnD when not matched then insert (columnA, columnB, columnC, columnD, id1, id2) values (incoming.columnA,incoming.columnB,incoming.columnC,incoming.columnD,incoming.id1,incoming.id2); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/upsert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into myTable with (HOLDLOCK) AS target using (select ? AS id1, ? AS id2, ? AS columnA, ? AS columnB, ? AS columnC, ? AS columnD) AS incoming on (target.id1=incoming.id1 and target.id2=incoming.id2) when matched then update set columnA=incoming.columnA,columnB=incoming.columnB,columnC=incoming.columnC,columnD=incoming.columnD when not matched then insert (columnA, columnB, columnC, columnD, id1, id2) values (incoming.columnA,incoming.columnB,incoming.columnC,incoming.columnD,incoming.id1,incoming.id2); -------------------------------------------------------------------------------- /.github/workflows/master_push_workflow.yml: -------------------------------------------------------------------------------- 1 | # The workflow to check master after push. 2 | name: Master checks after push 3 | on: 4 | push: 5 | branches: [ master ] 6 | jobs: 7 | build: 8 | name: Build 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout code 12 | uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 0 15 | - name: Set up JDK 17 16 | uses: actions/setup-java@v2 17 | with: 18 | distribution: "temurin" 19 | java-version: 17 20 | - name: Build with Gradle 21 | run: ./gradlew build integrationTest 22 | -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/upsert0-nonquoted.txt: -------------------------------------------------------------------------------- 1 | merge into myTable using (select ? id1, ? id2, ? columnA, ? columnB, ? columnC, ? columnD FROM dual) incoming on(myTable.id1=incoming.id1 and myTable.id2=incoming.id2) when matched then update set myTable.columnA=incoming.columnA,myTable.columnB=incoming.columnB,myTable.columnC=incoming.columnC,myTable.columnD=incoming.columnD when not matched then insert(myTable.columnA,myTable.columnB,myTable.columnC,myTable.columnD,myTable.id1,myTable.id2) values(incoming.columnA,incoming.columnB,incoming.columnC,incoming.columnD,incoming.id1,incoming.id2) -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/Db2DatabaseDialectTest/upsert0-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "myTable" using (values(?, ?, ?, ?, ?, ?)) as DAT("id1", "id2", "columnA", "columnB", "columnC", "columnD") on "myTable"."id1"=DAT."id1" and "myTable"."id2"=DAT."id2" when matched then update set "myTable"."columnA"=DAT."columnA", "myTable"."columnB"=DAT."columnB", "myTable"."columnC"=DAT."columnC", "myTable"."columnD"=DAT."columnD" when not matched then insert("myTable"."columnA","myTable"."columnB","myTable"."columnC","myTable"."columnD","myTable"."id1","myTable"."id2") values(DAT."columnA",DAT."columnB",DAT."columnC",DAT."columnD",DAT."id1",DAT."id2") -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/DerbyDatabaseDialectTest/upsert0-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "myTable" using (values(?, ?, ?, ?, ?, ?)) as DAT("id1", "id2", "columnA", "columnB", "columnC", "columnD") on "myTable"."id1"=DAT."id1" and "myTable"."id2"=DAT."id2" when matched then update set "myTable"."columnA"=DAT."columnA", "myTable"."columnB"=DAT."columnB", "myTable"."columnC"=DAT."columnC", "myTable"."columnD"=DAT."columnD" when not matched then insert("myTable"."columnA","myTable"."columnB","myTable"."columnC","myTable"."columnD","myTable"."id1","myTable"."id2") values(DAT."columnA",DAT."columnB",DAT."columnC",DAT."columnD",DAT."id1",DAT."id2") -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SybaseDatabaseDialectTest/upsert0-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "myTable" with (HOLDLOCK) AS target using (select ? AS "id1", ? AS "id2", ? AS "columnA", ? AS "columnB", ? AS "columnC", ? AS "columnD") AS incoming on (target."id1"=incoming."id1" and target."id2"=incoming."id2") when matched then update set "columnA"=incoming."columnA","columnB"=incoming."columnB","columnC"=incoming."columnC","columnD"=incoming."columnD" when not matched then insert ("columnA", "columnB", "columnC", "columnD", "id1", "id2") values (incoming."columnA",incoming."columnB",incoming."columnC",incoming."columnD",incoming."id1",incoming."id2"); -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/SqlServerDatabaseDialectTest/upsert0-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into [myTable] with (HOLDLOCK) AS target using (select ? AS [id1], ? AS [id2], ? AS [columnA], ? AS [columnB], ? AS [columnC], ? AS [columnD]) AS incoming on (target.[id1]=incoming.[id1] and target.[id2]=incoming.[id2]) when matched then update set [columnA]=incoming.[columnA],[columnB]=incoming.[columnB],[columnC]=incoming.[columnC],[columnD]=incoming.[columnD] when not matched then insert ([columnA], [columnB], [columnC], [columnD], [id1], [id2]) values (incoming.[columnA],incoming.[columnB],incoming.[columnC],incoming.[columnD],incoming.[id1],incoming.[id2]); -------------------------------------------------------------------------------- /.github/workflows/pull_request_workflow.yml: -------------------------------------------------------------------------------- 1 | # The workflow to check pull requests into master. 2 | # This checks the source in the state as if after the merge. 3 | name: Pull request checks 4 | on: 5 | pull_request: 6 | branches: [ master ] 7 | jobs: 8 | build: 9 | name: Build 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4 14 | - name: Set up JDK 17 15 | uses: actions/setup-java@v2 16 | with: 17 | distribution: "temurin" 18 | java-version: 17 19 | - name: Build with Gradle 20 | run: ./gradlew build integrationTest 21 | -------------------------------------------------------------------------------- /src/test/resources/io.aiven.connect.jdbc.dialect/OracleDatabaseDialectTest/upsert0-quoted.txt: -------------------------------------------------------------------------------- 1 | merge into "myTable" using (select ? "id1", ? "id2", ? "columnA", ? "columnB", ? "columnC", ? "columnD" FROM dual) incoming on("myTable"."id1"=incoming."id1" and "myTable"."id2"=incoming."id2") when matched then update set "myTable"."columnA"=incoming."columnA","myTable"."columnB"=incoming."columnB","myTable"."columnC"=incoming."columnC","myTable"."columnD"=incoming."columnD" when not matched then insert("myTable"."columnA","myTable"."columnB","myTable"."columnC","myTable"."columnD","myTable"."id1","myTable"."id2") values(incoming."columnA",incoming."columnB",incoming."columnC",incoming."columnD",incoming."id1",incoming."id2") -------------------------------------------------------------------------------- /src/main/resources/jdbc-connector-for-apache-kafka-version.properties: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright 2019 Aiven Oy 3 | # Copyright 2015 Confluent Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | ## 17 | 18 | version=${version ?: 'unknown'} 19 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/io.aiven.connect.jdbc.dialect.DatabaseDialectProvider: -------------------------------------------------------------------------------- 1 | io.aiven.connect.jdbc.dialect.GenericDatabaseDialect$Provider 2 | io.aiven.connect.jdbc.dialect.Db2DatabaseDialect$Provider 3 | io.aiven.connect.jdbc.dialect.DerbyDatabaseDialect$Provider 4 | io.aiven.connect.jdbc.dialect.OracleDatabaseDialect$Provider 5 | io.aiven.connect.jdbc.dialect.SqliteDatabaseDialect$Provider 6 | io.aiven.connect.jdbc.dialect.PostgreSqlDatabaseDialect$Provider 7 | io.aiven.connect.jdbc.dialect.MySqlDatabaseDialect$Provider 8 | io.aiven.connect.jdbc.dialect.SqlServerDatabaseDialect$Provider 9 | io.aiven.connect.jdbc.dialect.SapHanaDatabaseDialect$Provider 10 | io.aiven.connect.jdbc.dialect.SybaseDatabaseDialect$Provider 11 | io.aiven.connect.jdbc.dialect.VerticaDatabaseDialect$Provider 12 | -------------------------------------------------------------------------------- /checkstyle/java.header: -------------------------------------------------------------------------------- 1 | /\* 2 | \* Copyright (20(19|2[0-9]) - )?20(19|2[0-9]) Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | \* Copyright 201[5-9] Confluent Inc. 4 | \* 5 | \* Licensed under the Apache License, Version 2.0 \(the "License"\); 6 | \* you may not use this file except in compliance with the License. 7 | \* You may obtain a copy of the License at 8 | \* 9 | \* http://www.apache.org/licenses/LICENSE-2.0 10 | \* 11 | \* Unless required by applicable law or agreed to in writing, software 12 | \* distributed under the License is distributed on an "AS IS" BASIS, 13 | \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | \* See the License for the specific language governing permissions and 15 | \* limitations under the License. 16 | \*/ 17 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | kafka-connect-jdbc 2 | Copyright (c) 2019 Aiven Oy 3 | Copyright (c) 2015 Confluent Inc. 4 | 5 | The following libraries are included in packaged versions of this project: 6 | 7 | * SQLite JDBC Driver 8 | * COPYRIGHT: Copyright Taro L. Saito, David Crenshaw 9 | * LICENSE: licenses/LICENSE.apache2.txt 10 | * NOTICE: licenses/NOTICE.sqlite-jdbc.txt 11 | * HOMEPAGE: https://github.com/xerial/sqlite-jdbc 12 | 13 | * PostgreSQL JDBC Driver 14 | * COPYRIGHT: Copyright 1997-2011, PostgreSQL Global Development Group 15 | * LICENSE: licenses/LICENSE.bsd.txt 16 | * HOMEPAGE: https://jdbc.postgresql.org/ 17 | 18 | * MariaDB JDBC Driver 19 | * COPYRIGHT: Copyright 2012 Monty Program Ab., 2009-2011, Marcus Eriksson 20 | * LICENSE: licenses/LICENSE.lgpl.txt 21 | * HOMEPAGE: https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/ 22 | -------------------------------------------------------------------------------- /src/integrationTest/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright 2024 Aiven Oy 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | ## 16 | log4j.rootLogger=INFO, stdout 17 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 18 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 19 | log4j.appender.stdout.layout.ConversionPattern=[%d] %C %p %m (%c:%L)%n 20 | log4j.logger.org.apache.kafka=ERROR -------------------------------------------------------------------------------- /src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright 2019 Aiven Oy 3 | # Copyright 2015 Confluent Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | ## 17 | 18 | log4j.rootLogger=INFO, stdout 19 | 20 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 21 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 22 | log4j.appender.stdout.layout.ConversionPattern=[%d] %p %m (%c:%L)%n 23 | 24 | log4j.logger.org.apache.kafka=ERROR 25 | log4j.logger.io.aiven.connect=ERROR 26 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/CollectionUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.aiven.connect.jdbc.util; 18 | 19 | import java.util.Collection; 20 | 21 | public final class CollectionUtils { 22 | private CollectionUtils() { 23 | } 24 | 25 | public static boolean isEmpty(final Collection collection) { 26 | return collection == null || collection.isEmpty(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /cve-list.md: -------------------------------------------------------------------------------- 1 | # Known Vulnerabilities 2 | 3 | This page contains a list of all known vulnerabilities fixed in released versions of `JDBC connector for Apache Kafka`. 4 | 5 | ## CVE-2021-45046 and CVE-2021-44228 a.k.a. Log4Shell 6 | 7 | The [CVE-2021-45046](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-45046) and [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228) vulnerabilities affect the `Apache Log4j` logging library in versions prior 2.15.0. 8 | 9 | `JDBC connector for Apache Kafka` does not use any version of [`Log4j`](https://logging.apache.org/log4j/2.x/) directly as it uses [`slf4j`](http://www.slf4j.org/log4shell.html), which acts as an abstraction layer over logging frameworks. For this reason, **this project is not directly impacted by said vulnerabilities**. 10 | 11 | We recommend all users of `JDBC connector for Apache Kafka` to inspect their dependency tree and make sure they are not including any impacted version of `Log4j`. In case `Log4j` is used, we highly encourage to update to a newer version where these vulnerabilities are addressed (`2.16.0` or newer at the time of this writing). 12 | -------------------------------------------------------------------------------- /licenses/LICENSE-mssql-jdbc-8-2-1.txt: -------------------------------------------------------------------------------- 1 | Copyright(c) 2019 Microsoft Corporation 2 | All rights reserved. 3 | 4 | MIT License 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), 6 | to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 13 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 14 | IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/source/JdbcSourceConnectorConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2015 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.source; 19 | 20 | public class JdbcSourceConnectorConstants { 21 | public static final String TABLE_NAME_KEY = "table"; 22 | public static final String QUERY_NAME_KEY = "query"; 23 | public static final String QUERY_NAME_VALUE = "query"; 24 | public static final String OFFSET_PROTOCOL_VERSION_KEY = "protocol"; 25 | public static final String PROTOCOL_VERSION_ONE = "1"; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/BytesUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2016 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | public class BytesUtil { 21 | 22 | private static final char[] HEX_CODE = "0123456789ABCDEF".toCharArray(); 23 | 24 | public static String toHex(final byte[] data) { 25 | final StringBuilder r = new StringBuilder(data.length * 2); 26 | for (final byte b : data) { 27 | r.append(HEX_CODE[(b >> 4) & 0xF]); 28 | r.append(HEX_CODE[b & 0xF]); 29 | } 30 | return r.toString(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /config/sink-quickstart-sqlite.properties: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright 2019 Aiven Oy 3 | # Copyright 2016 Confluent Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | ## 17 | 18 | # A simple example that copies from a topic to a SQLite database. 19 | # The first few settings are required for all connectors: 20 | # a name, the connector class to run, and the maximum number of tasks to create: 21 | name=test-sink 22 | connector.class=io.aiven.connect.jdbc.JdbcSinkConnector 23 | tasks.max=1 24 | 25 | # The topics to consume from - required for sink connectors like this one 26 | topics=orders 27 | 28 | # Configuration specific to the JDBC sink connector. 29 | # We want to connect to a SQLite database stored in the file test.db and auto-create tables. 30 | connection.url=jdbc:sqlite:test.db 31 | auto.create=true 32 | -------------------------------------------------------------------------------- /licenses.html: -------------------------------------------------------------------------------- 1 | 28 |

kafka-connect-jdbc


29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
ArtifactTypeVersionLicense(s)
kafka-connect-jdbc-5.2.0-SNAPSHOTjar5.2.0-SNAPSHOTApache 2.0
postgresql-9.4-1206-jdbc41jar9.4.0.build-1206link from artifact (META-INF/MANIFEST.MF)
sqlite-jdbc-3.8.11.2jar3.8.11.2Apache 2.0
43 | 44 | -------------------------------------------------------------------------------- /licenses/LICENSE-postgresql-42-2-10.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 1997, PostgreSQL Global Development Group 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /config/source-quickstart-sqlite.properties: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright 2019 Aiven Oy 3 | # Copyright 2015 Confluent Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | ## 17 | 18 | # A simple example that copies all tables from a SQLite database. The first few settings are 19 | # required for all connectors: a name, the connector class to run, and the maximum number of 20 | # tasks to create: 21 | name=test-source-sqlite-jdbc-autoincrement 22 | connector.class=io.aiven.connect.jdbc.JdbcSourceConnector 23 | tasks.max=1 24 | # The remaining configs are specific to the JDBC source connector. In this example, we connect to a 25 | # SQLite database stored in the file test.db, use and auto-incrementing column called 'id' to 26 | # detect new rows as they are added, and output to topics prefixed with 'test-sqlite-jdbc-', e.g. 27 | # a table called 'users' will be written to the topic 'test-sqlite-jdbc-users'. 28 | connection.url=jdbc:sqlite:test.db 29 | mode=incrementing 30 | incrementing.column.name=id 31 | topic.prefix=test-sqlite-jdbc- -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/source/SourceConnectionProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.aiven.connect.jdbc.source; 18 | 19 | import java.sql.Connection; 20 | import java.sql.SQLException; 21 | 22 | import io.aiven.connect.jdbc.util.CachedConnectionProvider; 23 | import io.aiven.connect.jdbc.util.ConnectionProvider; 24 | 25 | class SourceConnectionProvider extends CachedConnectionProvider { 26 | SourceConnectionProvider( 27 | final ConnectionProvider provider, 28 | final int maxConnectionAttempts, 29 | final long connectionRetryBackoff 30 | ) { 31 | super(provider, maxConnectionAttempts, connectionRetryBackoff); 32 | } 33 | 34 | @Override 35 | protected void onConnect(final Connection connection) throws SQLException { 36 | super.onConnect(connection); 37 | connection.setAutoCommit(false); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | We release patches for security vulnerabilities. Which versions are eligible 6 | receiving such patches depend on the CVSS v3.0 Rating: 7 | 8 | | CVSS v3.0 | Supported Versions | 9 | | --------- | ----------------------------------------- | 10 | | 4.0-10.0 | Most recent release | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | Please report (suspected) security vulnerabilities to our **[bug bounty 15 | program](https://bugcrowd.com/aiven-mbb-og)**. You will receive a response from 16 | us within 2 working days. If the issue is confirmed, we will release a patch as 17 | soon as possible depending on impact and complexity. 18 | 19 | ## Qualifying Vulnerabilities 20 | 21 | Any reproducible vulnerability that has a severe effect on the security or 22 | privacy of our users is likely to be in scope for the program. 23 | 24 | We generally **aren't** interested in the following issues: 25 | * Social engineering (e.g. phishing, vishing, smishing) attacks 26 | * Brute force, DoS, text injection 27 | * Missing best practices such as HTTP security headers (CSP, X-XSS, etc.), 28 | email (SPF/DKIM/DMARC records), SSL/TLS configuration. 29 | * Software version disclosure / Banner identification issues / Descriptive 30 | error messages or headers (e.g. stack traces, application or server errors). 31 | * Clickjacking on pages with no sensitive actions 32 | * Theoretical vulnerabilities where you can't demonstrate a significant 33 | security impact with a proof of concept. 34 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/Version.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2015 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.io.InputStream; 21 | import java.util.Properties; 22 | 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | public class Version { 27 | private static final Logger log = LoggerFactory.getLogger(Version.class); 28 | private static final String PATH = "/jdbc-connector-for-apache-kafka-version.properties"; 29 | private static String version = "unknown"; 30 | 31 | static { 32 | try (final InputStream stream = Version.class.getResourceAsStream(PATH)) { 33 | final Properties props = new Properties(); 34 | props.load(stream); 35 | version = props.getProperty("version", version).trim(); 36 | } catch (final Exception e) { 37 | log.warn("Error while loading version:", e); 38 | } 39 | } 40 | 41 | public static String getVersion() { 42 | return version; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/TimeZoneValidator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2015 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.time.DateTimeException; 21 | import java.time.ZoneId; 22 | 23 | import org.apache.kafka.common.config.ConfigDef; 24 | import org.apache.kafka.common.config.ConfigException; 25 | 26 | public class TimeZoneValidator implements ConfigDef.Validator { 27 | 28 | public static final TimeZoneValidator INSTANCE = new TimeZoneValidator(); 29 | 30 | @Override 31 | public void ensureValid(final String name, final Object value) { 32 | if (value != null) { 33 | try { 34 | ZoneId.of(value.toString()); 35 | } catch (final DateTimeException e) { 36 | throw new ConfigException(name, value, "Invalid time zone identifier"); 37 | } 38 | } 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "valid time zone identifier (e.g., 'Europe/Helsinki', 'UTC+2', 'Z', 'CET')"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/io/aiven/connect/jdbc/dialect/MockDatabaseDialect.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2017 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.dialect; 19 | 20 | import io.aiven.connect.jdbc.config.JdbcConfig; 21 | import io.aiven.connect.jdbc.dialect.DatabaseDialectProvider.SubprotocolBasedProvider; 22 | 23 | public class MockDatabaseDialect extends GenericDatabaseDialect { 24 | 25 | /** 26 | * The provider for {@link MockDatabaseDialect}. 27 | */ 28 | public static class Provider extends SubprotocolBasedProvider { 29 | public Provider() { 30 | super(MockDatabaseDialect.class.getSimpleName(), "mock"); 31 | } 32 | 33 | @Override 34 | public DatabaseDialect create(final JdbcConfig config) { 35 | return new MockDatabaseDialect(config); 36 | } 37 | } 38 | 39 | /** 40 | * Create a new dialect instance with the given connector configuration. 41 | * 42 | * @param config the connector configuration; may not be null 43 | */ 44 | public MockDatabaseDialect(final JdbcConfig config) { 45 | super(config); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/StringUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2015 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | /** 21 | * General string utilities that are missing from the standard library and may commonly be 22 | * required by Connector or Task implementations. 23 | */ 24 | public class StringUtils { 25 | 26 | /** 27 | * Generate a String by appending all the @{elements}, converted to Strings, delimited by 28 | * 29 | * @param elements list of elements to concatenate 30 | * @param delim delimiter to place between each element 31 | * @return the concatenated string with delimiters 32 | */ 33 | public static String join(final Iterable elements, final String delim) { 34 | final StringBuilder result = new StringBuilder(); 35 | boolean first = true; 36 | for (final T elem : elements) { 37 | if (first) { 38 | first = false; 39 | } else { 40 | result.append(delim); 41 | } 42 | result.append(elem); 43 | } 44 | return result.toString(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/sink/metadata/SchemaPair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2016 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.sink.metadata; 19 | 20 | import java.util.Objects; 21 | 22 | import org.apache.kafka.connect.data.Schema; 23 | 24 | public class SchemaPair { 25 | public final Schema keySchema; 26 | public final Schema valueSchema; 27 | 28 | public SchemaPair(final Schema keySchema, final Schema valueSchema) { 29 | this.keySchema = keySchema; 30 | this.valueSchema = valueSchema; 31 | } 32 | 33 | @Override 34 | public boolean equals(final Object o) { 35 | if (this == o) { 36 | return true; 37 | } 38 | if (o == null || getClass() != o.getClass()) { 39 | return false; 40 | } 41 | final SchemaPair that = (SchemaPair) o; 42 | return Objects.equals(keySchema, that.keySchema) 43 | && Objects.equals(valueSchema, that.valueSchema); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return Objects.hash(keySchema, valueSchema); 49 | } 50 | 51 | public String toString() { 52 | return String.format("", keySchema, valueSchema); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/integrationTest/java/io/aiven/kafka/connect/jdbc/SchemaRegistryContainer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.aiven.kafka.connect.jdbc; 18 | 19 | import org.testcontainers.containers.GenericContainer; 20 | import org.testcontainers.containers.KafkaContainer; 21 | import org.testcontainers.utility.Base58; 22 | 23 | public final class SchemaRegistryContainer extends GenericContainer { 24 | public static final int SCHEMA_REGISTRY_PORT = 8081; 25 | 26 | public SchemaRegistryContainer(final KafkaContainer kafka) { 27 | this("5.4.3", kafka); 28 | } 29 | 30 | public SchemaRegistryContainer(final String confluentPlatformVersion, final KafkaContainer kafka) { 31 | super("confluentinc/cp-schema-registry:" + confluentPlatformVersion); 32 | 33 | dependsOn(kafka); 34 | withNetwork(kafka.getNetwork()); 35 | withNetworkAliases("schema-registry-" + Base58.randomString(6)); 36 | 37 | withEnv("SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS", 38 | String.format("PLAINTEXT://%s:%s", kafka.getNetworkAliases().get(0), 9092)); 39 | 40 | withExposedPorts(SCHEMA_REGISTRY_PORT); 41 | withEnv("SCHEMA_REGISTRY_HOST_NAME", "localhost"); 42 | } 43 | 44 | public String getSchemaRegistryUrl() { 45 | return String.format("http://%s:%s", getContainerIpAddress(), getMappedPort(SCHEMA_REGISTRY_PORT)); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/io/aiven/connect/jdbc/util/TimeZoneValidatorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2017 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.util.stream.Stream; 21 | 22 | import org.apache.kafka.common.config.ConfigException; 23 | 24 | import org.junit.jupiter.api.Test; 25 | 26 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 27 | 28 | public class TimeZoneValidatorTest { 29 | 30 | @Test 31 | public void testAccuracy() { 32 | final String[] validTimeZones = new String[]{ 33 | "Europe/Vienna", 34 | "Asia/Tokyo", 35 | "America/Los_Angeles", 36 | "UTC", 37 | "GMT+01:00", 38 | "UTC" 39 | }; 40 | 41 | Stream.of(validTimeZones) 42 | .forEach(timeZone -> TimeZoneValidator.INSTANCE.ensureValid("db.timezone", timeZone)); 43 | } 44 | 45 | @Test 46 | public void testTimeZoneNotSpecified() { 47 | TimeZoneValidator.INSTANCE.ensureValid("db.timezone", null); 48 | } 49 | 50 | @Test 51 | public void testInvalidTimeZone() { 52 | assertThatThrownBy(() -> TimeZoneValidator.INSTANCE.ensureValid("db.timezone", "invalid")) 53 | .isInstanceOf(ConfigException.class); 54 | } 55 | 56 | @Test 57 | public void testEmptyTimeZone() { 58 | assertThatThrownBy(() -> TimeZoneValidator.INSTANCE.ensureValid("db.timezone", "")) 59 | .isInstanceOf(ConfigException.class); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/config/DatabaseDialectRecommender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.config; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | import org.apache.kafka.common.config.ConfigDef; 25 | import org.apache.kafka.common.config.ConfigException; 26 | 27 | import io.aiven.connect.jdbc.dialect.DatabaseDialects; 28 | 29 | public class DatabaseDialectRecommender implements ConfigDef.Recommender, ConfigDef.Validator { 30 | 31 | public static final DatabaseDialectRecommender INSTANCE = new DatabaseDialectRecommender(); 32 | 33 | private static final List DIALECT_NAMES; 34 | 35 | static { 36 | DIALECT_NAMES = new ArrayList<>(); 37 | DIALECT_NAMES.add(""); 38 | DIALECT_NAMES.addAll(DatabaseDialects.registeredDialectNames()); 39 | } 40 | 41 | public List validValues(final String var1, final Map var2) { 42 | return DIALECT_NAMES; 43 | } 44 | 45 | public boolean visible(final String var1, final Map var2) { 46 | return true; 47 | } 48 | 49 | @Override 50 | public void ensureValid(final String key, final Object value) { 51 | if (value != null && !DIALECT_NAMES.contains(value.toString())) { 52 | throw new ConfigException(key, value, "Invalid enumerator"); 53 | } 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return DIALECT_NAMES.toString(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aiven's JDBC Sink and Source Connectors for Apache Kafka® 2 | 3 | This repository includes a Source connector that allows transfering data from a relational database into Apache Kafka topics 4 | and a Sink connector that allows to transfer data from Kafka topics into a relational database 5 | [Apache Kafka Connect](http://kafka.apache.org/documentation.html#connect) over JDBC. 6 | 7 | The project originates from Confluent 8 | [kafka-connect-jdbc](https://github.com/confluentinc/kafka-connect-jdbc). 9 | The code was forked before the change of the project's license. We want 10 | to thank the Confluent team for their efforts in developing the 11 | connector and aim to continue keeping this fork well-maintained and 12 | truly open. 13 | 14 | ## Documentation 15 | 16 | The documentation can be found in the `docs/` directory of the source code 17 | 18 | For the Source connector it could be found at 19 | [here](docs/source-connector.md). 20 | 21 | For the Sink connector it could be found at 22 | [here](docs/sink-connector.md). 23 | 24 | ## Building from source 25 | 26 | Prerequisites for building JDBC connector for Apache Kafka: 27 | 28 | * Git 29 | * Java 11 30 | 31 | ``` 32 | git clone git@github.com:aiven/jdbc-connector-for-apache-kafka.git 33 | cd jdbc-connector-for-apache-kafka 34 | ./gradlew clean build 35 | ``` 36 | 37 | To publish to maven local use 38 | ``` 39 | ./gradlew clean build publishToMavenLocal 40 | ``` 41 | 42 | ## Contribute 43 | 44 | [Source Code](https://github.com/aiven/jdbc-connector-for-apache-kafka) 45 | 46 | [Issue Tracker](https://github.com/aiven/jdbc-connector-for-apache-kafka/issues) 47 | 48 | ## License 49 | 50 | The project is licensed under the 51 | [Apache 2 license](https://www.apache.org/licenses/LICENSE-2.0). See 52 | [LICENSE](LICENSE). 53 | 54 | ## Security 55 | 56 | Security policies can be found [here](SECURITY.md) and the list of known vulnerabilities [here](cve-list.md) 57 | 58 | ## Trademark 59 | Apache Kafka, Apache Kafka Connect are either registered trademarks or trademarks of the Apache Software Foundation in the United States and/or other countries. Kafka Connect JDBC is trademark and property of their respective owners. All product and service names used in this page are for identification purposes only and do not imply endorsement. 60 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/sink/metadata/SinkRecordField.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2016 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.sink.metadata; 19 | 20 | import java.util.Map; 21 | 22 | import org.apache.kafka.connect.data.Schema; 23 | 24 | public class SinkRecordField { 25 | 26 | private final Schema schema; 27 | private final String name; 28 | private final boolean isPrimaryKey; 29 | 30 | public SinkRecordField(final Schema schema, final String name, final boolean isPrimaryKey) { 31 | this.schema = schema; 32 | this.name = name; 33 | this.isPrimaryKey = isPrimaryKey; 34 | } 35 | 36 | public Schema schema() { 37 | return schema; 38 | } 39 | 40 | public String schemaName() { 41 | return schema.name(); 42 | } 43 | 44 | public Map schemaParameters() { 45 | return schema.parameters(); 46 | } 47 | 48 | public Schema.Type schemaType() { 49 | return schema.type(); 50 | } 51 | 52 | public String name() { 53 | return name; 54 | } 55 | 56 | public boolean isOptional() { 57 | return !isPrimaryKey && schema.isOptional(); 58 | } 59 | 60 | public Object defaultValue() { 61 | return schema.defaultValue(); 62 | } 63 | 64 | public boolean isPrimaryKey() { 65 | return isPrimaryKey; 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return "SinkRecordField{" 71 | + "schema=" + schema 72 | + ", name='" + name + '\'' 73 | + ", isPrimaryKey=" + isPrimaryKey 74 | + '}'; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /.github/workflows/release_pr_workflow.yml: -------------------------------------------------------------------------------- 1 | # The workflow to create PRs with release commits. 2 | name: Create release PR 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_version: 7 | description: "Release version '0.1.2' (without 'v')" 8 | required: true 9 | snapshot_version: 10 | description: "Snapshot version '0.2.0-SNAPSHOT' (without 'v')" 11 | required: true 12 | 13 | permissions: 14 | contents: write 15 | pull-requests: write 16 | 17 | jobs: 18 | create_release_pr: 19 | name: Create release PR (job) 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Check versions 23 | run: | 24 | echo "Checking release version..." 25 | if echo ${{ github.event.inputs.release_version }} | grep --invert-match '^[0-9]\+\.[0-9]\+\.[0-9]\+$' > /dev/null; then 26 | echo "Release version is invalid" 27 | exit 1 28 | fi 29 | 30 | echo "Checking snapshot version..." 31 | if echo ${{ github.event.inputs.snapshot_version }} | grep --invert-match '^[0-9]\+\.[0-9]\+\.[0-9]\+-SNAPSHOT$' > /dev/null; then 32 | echo "Snapshot version is invalid" 33 | exit 1 34 | fi 35 | 36 | - name: Checkout master 37 | uses: actions/checkout@v2 38 | with: 39 | ref: master 40 | fetch-depth: 0 41 | 42 | - name: Create release commits 43 | run: | 44 | git config --local user.name "GitHub Action" 45 | git config --local user.email "action@github.com" 46 | sed -i -e "s/^version=.\+$/version=${{ github.event.inputs.release_version }}/g" gradle.properties 47 | git add gradle.properties 48 | git commit -m "Release version ${{ github.event.inputs.release_version }}" 49 | sed -i -e "s/^version=.\+$/version=${{ github.event.inputs.snapshot_version }}/g" gradle.properties 50 | git add gradle.properties 51 | git commit -m "Bump version to ${{ github.event.inputs.snapshot_version }}" 52 | 53 | - name: Create Pull Request 54 | uses: peter-evans/create-pull-request@v3 55 | with: 56 | branch: release-${{ github.event.inputs.release_version }} 57 | delete-branch: true 58 | draft: true 59 | title: Release version ${{ github.event.inputs.release_version }} 60 | body: | 61 | Proposed changelog: 62 | - *fill in* 63 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/source/JdbcSourceTaskConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2015 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.source; 19 | 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | import org.apache.kafka.common.config.ConfigDef; 24 | import org.apache.kafka.common.config.ConfigDef.Importance; 25 | import org.apache.kafka.common.config.ConfigDef.Type; 26 | import org.apache.kafka.common.config.ConfigException; 27 | 28 | /** 29 | * Configuration options for a single JdbcSourceTask. These are processed after all 30 | * Connector-level configs have been parsed. 31 | */ 32 | public class JdbcSourceTaskConfig extends JdbcSourceConnectorConfig { 33 | 34 | public static final String TABLES_CONFIG = "tables"; 35 | private static final String TABLES_DOC = "List of tables encoded as a comma separated string" 36 | + " for this task to watch for changes."; 37 | public static final String TABLES_DEFAULT = ""; 38 | 39 | 40 | static ConfigDef config = baseConfigDef() 41 | .define(TABLES_CONFIG, Type.LIST, TABLES_DEFAULT, Importance.HIGH, TABLES_DOC); 42 | 43 | public JdbcSourceTaskConfig(final Map props) { 44 | super(config, props); 45 | } 46 | 47 | public void validate() throws ConfigException { 48 | final List tables = this.getList(JdbcSourceTaskConfig.TABLES_CONFIG); 49 | final String query = this.getString(JdbcSourceTaskConfig.QUERY_CONFIG); 50 | if (tables.isEmpty() && query.isEmpty() || !tables.isEmpty() && !query.isEmpty()) { 51 | throw new org.apache.kafka.connect.errors.ConnectException( 52 | "Invalid configuration: each JdbcSourceTask must have at " 53 | + "least one table assigned to it or one query specified"); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/ConnectionProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.sql.Connection; 21 | import java.sql.SQLException; 22 | 23 | /** 24 | * A provider of JDBC {@link Connection} instances. 25 | */ 26 | public interface ConnectionProvider extends AutoCloseable { 27 | 28 | /** 29 | * Create a connection. 30 | * 31 | * @return the connection; never null 32 | * @throws SQLException if there is a problem getting the connection 33 | */ 34 | Connection getConnection() throws SQLException; 35 | 36 | /** 37 | * Determine if the specified connection is valid. 38 | * 39 | * @param connection the database connection; may not be null 40 | * @param timeout The time in seconds to wait for the database operation used to validate 41 | * the connection to complete. If the timeout period expires before the 42 | * operation completes, this method returns false. A value of 0 indicates a 43 | * timeout is not applied to the database operation. 44 | * @return true if it is valid, or false otherwise 45 | * @throws SQLException if there is an error with the database connection 46 | */ 47 | boolean isConnectionValid( 48 | Connection connection, 49 | int timeout 50 | ) throws SQLException; 51 | 52 | /** 53 | * Close this connection provider. 54 | */ 55 | void close(); 56 | 57 | /** 58 | * Get the publicly viewable identifier for this connection provider and / or the database. 59 | * The resulting value should not contain any secrets or passwords. 60 | * 61 | * @return the identifier; never null 62 | */ 63 | default String identifier() { 64 | return toString(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/source/OffsetProtocols.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.source; 19 | 20 | import java.util.Collections; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | import io.aiven.connect.jdbc.util.ExpressionBuilder; 25 | import io.aiven.connect.jdbc.util.TableId; 26 | 27 | /** 28 | * Provides helper methods to get partition map for different protocol versions. 29 | */ 30 | public class OffsetProtocols { 31 | 32 | /** 33 | * Provides the partition map for V1 protocol. The table name included is fully qualified 34 | * and there is also an explicit protocol key. 35 | * 36 | * @param tableId the tableId that requires partition keys 37 | * @return the partition map for V1 protocol 38 | */ 39 | public static Map sourcePartitionForProtocolV1(final TableId tableId) { 40 | final String fqn = ExpressionBuilder.create().append(tableId, false).toString(); 41 | final Map partitionForV1 = new HashMap<>(); 42 | partitionForV1.put(JdbcSourceConnectorConstants.TABLE_NAME_KEY, fqn); 43 | partitionForV1.put( 44 | JdbcSourceConnectorConstants.OFFSET_PROTOCOL_VERSION_KEY, 45 | JdbcSourceConnectorConstants.PROTOCOL_VERSION_ONE 46 | ); 47 | return partitionForV1; 48 | } 49 | 50 | /** 51 | * Provides the partition map for V0 protocol. The table name included is unqualified 52 | * and there is no explicit protocol key. 53 | * 54 | * @param tableId the tableId that requires partition keys 55 | * @return the partition map for V0 protocol 56 | */ 57 | public static Map sourcePartitionForProtocolV0(final TableId tableId) { 58 | return Collections.singletonMap( 59 | JdbcSourceConnectorConstants.TABLE_NAME_KEY, 60 | tableId.tableName() 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /checkstyle/suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 21 | 22 | 23 | 24 | 26 | 27 | 29 | 30 | 32 | 33 | 35 | 36 | 38 | 39 | 41 | 42 | 45 | 46 | 47 | 48 | 49 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/test/java/io/aiven/connect/jdbc/source/MockTime.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2016 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.source; 19 | 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.function.Supplier; 22 | 23 | import org.apache.kafka.common.errors.TimeoutException; 24 | import org.apache.kafka.common.utils.Time; 25 | 26 | /** 27 | * A clock that you can manually advance by calling sleep 28 | */ 29 | public class MockTime implements Time { 30 | 31 | private long nanos; 32 | private long autoTickMs; 33 | 34 | public MockTime() { 35 | this.nanos = System.nanoTime(); 36 | } 37 | 38 | public MockTime(final long autoTickMs) { 39 | this.nanos = System.nanoTime(); 40 | this.autoTickMs = autoTickMs; 41 | } 42 | 43 | @Override 44 | public long milliseconds() { 45 | this.sleep(autoTickMs); 46 | return TimeUnit.MILLISECONDS.convert(this.nanos, TimeUnit.NANOSECONDS); 47 | } 48 | 49 | @Override 50 | public long hiResClockMs() { 51 | return TimeUnit.NANOSECONDS.toMillis(nanoseconds()); 52 | } 53 | 54 | @Override 55 | public long nanoseconds() { 56 | this.sleep(autoTickMs); 57 | return nanos; 58 | } 59 | 60 | @Override 61 | public void sleep(final long ms) { 62 | this.nanos += TimeUnit.NANOSECONDS.convert(ms, TimeUnit.MILLISECONDS); 63 | } 64 | 65 | @Override 66 | public void waitObject(final Object object, final Supplier condition, final long deadlineMs) 67 | throws InterruptedException { 68 | synchronized (object) { 69 | while (true) { 70 | if (condition.get()) { 71 | return; 72 | } 73 | 74 | final long currentTimeMs = milliseconds(); 75 | if (currentTimeMs >= deadlineMs) { 76 | throw new TimeoutException("Condition not satisfied before deadline"); 77 | } 78 | 79 | object.wait(deadlineMs - currentTimeMs); 80 | } 81 | } 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/JdbcSinkConnector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2016 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | import org.apache.kafka.common.config.Config; 25 | import org.apache.kafka.common.config.ConfigDef; 26 | import org.apache.kafka.connect.connector.Task; 27 | import org.apache.kafka.connect.sink.SinkConnector; 28 | 29 | import io.aiven.connect.jdbc.sink.JdbcSinkConfig; 30 | import io.aiven.connect.jdbc.sink.JdbcSinkTask; 31 | import io.aiven.connect.jdbc.util.Version; 32 | 33 | import org.slf4j.Logger; 34 | import org.slf4j.LoggerFactory; 35 | 36 | public final class JdbcSinkConnector extends SinkConnector { 37 | private static final Logger log = LoggerFactory.getLogger(JdbcSinkConnector.class); 38 | 39 | private Map configProps; 40 | 41 | public Class taskClass() { 42 | return JdbcSinkTask.class; 43 | } 44 | 45 | @Override 46 | public List> taskConfigs(final int maxTasks) { 47 | log.info("Setting task configurations for {} workers.", maxTasks); 48 | final List> configs = new ArrayList<>(maxTasks); 49 | for (int i = 0; i < maxTasks; ++i) { 50 | configs.add(configProps); 51 | } 52 | return configs; 53 | } 54 | 55 | @Override 56 | public void start(final Map props) { 57 | configProps = props; 58 | } 59 | 60 | @Override 61 | public void stop() { 62 | } 63 | 64 | @Override 65 | public ConfigDef config() { 66 | return JdbcSinkConfig.CONFIG_DEF; 67 | } 68 | 69 | @Override 70 | public Config validate(final Map connectorConfigs) { 71 | final Config config = super.validate(connectorConfigs); 72 | 73 | JdbcSinkConfig.validateDeleteEnabled(config); 74 | JdbcSinkConfig.validatePKModeAgainstPKFields(config); 75 | return config; 76 | } 77 | 78 | @Override 79 | public String version() { 80 | return Version.getVersion(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/io/aiven/connect/jdbc/util/CachedConnectionProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2017 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.sql.Connection; 21 | import java.sql.SQLException; 22 | 23 | import org.apache.kafka.connect.errors.ConnectException; 24 | 25 | import org.junit.jupiter.api.Test; 26 | import org.junit.jupiter.api.extension.ExtendWith; 27 | import org.mockito.Mock; 28 | import org.mockito.junit.jupiter.MockitoExtension; 29 | 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 32 | import static org.mockito.Mockito.mock; 33 | import static org.mockito.Mockito.times; 34 | import static org.mockito.Mockito.verify; 35 | import static org.mockito.Mockito.when; 36 | 37 | @ExtendWith(MockitoExtension.class) 38 | public class CachedConnectionProviderTest { 39 | 40 | @Mock 41 | private ConnectionProvider provider; 42 | 43 | @Test 44 | public void retryTillFailure() throws SQLException { 45 | final int retries = 15; 46 | final ConnectionProvider connectionProvider = new CachedConnectionProvider(provider, retries, 100L); 47 | when(provider.getConnection()).thenThrow(new SQLException("test")); 48 | 49 | assertThatThrownBy(connectionProvider::getConnection) 50 | .isInstanceOf(ConnectException.class); 51 | 52 | verify(provider, times(retries)).getConnection(); 53 | } 54 | 55 | 56 | @Test 57 | public void retryTillConnect() throws SQLException { 58 | final Connection connection = mock(Connection.class); 59 | final int retries = 4; 60 | 61 | final ConnectionProvider connectionProvider = new CachedConnectionProvider(provider, retries, 100L); 62 | when(provider.getConnection()) 63 | .thenThrow(new SQLException("test")) 64 | .thenThrow(new SQLException("test")) 65 | .thenThrow(new SQLException("test")) 66 | .thenReturn(connection); 67 | 68 | assertThat(connectionProvider.getConnection()).isNotNull(); 69 | verify(provider, times(4)).getConnection(); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /.github/workflows/create_release.yml: -------------------------------------------------------------------------------- 1 | name: Create release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | build: 13 | name: Create Release 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Setup Java SDK 17 | uses: actions/setup-java@v2 18 | with: 19 | distribution: "temurin" 20 | java-version: 17 21 | 22 | - name: Checkout code 23 | uses: actions/checkout@v4 24 | with: 25 | ref: ${{ github.ref }} 26 | 27 | - name: Check commit title and extract version 28 | run: | 29 | export commit_title=$(git log --pretty=format:%s -1 ${{ github.ref }}) 30 | echo "Commit title: $commit_title" 31 | if [[ $commit_title =~ ^Release\ version\ [0-9]*\.[0-9]*\.[0-9]*$ ]]; then 32 | echo "Valid commit title" 33 | else 34 | echo "Invalid commit title" 35 | exit 1 36 | fi 37 | export version=$(echo ${commit_title} | sed s/^Release\ version\ //g) 38 | echo "Will use version ${version}" 39 | echo "version=${version}" >> $GITHUB_ENV 40 | 41 | - name: Build 42 | run: | 43 | ./gradlew distTar distZip 44 | 45 | export tar_file=$(ls ./build/distributions/ | grep tar) 46 | export zip_file=$(ls ./build/distributions/ | grep zip) 47 | echo tar_file=${tar_file} >> $GITHUB_ENV 48 | echo zip_file=${zip_file} >> $GITHUB_ENV 49 | 50 | echo tar_path=`realpath ./build/distributions/${tar_file}` >> $GITHUB_ENV 51 | echo zip_path=`realpath ./build/distributions/${zip_file}` >> $GITHUB_ENV 52 | 53 | - name: Create release draft 54 | id: create_release 55 | uses: actions/create-release@v1 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | with: 59 | tag_name: "v${{ env.version }}" 60 | release_name: "v${{ env.version }}" 61 | commitish: ${{ github.sha }} 62 | body: | 63 | *Fill in* 64 | draft: true 65 | prerelease: false 66 | 67 | - name: Upload tar 68 | uses: actions/upload-release-asset@v1 69 | env: 70 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 71 | with: 72 | upload_url: ${{ steps.create_release.outputs.upload_url }} 73 | asset_path: ${{ env.tar_path }} 74 | asset_name: ${{ env.tar_file }} 75 | asset_content_type: application/tar 76 | 77 | - name: Upload zip 78 | uses: actions/upload-release-asset@v1 79 | env: 80 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 81 | with: 82 | upload_url: ${{ steps.create_release.outputs.upload_url }} 83 | asset_path: ${{ env.zip_path }} 84 | asset_name: ${{ env.zip_file }} 85 | asset_content_type: application/zip 86 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '42 20 * * 6' 22 | 23 | permissions: 24 | actions: read 25 | contents: read 26 | security-events: write 27 | 28 | jobs: 29 | analyze: 30 | name: Analyze 31 | runs-on: ubuntu-latest 32 | 33 | strategy: 34 | fail-fast: false 35 | matrix: 36 | language: [ 'java' ] 37 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 38 | # Learn more: 39 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v3 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 54 | 55 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 56 | # If this step fails, then you should remove it and run the build manually (see below) 57 | #- name: Autobuild 58 | # uses: github/codeql-action/autobuild@v1 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 https://git.io/JvXDl 62 | 63 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 64 | # and modify them (or add more) to build your code if your project 65 | # uses a compiled language 66 | 67 | #- run: | 68 | # make bootstrap 69 | # make release 70 | - name: Set up JDK 17 71 | uses: actions/setup-java@v2 72 | with: 73 | distribution: "temurin" 74 | java-version: 17 75 | 76 | - name: Build with Gradle 77 | run: ./gradlew build 78 | 79 | - name: Perform CodeQL Analysis 80 | uses: github/codeql-action/analyze@v3 81 | -------------------------------------------------------------------------------- /src/test/java/io/aiven/connect/jdbc/sink/DbStructureTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2019 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.sink; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Arrays; 22 | import java.util.Collection; 23 | import java.util.HashSet; 24 | import java.util.List; 25 | import java.util.Set; 26 | 27 | import org.apache.kafka.connect.data.Schema; 28 | 29 | import io.aiven.connect.jdbc.sink.metadata.SinkRecordField; 30 | 31 | import org.junit.jupiter.api.Test; 32 | 33 | import static org.assertj.core.api.Assertions.assertThat; 34 | 35 | public class DbStructureTest { 36 | 37 | DbStructure structure = new DbStructure(null); 38 | 39 | @Test 40 | public void testNoMissingFields() { 41 | assertThat(missingFields(sinkRecords("aaa"), columns("aaa", "bbb"))).isEmpty(); 42 | } 43 | 44 | @Test 45 | public void testMissingFieldsWithSameCase() { 46 | assertThat(missingFields(sinkRecords("aaa", "bbb"), columns("aaa"))).hasSize(1); 47 | } 48 | 49 | @Test 50 | public void testSameNamesDifferentCases() { 51 | assertThat(missingFields(sinkRecords("aaa"), columns("aAa", "AaA"))).isEmpty(); 52 | } 53 | 54 | @Test 55 | public void testMissingFieldsWithDifferentCase() { 56 | assertThat(missingFields(sinkRecords("aaa", "bbb"), columns("AaA", "BbB"))).isEmpty(); 57 | assertThat(missingFields(sinkRecords("AaA", "bBb"), columns("aaa", "bbb"))).isEmpty(); 58 | assertThat(missingFields(sinkRecords("AaA", "bBb"), columns("aAa", "BbB"))).isEmpty(); 59 | } 60 | 61 | private Set missingFields( 62 | final Collection fields, 63 | final Set dbColumnNames 64 | ) { 65 | return structure.missingFields(fields, dbColumnNames); 66 | } 67 | 68 | static Set columns(final String... names) { 69 | return new HashSet<>(Arrays.asList(names)); 70 | } 71 | 72 | static List sinkRecords(final String... names) { 73 | final List fields = new ArrayList<>(); 74 | for (final String n : names) { 75 | fields.add(field(n)); 76 | } 77 | return fields; 78 | } 79 | 80 | static SinkRecordField field(final String name) { 81 | return new SinkRecordField(Schema.STRING_SCHEMA, name, false); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/DateTimeUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2016 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.text.SimpleDateFormat; 21 | import java.util.Calendar; 22 | import java.util.Date; 23 | import java.util.GregorianCalendar; 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | import java.util.TimeZone; 27 | 28 | public class DateTimeUtils { 29 | 30 | private static final ThreadLocal> TIMEZONE_CALENDARS = 31 | ThreadLocal.withInitial(HashMap::new); 32 | 33 | private static final ThreadLocal> TIMEZONE_DATE_FORMATS = 34 | ThreadLocal.withInitial(HashMap::new); 35 | 36 | private static final ThreadLocal> TIMEZONE_TIME_FORMATS = 37 | ThreadLocal.withInitial(HashMap::new); 38 | 39 | private static final ThreadLocal> TIMEZONE_TIMESTAMP_FORMATS = 40 | ThreadLocal.withInitial(HashMap::new); 41 | 42 | public static Calendar getTimeZoneCalendar(final TimeZone timeZone) { 43 | return TIMEZONE_CALENDARS.get().computeIfAbsent(timeZone, GregorianCalendar::new); 44 | } 45 | 46 | public static String formatDate(final Date date, final TimeZone timeZone) { 47 | return TIMEZONE_DATE_FORMATS.get().computeIfAbsent(timeZone, aTimeZone -> { 48 | final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 49 | sdf.setTimeZone(aTimeZone); 50 | return sdf; 51 | }).format(date); 52 | } 53 | 54 | public static String formatTime(final Date date, final TimeZone timeZone) { 55 | return TIMEZONE_TIME_FORMATS.get().computeIfAbsent(timeZone, aTimeZone -> { 56 | final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); 57 | sdf.setTimeZone(aTimeZone); 58 | return sdf; 59 | }).format(date); 60 | } 61 | 62 | public static String formatTimestamp(final Date date, final TimeZone timeZone) { 63 | return TIMEZONE_TIMESTAMP_FORMATS.get().computeIfAbsent(timeZone, aTimeZone -> { 64 | final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 65 | sdf.setTimeZone(aTimeZone); 66 | return sdf; 67 | }).format(date); 68 | } 69 | 70 | private DateTimeUtils() { 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/ColumnId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.util.Objects; 21 | 22 | public class ColumnId implements ExpressionBuilder.Expressable { 23 | 24 | private final TableId tableId; 25 | private final String name; 26 | private final String alias; 27 | private final int hash; 28 | 29 | public ColumnId( 30 | final TableId tableId, 31 | final String columnName 32 | ) { 33 | this(tableId, columnName, null); 34 | } 35 | 36 | public ColumnId( 37 | final TableId tableId, 38 | final String columnName, 39 | final String alias 40 | ) { 41 | assert columnName != null; 42 | this.tableId = tableId; 43 | this.name = columnName; 44 | this.alias = alias != null && !alias.trim().isEmpty() ? alias : name; 45 | this.hash = Objects.hash(this.tableId, this.name); 46 | } 47 | 48 | public TableId tableId() { 49 | return tableId; 50 | } 51 | 52 | public String name() { 53 | return name; 54 | } 55 | 56 | /** 57 | * Gets the column's suggested title for use in printouts and displays. The suggested title is 58 | * usually specified by the SQL AS clause. If a SQL AS is not 59 | * specified, the value will be the same as the value returned by the {@link #name()} method. 60 | * 61 | * @return the suggested column title; never null 62 | */ 63 | public String aliasOrName() { 64 | return alias; 65 | } 66 | 67 | @Override 68 | public void appendTo(final ExpressionBuilder builder, final boolean useQuotes) { 69 | if (tableId != null) { 70 | builder.append(tableId); 71 | builder.appendIdentifierDelimiter(); 72 | } 73 | builder.appendIdentifier(this.name, useQuotes); 74 | } 75 | 76 | @Override 77 | public int hashCode() { 78 | return hash; 79 | } 80 | 81 | @Override 82 | public boolean equals(final Object obj) { 83 | if (obj == this) { 84 | return true; 85 | } 86 | if (obj instanceof ColumnId) { 87 | final ColumnId that = (ColumnId) obj; 88 | return Objects.equals(this.name, that.name) && Objects.equals(this.alias, that.alias) 89 | && Objects.equals(this.tableId, that.tableId); 90 | } 91 | return false; 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | return ExpressionBuilder.create().append(this).toString(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/TableDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.util.Collection; 21 | import java.util.LinkedHashMap; 22 | import java.util.Map; 23 | import java.util.Set; 24 | 25 | /** 26 | * A description of a table. 27 | */ 28 | public class TableDefinition { 29 | private final TableId id; 30 | private final Map columnsByName = new LinkedHashMap<>(); 31 | private final Map pkColumnNames = new LinkedHashMap<>(); 32 | 33 | public TableDefinition( 34 | final TableId id, 35 | final Iterable columns 36 | ) { 37 | this.id = id; 38 | for (final ColumnDefinition defn : columns) { 39 | final String columnName = defn.id().name(); 40 | columnsByName.put( 41 | columnName, 42 | defn.forTable(this.id) 43 | ); 44 | if (defn.isPrimaryKey()) { 45 | this.pkColumnNames.put( 46 | columnName, 47 | columnName 48 | ); 49 | } 50 | } 51 | } 52 | 53 | public TableId id() { 54 | return id; 55 | } 56 | 57 | public int columnCount() { 58 | return columnsByName.size(); 59 | } 60 | 61 | public ColumnDefinition definitionForColumn(final String name) { 62 | return columnsByName.get(name); 63 | } 64 | 65 | public Collection definitionsForColumns() { 66 | return columnsByName.values(); 67 | } 68 | 69 | public Collection primaryKeyColumnNames() { 70 | return pkColumnNames.values(); 71 | } 72 | 73 | public Set columnNames() { 74 | return columnsByName.keySet(); 75 | } 76 | 77 | @Override 78 | public int hashCode() { 79 | return id.hashCode(); 80 | } 81 | 82 | @Override 83 | public boolean equals(final Object obj) { 84 | if (obj == null) { 85 | return true; 86 | } 87 | if (obj instanceof TableDefinition) { 88 | final TableDefinition that = (TableDefinition) obj; 89 | return this.id.equals(that.id()) && this.definitionsForColumns() 90 | .equals(that.definitionsForColumns()); 91 | } 92 | return false; 93 | } 94 | 95 | @Override 96 | public String toString() { 97 | return "Table{" + "name='" + id + '\'' + ", columns=" + definitionsForColumns() + '}'; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/test/java/io/aiven/connect/jdbc/source/NumericMappingConfigTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.source; 19 | 20 | import java.util.Arrays; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | import java.util.stream.Stream; 24 | 25 | import org.junit.jupiter.api.BeforeEach; 26 | import org.junit.jupiter.params.ParameterizedTest; 27 | import org.junit.jupiter.params.provider.MethodSource; 28 | 29 | import static io.aiven.connect.jdbc.source.JdbcSourceConnectorConfig.NumericMapping; 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | 32 | public class NumericMappingConfigTest { 33 | private Map props; 34 | 35 | public static Stream mapping() { 36 | return Arrays.stream( 37 | new Object[][]{ 38 | {NumericMapping.NONE, false, null}, 39 | {NumericMapping.NONE, false, "none"}, 40 | {NumericMapping.NONE, false, "NONE"}, 41 | {NumericMapping.PRECISION_ONLY, false, "precision_only"}, 42 | {NumericMapping.PRECISION_ONLY, false, "PRECISION_ONLY"}, 43 | {NumericMapping.BEST_FIT, false, "best_fit"}, 44 | {NumericMapping.BEST_FIT, false, "BEST_FIT"}, 45 | {NumericMapping.PRECISION_ONLY, true, null}, 46 | {NumericMapping.NONE, true, "none"}, 47 | {NumericMapping.NONE, true, "NONE"}, 48 | {NumericMapping.PRECISION_ONLY, true, "precision_only"}, 49 | {NumericMapping.PRECISION_ONLY, true, "PRECISION_ONLY"}, 50 | {NumericMapping.BEST_FIT, true, "best_fit"}, 51 | {NumericMapping.BEST_FIT, true, "BEST_FIT"} 52 | } 53 | ); 54 | } 55 | 56 | @BeforeEach 57 | public void setup() throws Exception { 58 | props = new HashMap<>(); 59 | } 60 | 61 | @ParameterizedTest 62 | @MethodSource("mapping") 63 | public void testNumericMapping(final NumericMapping expected, final boolean precisionMapping, 64 | final String extendedMapping) { 65 | props.put(JdbcSourceConnectorConfig.CONNECTION_URL_CONFIG, "jdbc:foo:bar"); 66 | props.put(JdbcSourceConnectorConfig.MODE_CONFIG, JdbcSourceConnectorConfig.MODE_BULK); 67 | props.put(JdbcSourceConnectorConfig.TOPIC_PREFIX_CONFIG, "test-"); 68 | props.put( 69 | JdbcSourceConnectorConfig.NUMERIC_PRECISION_MAPPING_CONFIG, 70 | String.valueOf(precisionMapping) 71 | ); 72 | if (extendedMapping != null) { 73 | props.put(JdbcSourceConnectorConfig.NUMERIC_MAPPING_CONFIG, extendedMapping); 74 | } 75 | final JdbcSourceConnectorConfig config = new JdbcSourceConnectorConfig(props); 76 | assertThat(NumericMapping.get(config)).isEqualTo(expected); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/io/aiven/connect/jdbc/sink/SqliteHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2016 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.sink; 19 | 20 | import java.io.IOException; 21 | import java.nio.file.Files; 22 | import java.nio.file.Path; 23 | import java.nio.file.Paths; 24 | import java.sql.Connection; 25 | import java.sql.DriverManager; 26 | import java.sql.ResultSet; 27 | import java.sql.SQLException; 28 | import java.sql.Statement; 29 | 30 | public final class SqliteHelper { 31 | 32 | static { 33 | try { 34 | Class.forName("org.sqlite.JDBC"); 35 | } catch (final ClassNotFoundException e) { 36 | throw new RuntimeException(e); 37 | } 38 | } 39 | 40 | public interface ResultSetReadCallback { 41 | void read(final ResultSet rs) throws SQLException; 42 | } 43 | 44 | public final Path dbPath; 45 | 46 | public Connection connection; 47 | 48 | public SqliteHelper(final String testId) { 49 | dbPath = Paths.get(testId + ".db"); 50 | } 51 | 52 | public String sqliteUri() { 53 | return "jdbc:sqlite:" + dbPath; 54 | } 55 | 56 | public void setUp() throws SQLException, IOException { 57 | Files.deleteIfExists(dbPath); 58 | connection = DriverManager.getConnection(sqliteUri()); 59 | connection.setAutoCommit(false); 60 | } 61 | 62 | public void tearDown() throws SQLException, IOException { 63 | connection.close(); 64 | Files.deleteIfExists(dbPath); 65 | } 66 | 67 | public void createTable(final String createSql) throws SQLException { 68 | execute(createSql); 69 | } 70 | 71 | public void deleteTable(final String table) throws SQLException { 72 | execute("DROP TABLE IF EXISTS " + table); 73 | 74 | //random errors of table not being available happens in the unit tests 75 | try { 76 | Thread.sleep(100); 77 | } catch (final InterruptedException e) { 78 | throw new RuntimeException(e); 79 | } 80 | } 81 | 82 | public int select(final String query, final SqliteHelper.ResultSetReadCallback callback) throws SQLException { 83 | int count = 0; 84 | try (final Statement stmt = connection.createStatement()) { 85 | try (final ResultSet rs = stmt.executeQuery(query)) { 86 | while (rs.next()) { 87 | callback.read(rs); 88 | count++; 89 | } 90 | } 91 | } 92 | return count; 93 | } 94 | 95 | public void execute(final String sql) throws SQLException { 96 | try (final Statement stmt = connection.createStatement()) { 97 | stmt.executeUpdate(sql); 98 | connection.commit(); 99 | } 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/util/TableDefinitions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.sql.Connection; 21 | import java.sql.SQLException; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | import io.aiven.connect.jdbc.dialect.DatabaseDialect; 26 | 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | 30 | /** 31 | * A simple cache of {@link TableDefinition} keyed. 32 | */ 33 | public class TableDefinitions { 34 | 35 | private static final Logger log = LoggerFactory.getLogger(TableDefinitions.class); 36 | 37 | private final Map cache = new HashMap<>(); 38 | private final DatabaseDialect dialect; 39 | 40 | /** 41 | * Create an instance that uses the specified database dialect. 42 | * 43 | * @param dialect the database dialect; may not be null 44 | */ 45 | public TableDefinitions(final DatabaseDialect dialect) { 46 | this.dialect = dialect; 47 | } 48 | 49 | /** 50 | * Get the {@link TableDefinition} for the given table. 51 | * 52 | * @param connection the JDBC connection to use; may not be null 53 | * @param tableId the table identifier; may not be null 54 | * @return the cached {@link TableDefinition}, or null if there is no such table 55 | * @throws SQLException if there is any problem using the connection 56 | */ 57 | public TableDefinition get( 58 | final Connection connection, 59 | final TableId tableId 60 | ) throws SQLException { 61 | TableDefinition dbTable = cache.get(tableId); 62 | if (dbTable == null) { 63 | if (dialect.tableExists(connection, tableId)) { 64 | dbTable = dialect.describeTable(connection, tableId); 65 | if (dbTable != null) { 66 | log.info("Setting metadata for table {} to {}", tableId, dbTable); 67 | cache.put(tableId, dbTable); 68 | } 69 | } 70 | } 71 | return dbTable; 72 | } 73 | 74 | /** 75 | * Refresh the cached {@link TableDefinition} for the given table. 76 | * 77 | * @param connection the JDBC connection to use; may not be null 78 | * @param tableId the table identifier; may not be null 79 | * @return the refreshed {@link TableDefinition}, or null if there is no such table 80 | * @throws SQLException if there is any problem using the connection 81 | */ 82 | public TableDefinition refresh( 83 | final Connection connection, 84 | final TableId tableId 85 | ) throws SQLException { 86 | final TableDefinition dbTable = dialect.describeTable(connection, tableId); 87 | log.info("Refreshing metadata for table {} to {}", tableId, dbTable); 88 | cache.put(dbTable.id(), dbTable); 89 | return dbTable; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/io/aiven/connect/jdbc/util/DatabaseHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2016 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.util; 19 | 20 | import java.io.IOException; 21 | import java.sql.Connection; 22 | import java.sql.ResultSet; 23 | import java.sql.SQLException; 24 | import java.sql.Statement; 25 | 26 | import io.aiven.connect.jdbc.dialect.DatabaseDialect; 27 | import io.aiven.connect.jdbc.dialect.DropOptions; 28 | 29 | public final class DatabaseHelper { 30 | 31 | public interface ResultSetReadCallback { 32 | void read(final ResultSet rs) throws SQLException; 33 | } 34 | 35 | public final DatabaseDialect dialect; 36 | private Connection connection; 37 | 38 | public DatabaseHelper(final DatabaseDialect dialect) { 39 | this.dialect = dialect; 40 | } 41 | 42 | public void setUp() throws SQLException { 43 | connection = dialect.getConnection(); 44 | } 45 | 46 | public void tearDown() throws SQLException, IOException { 47 | try { 48 | if (connection != null) { 49 | connection.close(); 50 | } 51 | } finally { 52 | if (dialect != null) { 53 | dialect.close(); 54 | } 55 | } 56 | } 57 | 58 | public void createTable(final String createSql) throws SQLException { 59 | execute(createSql); 60 | } 61 | 62 | public void deleteTable(final TableId tableId) throws SQLException { 63 | deleteTable(tableId, new DropOptions().setIfExists(true)); 64 | } 65 | 66 | public void deleteTable(final TableId tableId, final DropOptions options) throws SQLException { 67 | final String sql = dialect.buildDropTableStatement(tableId, options); 68 | execute(sql); 69 | 70 | //random errors of table not being available happens in the unit tests 71 | try { 72 | Thread.sleep(100); 73 | } catch (final InterruptedException e) { 74 | throw new RuntimeException(e); 75 | } 76 | } 77 | 78 | public int select(final String query, final DatabaseHelper.ResultSetReadCallback callback) throws SQLException { 79 | int count = 0; 80 | try (final Statement stmt = connection.createStatement()) { 81 | try (final ResultSet rs = stmt.executeQuery(query)) { 82 | while (rs.next()) { 83 | callback.read(rs); 84 | count++; 85 | } 86 | } 87 | } 88 | return count; 89 | } 90 | 91 | public void execute(final String sql) throws SQLException { 92 | try (final Statement stmt = connection.createStatement()) { 93 | stmt.executeUpdate(sql); 94 | if (!connection.getAutoCommit()) { 95 | connection.commit(); 96 | } 97 | } 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/integrationTest/java/io/aiven/kafka/connect/jdbc/oracle/AbstractOracleIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.aiven.kafka.connect.jdbc.oracle; 18 | 19 | import javax.sql.DataSource; 20 | 21 | import java.sql.Connection; 22 | import java.sql.SQLException; 23 | import java.sql.Statement; 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | 27 | import io.aiven.kafka.connect.jdbc.AbstractIT; 28 | 29 | import oracle.jdbc.pool.OracleDataSource; 30 | import org.testcontainers.junit.jupiter.Container; 31 | import org.testcontainers.oracle.OracleContainer; 32 | import org.testcontainers.utility.DockerImageName; 33 | 34 | public class AbstractOracleIT extends AbstractIT { 35 | 36 | public static final String DEFAULT_ORACLE_TAG = "slim-faststart"; 37 | private static final DockerImageName DEFAULT_ORACLE_IMAGE_NAME = 38 | DockerImageName.parse("gvenzl/oracle-free") 39 | .withTag(DEFAULT_ORACLE_TAG); 40 | @Container 41 | protected final OracleContainer oracleContainer = new OracleContainer(DEFAULT_ORACLE_IMAGE_NAME); 42 | 43 | protected void executeSqlStatement(final String sqlStatement) throws SQLException { 44 | try (final Connection connection = getDatasource().getConnection(); 45 | final Statement statement = connection.createStatement()) { 46 | statement.executeUpdate(sqlStatement); 47 | } 48 | } 49 | 50 | protected DataSource getDatasource() throws SQLException { 51 | final OracleDataSource dataSource = new OracleDataSource(); 52 | dataSource.setServerName(oracleContainer.getHost()); 53 | // Assuming the default Oracle port is 1521 54 | dataSource.setPortNumber(oracleContainer.getMappedPort(1521)); 55 | // Or use setDatabaseName() if that's how your Oracle is configured 56 | dataSource.setServiceName(oracleContainer.getDatabaseName()); 57 | dataSource.setUser(oracleContainer.getUsername()); 58 | dataSource.setPassword(oracleContainer.getPassword()); 59 | dataSource.setDriverType("thin"); 60 | return dataSource; 61 | } 62 | 63 | 64 | protected Map basicConnectorConfig() { 65 | final HashMap config = new HashMap<>(); 66 | config.put("tasks.max", "1"); 67 | config.put("connection.url", oracleContainer.getJdbcUrl()); 68 | config.put("connection.user", oracleContainer.getUsername()); 69 | config.put("connection.password", oracleContainer.getPassword()); 70 | config.put("dialect.name", "OracleDatabaseDialect"); 71 | config.put("key.converter", "io.confluent.connect.avro.AvroConverter"); 72 | config.put("key.converter.schema.registry.url", schemaRegistryContainer.getSchemaRegistryUrl()); 73 | config.put("value.converter", "io.confluent.connect.avro.AvroConverter"); 74 | config.put("value.converter.schema.registry.url", schemaRegistryContainer.getSchemaRegistryUrl()); 75 | return config; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/integrationTest/java/io/aiven/kafka/connect/jdbc/postgres/AbstractPostgresIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.aiven.kafka.connect.jdbc.postgres; 18 | 19 | import javax.sql.DataSource; 20 | 21 | import java.sql.Connection; 22 | import java.sql.SQLException; 23 | import java.sql.Statement; 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | 27 | import io.aiven.kafka.connect.jdbc.AbstractIT; 28 | 29 | import org.assertj.core.util.Arrays; 30 | import org.postgresql.ds.PGSimpleDataSource; 31 | import org.testcontainers.containers.PostgreSQLContainer; 32 | import org.testcontainers.junit.jupiter.Container; 33 | import org.testcontainers.utility.DockerImageName; 34 | 35 | public class AbstractPostgresIT extends AbstractIT { 36 | 37 | public static final String DEFAULT_POSTGRES_TAG = "10.20"; 38 | private static final DockerImageName DEFAULT_POSTGRES_IMAGE_NAME = 39 | DockerImageName.parse("postgres") 40 | .withTag(DEFAULT_POSTGRES_TAG); 41 | 42 | @Container 43 | protected final PostgreSQLContainer postgreSqlContainer = new PostgreSQLContainer<>(DEFAULT_POSTGRES_IMAGE_NAME) 44 | .withStartupTimeout(CONTAINER_STARTUP_TIMEOUT); 45 | 46 | protected void executeSqlStatement(final String sqlStatement) throws SQLException { 47 | try (final Connection connection = getDatasource().getConnection(); 48 | final Statement statement = connection.createStatement()) { 49 | statement.executeUpdate(sqlStatement); 50 | } 51 | } 52 | 53 | protected DataSource getDatasource() { 54 | final PGSimpleDataSource pgSimpleDataSource = new PGSimpleDataSource(); 55 | pgSimpleDataSource.setServerNames(Arrays.array(postgreSqlContainer.getHost())); 56 | pgSimpleDataSource.setPortNumbers(new int[] {postgreSqlContainer.getMappedPort(5432)}); 57 | pgSimpleDataSource.setDatabaseName(postgreSqlContainer.getDatabaseName()); 58 | pgSimpleDataSource.setUser(postgreSqlContainer.getUsername()); 59 | pgSimpleDataSource.setPassword(postgreSqlContainer.getPassword()); 60 | return pgSimpleDataSource; 61 | } 62 | 63 | protected Map basicConnectorConfig() { 64 | final HashMap config = new HashMap<>(); 65 | config.put("key.converter", "io.confluent.connect.avro.AvroConverter"); 66 | config.put("key.converter.schema.registry.url", schemaRegistryContainer.getSchemaRegistryUrl()); 67 | config.put("value.converter", "io.confluent.connect.avro.AvroConverter"); 68 | config.put("value.converter.schema.registry.url", schemaRegistryContainer.getSchemaRegistryUrl()); 69 | config.put("tasks.max", "1"); 70 | config.put("connection.url", postgreSqlContainer.getJdbcUrl()); 71 | config.put("connection.user", postgreSqlContainer.getUsername()); 72 | config.put("connection.password", postgreSqlContainer.getPassword()); 73 | config.put("dialect.name", "PostgreSqlDatabaseDialect"); 74 | return config; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/dialect/DropOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.dialect; 19 | 20 | import java.util.Objects; 21 | 22 | /** 23 | * Options for dropping objects from a database. To use, simply create a new instance and then 24 | * use the setter methods. 25 | */ 26 | public class DropOptions { 27 | 28 | private final boolean ifExists; 29 | private final boolean cascade; 30 | 31 | /** 32 | * Create a new instance with the default settings. 33 | */ 34 | public DropOptions() { 35 | this(false, false); 36 | } 37 | 38 | protected DropOptions( 39 | final boolean ifExists, 40 | final boolean cascade 41 | ) { 42 | this.ifExists = ifExists; 43 | this.cascade = cascade; 44 | } 45 | 46 | /** 47 | * Get whether the 'IF EXISTS' clause should be used with the 'DROP' statement. 48 | * 49 | * @return true if the object should be dropped only if it already exists, or false otherwise 50 | */ 51 | public boolean ifExists() { 52 | return ifExists; 53 | } 54 | 55 | /** 56 | * Get whether the 'DROP' statement should cascade to dependent objects. 57 | * 58 | * @return true if dependent objects should also be dropped, or false otherwise 59 | */ 60 | public boolean cascade() { 61 | return cascade; 62 | } 63 | 64 | /** 65 | * Set whether the 'IF EXISTS' clause should be used with the 'DROP' statement. 66 | * 67 | * @param ifExists true if the object should be dropped only if it already exists 68 | * @return a new options object with the current state plus the new if-exists state; never null 69 | */ 70 | public DropOptions setIfExists(final boolean ifExists) { 71 | return new DropOptions(ifExists, cascade); 72 | } 73 | 74 | /** 75 | * Set whether the 'DROP' statement should cascade to dependent objects. 76 | * 77 | * @param cascade true if dependent objects should also be dropped, or false otherwise 78 | * @return a new options object with the current state plus the new cascade state; never null 79 | */ 80 | public DropOptions setCascade(final boolean cascade) { 81 | return new DropOptions(ifExists, cascade); 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return "DropOptions{ifExists=" + ifExists + ", cascade=" + cascade + "}"; 87 | } 88 | 89 | @Override 90 | public int hashCode() { 91 | return Objects.hash(ifExists, cascade); 92 | } 93 | 94 | @Override 95 | public boolean equals(final Object obj) { 96 | if (obj == this) { 97 | return true; 98 | } 99 | if (obj instanceof DropOptions) { 100 | final DropOptions that = (DropOptions) obj; 101 | return this.ifExists() == that.ifExists() && this.cascade() == that.cascade(); 102 | } 103 | return false; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/source/ColumnMapping.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.source; 19 | 20 | import java.sql.ResultSet; 21 | import java.util.Objects; 22 | 23 | import org.apache.kafka.connect.data.Field; 24 | import org.apache.kafka.connect.data.Schema; 25 | 26 | import io.aiven.connect.jdbc.util.ColumnDefinition; 27 | 28 | /** 29 | * A mapping of a {@link ColumnDefinition result set column definition} and a {@link Field} within a 30 | * {@link Schema}. 31 | */ 32 | public class ColumnMapping { 33 | 34 | private final Field field; 35 | private final ColumnDefinition columnDefn; 36 | private final int columnNumber; 37 | private final int hash; 38 | 39 | /** 40 | * Create the column mapping. 41 | * 42 | * @param columnDefn the definition of the column; may not be null 43 | * @param columnNumber the 1-based number of the column within the result set; must be positive 44 | * @param field the corresponding {@link Field} within the {@link Schema}; may not be null 45 | */ 46 | public ColumnMapping( 47 | final ColumnDefinition columnDefn, 48 | final int columnNumber, 49 | final Field field 50 | ) { 51 | assert columnDefn != null; 52 | assert field != null; 53 | assert columnNumber > 0; 54 | this.columnDefn = columnDefn; 55 | this.field = field; 56 | this.columnNumber = columnNumber; 57 | this.hash = Objects.hash(this.columnNumber, this.columnDefn, this.field); 58 | } 59 | 60 | /** 61 | * Get this mapping's {@link Field}. 62 | * 63 | * @return the field; never null 64 | */ 65 | public Field field() { 66 | return field; 67 | } 68 | 69 | /** 70 | * Get this mapping's {@link ColumnDefinition result set column definition}. 71 | * 72 | * @return the column definition; never null 73 | */ 74 | public ColumnDefinition columnDefn() { 75 | return columnDefn; 76 | } 77 | 78 | /** 79 | * Get the 1-based number of the column within the result set. This can be used to access the 80 | * corresponding value from the {@link ResultSet}. 81 | * 82 | * @return the column number within the {@link ResultSet}; always positive 83 | */ 84 | public int columnNumber() { 85 | return columnNumber; 86 | } 87 | 88 | @Override 89 | public int hashCode() { 90 | return hash; 91 | } 92 | 93 | @Override 94 | public boolean equals(final Object obj) { 95 | if (obj == this) { 96 | return true; 97 | } 98 | if (obj instanceof ColumnMapping) { 99 | final ColumnMapping that = (ColumnMapping) obj; 100 | return this.columnNumber == that.columnNumber && Objects.equals( 101 | this.columnDefn, that.columnDefn) && Objects.equals(this.field, that.field); 102 | } 103 | return false; 104 | } 105 | 106 | @Override 107 | public String toString() { 108 | return field.name() + " (col=" + columnNumber + ", " + columnDefn + ")"; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 7. Before merging, clean up the commit history for the PR. Each commit should be self-contained with an informative message, since each commit will be added to the history for this project. 39 | 40 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 41 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 42 | 43 | ## Developer Certificate of Origin 44 | 45 | JDBC connector for Apache Kafka is an open source product released under the Apache 2.0 license (see either [the Apache site](https://www.apache.org/licenses/LICENSE-2.0) or the [LICENSE.txt file](LICENSE.txt)). The Apache 2.0 license allows you to freely use, modify, distribute, and sell your own products that include Apache 2.0 licensed software. 46 | 47 | We respect intellectual property rights of others and we want to make sure all incoming contributions are correctly attributed and licensed. A Developer Certificate of Origin (DCO) is a lightweight mechanism to do that. 48 | 49 | So we require by making a contribution every contributor certifies that: 50 | ``` 51 | The contribution was created in whole or in part by me and I have the right to submit it under the open source license 52 | indicated in the file 53 | ``` 54 | 55 | ## Finding contributions to work on 56 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 57 | 58 | 59 | ## Code of Conduct 60 | This project has adopted the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). 61 | For more information see the [Code of Conduct FAQ](https://www.contributor-covenant.org/faq/). 62 | 63 | 64 | ## Security issue notifications 65 | If you discover a potential security issue in this project we ask that you report it according to [Security Policy](SECURITY.md). Please do **not** create a public github issue. 66 | 67 | ## Licensing 68 | 69 | See the [LICENSE](LICENSE.txt) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 70 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/dialect/VerticaDatabaseDialect.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2018 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.dialect; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Collection; 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | import org.apache.kafka.connect.data.Date; 26 | import org.apache.kafka.connect.data.Decimal; 27 | import org.apache.kafka.connect.data.Time; 28 | import org.apache.kafka.connect.data.Timestamp; 29 | 30 | import io.aiven.connect.jdbc.config.JdbcConfig; 31 | import io.aiven.connect.jdbc.dialect.DatabaseDialectProvider.SubprotocolBasedProvider; 32 | import io.aiven.connect.jdbc.sink.metadata.SinkRecordField; 33 | import io.aiven.connect.jdbc.util.IdentifierRules; 34 | import io.aiven.connect.jdbc.util.TableId; 35 | 36 | /** 37 | * A {@link DatabaseDialect} for Vertica. 38 | */ 39 | public class VerticaDatabaseDialect extends GenericDatabaseDialect { 40 | /** 41 | * The provider for {@link VerticaDatabaseDialect}. 42 | */ 43 | public static class Provider extends SubprotocolBasedProvider { 44 | public Provider() { 45 | super(VerticaDatabaseDialect.class.getSimpleName(), "vertica"); 46 | } 47 | 48 | @Override 49 | public DatabaseDialect create(final JdbcConfig config) { 50 | return new VerticaDatabaseDialect(config); 51 | } 52 | } 53 | 54 | /** 55 | * Create a new dialect instance with the given connector configuration. 56 | * 57 | * @param config the connector configuration; may not be null 58 | */ 59 | public VerticaDatabaseDialect(final JdbcConfig config) { 60 | super(config, new IdentifierRules(".", "\"", "\"")); 61 | } 62 | 63 | @Override 64 | protected String getSqlType(final SinkRecordField field) { 65 | if (field.schemaName() != null) { 66 | switch (field.schemaName()) { 67 | case Decimal.LOGICAL_NAME: 68 | return "DECIMAL(18," + field.schemaParameters().get(Decimal.SCALE_FIELD) + ")"; 69 | case Date.LOGICAL_NAME: 70 | return "DATE"; 71 | case Time.LOGICAL_NAME: 72 | return "TIME"; 73 | case Timestamp.LOGICAL_NAME: 74 | return "TIMESTAMP"; 75 | default: 76 | // fall through to non-logical types 77 | break; 78 | } 79 | } 80 | switch (field.schemaType()) { 81 | case INT8: 82 | return "INT"; 83 | case INT16: 84 | return "INT"; 85 | case INT32: 86 | return "INT"; 87 | case INT64: 88 | return "INT"; 89 | case FLOAT32: 90 | return "FLOAT"; 91 | case FLOAT64: 92 | return "FLOAT"; 93 | case BOOLEAN: 94 | return "BOOLEAN"; 95 | case STRING: 96 | return "VARCHAR(1024)"; 97 | case BYTES: 98 | return "VARBINARY(1024)"; 99 | default: 100 | return super.getSqlType(field); 101 | } 102 | } 103 | 104 | @Override 105 | public List buildAlterTable( 106 | final TableId table, 107 | final Collection fields 108 | ) { 109 | final List queries = new ArrayList<>(fields.size()); 110 | for (final SinkRecordField field : fields) { 111 | queries.addAll(super.buildAlterTable(table, Collections.singleton(field))); 112 | } 113 | return queries; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/io/aiven/connect/jdbc/source/JdbcSourceTaskConfigTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.aiven.connect.jdbc.source; 18 | 19 | import java.util.Collections; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | import org.apache.kafka.common.config.ConfigException; 25 | import org.apache.kafka.connect.errors.ConnectException; 26 | 27 | import io.aiven.connect.jdbc.config.JdbcConfig; 28 | 29 | import org.junit.Test; 30 | 31 | import static org.junit.jupiter.api.Assertions.assertEquals; 32 | import static org.junit.jupiter.api.Assertions.assertThrowsExactly; 33 | 34 | 35 | public final class JdbcSourceTaskConfigTest { 36 | 37 | @Test(expected = ConfigException.class) 38 | public void testValidateEmptyConfig() { 39 | new JdbcSourceTaskConfig(Collections.emptyMap()); 40 | } 41 | 42 | @Test 43 | public void testValidateTablesAndQueryMandatoryConfigPresent() { 44 | final Map properties = new HashMap<>(); 45 | properties.put(JdbcConfig.CONNECTION_URL_CONFIG, "connection-url"); 46 | properties.put(JdbcSourceConnectorConfig.MODE_CONFIG, "bulk"); 47 | properties.put(JdbcSourceConnectorConfig.TOPIC_PREFIX_CONFIG, "test-prefix"); 48 | final JdbcSourceTaskConfig config = new JdbcSourceTaskConfig(properties); 49 | assertThrowsExactly(ConnectException.class, config::validate, 50 | "Invalid configuration: each JdbcSourceTask must" 51 | + " have at least one table assigned to it or one query specified"); 52 | } 53 | 54 | 55 | @Test 56 | public void testValidateQueryAndTablesGiven() { 57 | final Map properties = new HashMap<>(); 58 | properties.put(JdbcSourceTaskConfig.TABLES_CONFIG, "test-table-1, test-table-2"); 59 | properties.put(JdbcSourceTaskConfig.QUERY_CONFIG, "test-query"); 60 | properties.put(JdbcConfig.CONNECTION_URL_CONFIG, "connection-url"); 61 | properties.put(JdbcSourceConnectorConfig.MODE_CONFIG, "bulk"); 62 | properties.put(JdbcSourceConnectorConfig.TOPIC_PREFIX_CONFIG, "test-prefix"); 63 | final JdbcSourceTaskConfig config = new JdbcSourceTaskConfig(properties); 64 | assertThrowsExactly(ConnectException.class, config::validate, 65 | "Invalid configuration: each JdbcSourceTask must" 66 | + " have at least one table assigned to it or one query specified"); 67 | } 68 | 69 | @Test 70 | public void testValidateQueryGiven() { 71 | final Map properties = new HashMap<>(); 72 | properties.put(JdbcSourceTaskConfig.QUERY_CONFIG, "test-query"); 73 | properties.put(JdbcConfig.CONNECTION_URL_CONFIG, "connection-url"); 74 | properties.put(JdbcSourceConnectorConfig.MODE_CONFIG, "bulk"); 75 | properties.put(JdbcSourceConnectorConfig.TOPIC_PREFIX_CONFIG, "test-prefix"); 76 | final JdbcSourceTaskConfig config = new JdbcSourceTaskConfig(properties); 77 | config.validate(); 78 | } 79 | 80 | @Test 81 | public void testValidateTablesGiven() { 82 | final Map properties = new HashMap<>(); 83 | properties.put(JdbcSourceTaskConfig.TABLES_CONFIG, "test-table-1, test-table-2"); 84 | properties.put(JdbcConfig.CONNECTION_URL_CONFIG, "connection-url"); 85 | properties.put(JdbcSourceConnectorConfig.MODE_CONFIG, "bulk"); 86 | properties.put(JdbcSourceConnectorConfig.TOPIC_PREFIX_CONFIG, "test-prefix"); 87 | final JdbcSourceTaskConfig config = new JdbcSourceTaskConfig(properties); 88 | config.validate(); 89 | assertEquals( 90 | config.getList(JdbcSourceTaskConfig.TABLES_CONFIG), 91 | List.of("test-table-1", "test-table-2") 92 | ); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/io/aiven/connect/jdbc/source/TimestampIncrementingOffset.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Aiven Oy and jdbc-connector-for-apache-kafka project contributors 3 | * Copyright 2016 Confluent Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package io.aiven.connect.jdbc.source; 19 | 20 | import java.sql.Timestamp; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | public class TimestampIncrementingOffset { 28 | private static final Logger log = LoggerFactory.getLogger(JdbcSourceTask.class); 29 | 30 | private static final String INCREMENTING_FIELD = "incrementing"; 31 | private static final String TIMESTAMP_FIELD = "timestamp"; 32 | private static final String TIMESTAMP_NANOS_FIELD = "timestamp_nanos"; 33 | 34 | private final Long incrementingOffset; 35 | private final Timestamp timestampOffset; 36 | 37 | /** 38 | * @param timestampOffset the timestamp offset. 39 | * @param incrementingOffset the incrementing offset. 40 | */ 41 | public TimestampIncrementingOffset(final Timestamp timestampOffset, final Long incrementingOffset) { 42 | this.timestampOffset = timestampOffset; 43 | this.incrementingOffset = incrementingOffset; 44 | } 45 | 46 | public Long getIncrementingOffset() { 47 | return incrementingOffset; 48 | } 49 | 50 | public Timestamp getTimestampOffset() { 51 | return timestampOffset; 52 | } 53 | 54 | public Map toMap() { 55 | final Map map = new HashMap<>(3); 56 | if (incrementingOffset != null) { 57 | map.put(INCREMENTING_FIELD, incrementingOffset); 58 | } 59 | if (timestampOffset != null) { 60 | map.put(TIMESTAMP_FIELD, timestampOffset.getTime()); 61 | map.put(TIMESTAMP_NANOS_FIELD, (long) timestampOffset.getNanos()); 62 | } 63 | return map; 64 | } 65 | 66 | public static TimestampIncrementingOffset fromMap(final Map map) { 67 | if (map == null || map.isEmpty()) { 68 | return new TimestampIncrementingOffset(null, null); 69 | } 70 | 71 | final Long incr = (Long) map.get(INCREMENTING_FIELD); 72 | final Long millis = (Long) map.get(TIMESTAMP_FIELD); 73 | Timestamp ts = null; 74 | if (millis != null) { 75 | log.trace("millis is not null"); 76 | ts = new Timestamp(millis); 77 | final Long nanos = (Long) map.get(TIMESTAMP_NANOS_FIELD); 78 | if (nanos != null) { 79 | log.trace("Nanos is not null"); 80 | ts.setNanos(nanos.intValue()); 81 | } 82 | } 83 | return new TimestampIncrementingOffset(ts, incr); 84 | } 85 | 86 | @Override 87 | public boolean equals(final Object o) { 88 | if (this == o) { 89 | return true; 90 | } 91 | if (o == null || getClass() != o.getClass()) { 92 | return false; 93 | } 94 | 95 | final TimestampIncrementingOffset that = (TimestampIncrementingOffset) o; 96 | 97 | if (incrementingOffset != null 98 | ? !incrementingOffset.equals(that.incrementingOffset) 99 | : that.incrementingOffset != null) { 100 | return false; 101 | } 102 | return timestampOffset != null 103 | ? timestampOffset.equals(that.timestampOffset) 104 | : that.timestampOffset == null; 105 | 106 | } 107 | 108 | @Override 109 | public int hashCode() { 110 | int result = incrementingOffset != null ? incrementingOffset.hashCode() : 0; 111 | result = 31 * result + (timestampOffset != null ? timestampOffset.hashCode() : 0); 112 | return result; 113 | } 114 | } 115 | --------------------------------------------------------------------------------