├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── config.yml │ └── feature.yml ├── dependabot.yml ├── pull_request_template.md ├── setup-unit.sh └── workflows │ ├── main.yml │ └── publish-docker-images.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── docker-compose-ci.yml ├── dockerfiles └── snowflake-cli.Dockerfile ├── environment_db2 ├── environment_druid ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local-setup-unit.sh ├── lombok.config ├── plugin-jdbc-arrow-flight ├── build.gradle └── src │ └── main │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── arrowflight │ │ ├── ArrowFlightCellConverter.java │ │ ├── ArrowFlightConnectionInterface.java │ │ ├── Queries.java │ │ ├── Query.java │ │ ├── Trigger.java │ │ └── package-info.java │ └── resources │ └── icons │ ├── io.kestra.plugin.jdbc.arrowflight.svg │ └── plugin-icon.svg ├── plugin-jdbc-as400 ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── as400 │ │ │ ├── As400CellConverter.java │ │ │ ├── As400ConnectionInterface.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.as400.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── as400 │ │ └── As400DriverTest.java │ └── resources │ ├── allure.properties │ └── logback.xml ├── plugin-jdbc-clickhouse ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── clickhouse │ │ │ ├── BulkInsert.java │ │ │ ├── ClickHouseCellConverter.java │ │ │ ├── ClickHouseLocalCLI.java │ │ │ ├── ClickhouseConnectionInterface.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.clickhouse.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── clickhouse │ │ ├── AbstractClickHouseTest.java │ │ ├── ClickHouseDriverTest.java │ │ ├── ClickHouseLocalCLITest.java │ │ ├── ClickHouseQueriesTest.java │ │ ├── ClickHouseTest.java │ │ └── ClickHouseTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── clickhouse-listen.yml │ ├── logback.xml │ └── scripts │ ├── clickhouse.sql │ └── clickhouse_queries.sql ├── plugin-jdbc-db2 ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── db2 │ │ │ ├── Db2CellConverter.java │ │ │ ├── Db2ConnectionInterface.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.db2.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── db2 │ │ ├── DB2QueriesTest.java │ │ ├── Db2DriverTest.java │ │ ├── Db2Test.java │ │ └── Db2TriggerTest.java │ └── resources │ ├── flows │ ├── db2-listen.yml │ └── read_db2.yml │ └── scripts │ ├── db2.sql │ └── db2_queries.sql ├── plugin-jdbc-dremio ├── build.gradle └── src │ └── main │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── dremio │ │ ├── DremioCellConverter.java │ │ ├── DremioConnectionInterface.java │ │ ├── Queries.java │ │ ├── Query.java │ │ ├── Trigger.java │ │ └── package-info.java │ └── resources │ └── icons │ ├── io.kestra.plugin.jdbc.dremio.svg │ └── plugin-icon.svg ├── plugin-jdbc-druid ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── druid │ │ │ ├── DruidCellConverter.java │ │ │ ├── DruidConnectionInterface.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.druid.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── druid │ │ ├── DruidDriverTest.java │ │ ├── DruidQueriesTest.java │ │ ├── DruidTest.java │ │ ├── DruidTestHelper.java │ │ └── DruidTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── druid-listen.yml │ └── logback.xml ├── plugin-jdbc-duckdb ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── duckdb │ │ │ ├── DuckDbCellConverter.java │ │ │ ├── DuckDbQueryInterface.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.duckdb.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── duckdb │ │ ├── DuckDBTriggerTest.java │ │ ├── DuckDbDriverTest.java │ │ ├── DuckDbQueriesTest.java │ │ ├── DuckDbTest.java │ │ ├── DuckDbTestUtils.java │ │ └── RunnerTest.java │ └── resources │ ├── allure.properties │ ├── db │ ├── duck.db │ └── file.db │ ├── flows │ └── duckdb-listen.yml │ ├── full.csv │ ├── logback.xml │ └── sanity-checks │ └── all_duckdb.yaml ├── plugin-jdbc-mariadb ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── mariadb │ │ │ ├── MariaDbCellConverter.java │ │ │ ├── MariaDbConnectionInterface.java │ │ │ ├── MariaDbUtils.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.mariadb.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── mariadb │ │ ├── LoadTest.java │ │ ├── MariaDbDriverTest.java │ │ ├── MariaDbTest.java │ │ ├── MariaDbTriggerTest.java │ │ └── QueriesMariaDbTest.java │ └── resources │ ├── allure.properties │ ├── flows │ ├── mysql-listen.yml │ └── read_mysql.yaml │ ├── load.csv │ ├── logback.xml │ └── scripts │ ├── mariadb.sql │ ├── mariadb_insert.sql │ └── mariadb_queries.sql ├── plugin-jdbc-mysql ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── mysql │ │ │ ├── Batch.java │ │ │ ├── MySqlConnectionInterface.java │ │ │ ├── MysqlCellConverter.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.mysql.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── mysql │ │ ├── BatchTest.java │ │ ├── LoadTest.java │ │ ├── MySqlTriggerTest.java │ │ ├── MysqlDriverTest.java │ │ ├── MysqlTest.java │ │ └── QueriesMysqlTest.java │ └── resources │ ├── allure.properties │ ├── flows │ ├── mysql-listen.yml │ └── read_mysql.yaml │ ├── load.csv │ ├── logback.xml │ └── scripts │ ├── mysql.sql │ ├── mysql_insert.sql │ └── mysql_queries.sql ├── plugin-jdbc-oracle ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── oracle │ │ │ ├── Batch.java │ │ │ ├── OracleCellConverter.java │ │ │ ├── OracleConnectionInterface.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.oracle.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── oracle │ │ ├── BatchTest.java │ │ ├── OracleDriverTest.java │ │ ├── OracleQueriesTest.java │ │ ├── OracleTest.java │ │ └── OracleTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── oracle-listen.yml │ ├── logback.xml │ └── scripts │ ├── oracle.sql │ ├── oracle_insert.sql │ └── oracle_queries.sql ├── plugin-jdbc-pinot ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── pinot │ │ │ ├── PinotCellConverter.java │ │ │ ├── PinotConnectionInterface.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.pinot.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── pinot │ │ ├── PinotDriverTest.java │ │ ├── PinotQueriesTest.java │ │ ├── PinotTest.java │ │ └── PinotTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── pinot-listen.yml │ └── logback.xml ├── plugin-jdbc-postgres ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── postgresql │ │ │ ├── AbstractCopy.java │ │ │ ├── Batch.java │ │ │ ├── CopyIn.java │ │ │ ├── CopyOut.java │ │ │ ├── PostgresCellConverter.java │ │ │ ├── PostgresConnectionInterface.java │ │ │ ├── PostgresService.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.postgresql.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── postgresql │ │ ├── BatchTest.java │ │ ├── CopyTest.java │ │ ├── PgsqlDriverTest.java │ │ ├── PgsqlTest.java │ │ ├── PgsqlTriggerTest.java │ │ ├── QueriesPostgresTest.java │ │ └── TestUtils.java │ └── resources │ ├── allure.properties │ ├── flows │ ├── pgsql-listen.yml │ └── update_postgres.yaml │ ├── logback.xml │ ├── sanity-checks │ └── all_postgres.yaml │ └── scripts │ ├── postgres.sql │ ├── postgres_insert.sql │ └── postgres_queries.sql ├── plugin-jdbc-redshift ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── redshift │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── RedshiftCellConverter.java │ │ │ ├── RedshiftConnectionInterface.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.redshift.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── redshift │ │ ├── RedshiftQueriesTest.java │ │ ├── RedshiftTest.java │ │ └── RedshiftTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── redshift-listen.yml │ ├── logback.xml │ └── scripts │ ├── redshift.sql │ └── redshift_queries.sql ├── plugin-jdbc-snowflake ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── snowflake │ │ │ ├── AbstractSnowflakeConnection.java │ │ │ ├── Download.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── RSAKeyPairUtils.java │ │ │ ├── SnowflakeCLI.java │ │ │ ├── SnowflakeCellConverter.java │ │ │ ├── SnowflakeInterface.java │ │ │ ├── Trigger.java │ │ │ ├── Upload.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.snowflake.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── snowflake │ │ ├── RSAKeyPairUtilsTest.java │ │ ├── SnowflakeCLITest.java │ │ ├── SnowflakeDriverTest.java │ │ ├── SnowflakeQueriesTest.java │ │ ├── SnowflakeTest.java │ │ ├── SnowflakeTriggerTest.java │ │ └── UploadDownloadTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── snowflake-listen.yml │ ├── logback.xml │ └── scripts │ ├── snowflake.sql │ └── snowflake_queries.sql ├── plugin-jdbc-sqlite ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── sqlite │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── SqliteCellConverter.java │ │ │ ├── SqliteQueryInterface.java │ │ │ ├── SqliteQueryUtils.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.sqlite.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── sqlite │ │ ├── SqliteDriverTest.java │ │ ├── SqliteQueriesTest.java │ │ ├── SqliteTest.java │ │ ├── SqliteTriggerTest.java │ │ └── TestUtils.java │ └── resources │ ├── allure.properties │ ├── db │ └── Chinook_Sqlite.sqlite │ ├── flows │ └── sqlite-listen.yml │ ├── logback.xml │ └── scripts │ ├── sqlite.sql │ └── sqlite_queries.sql ├── plugin-jdbc-sqlserver ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── sqlserver │ │ │ ├── Batch.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── SqlServerCellConverter.java │ │ │ ├── SqlServerConnectionInterface.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.sqlserver.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── sqlserver │ │ ├── BatchTest.java │ │ ├── SqlServerDriverTest.java │ │ ├── SqlServerQueriesTest.java │ │ ├── SqlServerTest.java │ │ └── SqlServerTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── sqlserver-listen.yml │ ├── logback.xml │ └── scripts │ ├── sqlserver.sql │ ├── sqlserver_insert.sql │ └── sqlserver_queries.sql ├── plugin-jdbc-sybase ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── sybase │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── SybaseCellConverter.java │ │ │ ├── SybaseConnectionInterface.java │ │ │ ├── Trigger.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.sybase.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── sybase │ │ ├── SybaseDriverTest.java │ │ ├── SybaseQueriesTest.java │ │ ├── SybaseTest.java │ │ └── SybaseTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ ├── read_sybase.yaml │ └── sybase-listen.yml │ ├── logback.xml │ └── scripts │ ├── sybase.sql │ └── sybase_queries.sql ├── plugin-jdbc-trino ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── trino │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ ├── TrinoCellConverter.java │ │ │ ├── TrinoConnectionInterface.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.trino.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── trino │ │ ├── TrinoDriverTest.java │ │ ├── TrinoTest.java │ │ └── TrinoTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── trino-listen.yml │ ├── logback.xml │ └── scripts │ └── trino.sql ├── plugin-jdbc-vectorwise ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── vectorwise │ │ │ ├── Batch.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ ├── VectorwiseCellConverter.java │ │ │ ├── VetorwiseConnectionInterface.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.vectorwise.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── vectorwise │ │ ├── BatchTest.java │ │ ├── VectorwiseTest.java │ │ └── VectorwiseTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── vectorwise-listen.yml │ ├── logback.xml │ └── scripts │ └── vectorwise.sql ├── plugin-jdbc-vertica ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── kestra │ │ │ └── plugin │ │ │ └── jdbc │ │ │ └── vertica │ │ │ ├── Batch.java │ │ │ ├── Queries.java │ │ │ ├── Query.java │ │ │ ├── Trigger.java │ │ │ ├── VerticaCellConverter.java │ │ │ ├── VerticaConnectionInterface.java │ │ │ └── package-info.java │ └── resources │ │ └── icons │ │ ├── io.kestra.plugin.jdbc.vertica.svg │ │ └── plugin-icon.svg │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ └── vertica │ │ ├── BatchTest.java │ │ ├── VerticaDriverTest.java │ │ ├── VerticaQueriesTest.java │ │ ├── VerticaTest.java │ │ └── VerticaTriggerTest.java │ └── resources │ ├── allure.properties │ ├── flows │ └── vectica-listen.yml │ ├── logback.xml │ └── scripts │ ├── vertica.sql │ ├── vertica_insert.sql │ └── vertica_queries.sql ├── plugin-jdbc ├── build.gradle └── src │ ├── main │ └── java │ │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ ├── AbstractCellConverter.java │ │ ├── AbstractJdbcBaseQuery.java │ │ ├── AbstractJdbcBatch.java │ │ ├── AbstractJdbcQueries.java │ │ ├── AbstractJdbcQuery.java │ │ ├── AbstractJdbcTrigger.java │ │ ├── JdbcConnectionInterface.java │ │ ├── JdbcQueriesInterface.java │ │ ├── JdbcQueryInterface.java │ │ └── JdbcStatementInterface.java │ └── test │ ├── java │ └── io │ │ └── kestra │ │ └── plugin │ │ └── jdbc │ │ ├── AbstractJdbcDriverTest.java │ │ ├── AbstractJdbcTriggerTest.java │ │ ├── AbstractRdbmsTest.java │ │ └── JdbcTriggerTest.java │ └── resources │ ├── allure.properties │ ├── application.yml │ └── logback.xml └── settings.gradle /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset=utf-8 5 | end_of_line=lf 6 | insert_final_newline=false 7 | trim_trailing_whitespace=true 8 | indent_style=space 9 | indent_size=4 10 | continuation_indent_size=4 11 | 12 | [*.yml] 13 | indent_size=2 14 | 15 | [*.md] 16 | indent_size=2 17 | 18 | [*.yaml] 19 | indent_size=2 20 | 21 | [*.json] 22 | indent_size=2 23 | 24 | [*.css] 25 | indent_size=2 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: File a bug report 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | Thanks for reporting an issue! Please provide a [Minimal Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) and share any additional information that may help reproduce, troubleshoot, and hopefully fix the issue, including screenshots, error traceback, and your Kestra server logs. For quick questions, you can contact us directly on [Slack](https://kestra.io/slack). 8 | - type: textarea 9 | attributes: 10 | label: Describe the issue 11 | description: A concise description of the issue and how we can reproduce it. 12 | placeholder: Describe the issue step by step 13 | validations: 14 | required: true 15 | - type: textarea 16 | attributes: 17 | label: Environment 18 | description: Environment information where the problem occurs. 19 | value: | 20 | - Kestra Version: develop 21 | validations: 22 | required: false 23 | labels: 24 | - bug 25 | - area/plugin -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: Chat 3 | url: https://kestra.io/slack 4 | about: Chat with us on Slack. 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Create a new feature request 3 | body: 4 | - type: textarea 5 | attributes: 6 | label: Feature description 7 | placeholder: Tell us more about your feature request 8 | validations: 9 | required: true 10 | labels: 11 | - enhancement 12 | - area/plugin -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # See GitHub's docs for more information on this file: 2 | # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates 3 | version: 2 4 | updates: 5 | # Maintain dependencies for GitHub Actions 6 | - package-ecosystem: "github-actions" 7 | directory: "/" 8 | schedule: 9 | # Check for updates to GitHub Actions every weekday 10 | interval: "weekly" 11 | labels: 12 | - "dependency-upgrade" 13 | open-pull-requests-limit: 50 14 | 15 | # Maintain dependencies for Gradle modules 16 | - package-ecosystem: "gradle" 17 | directory: "/" 18 | schedule: 19 | # Check for updates to Gradle modules every week 20 | interval: "weekly" 21 | labels: 22 | - "dependency-upgrade" 23 | open-pull-requests-limit: 50 24 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ### What changes are being made and why? 10 | 11 | 12 | --- 13 | 14 | ### How the changes have been QAed? 15 | 16 | 25 | 26 | --- 27 | 28 | ### Setup Instructions 29 | 30 | 38 | -------------------------------------------------------------------------------- /.github/setup-unit.sh: -------------------------------------------------------------------------------- 1 | mkdir certs 2 | openssl req -new -x509 -days 365 -nodes -out certs/ca.crt -keyout certs/ca.key -subj "/CN=root-ca" 3 | 4 | mkdir certs/server 5 | openssl genrsa -des3 -out certs/server/server.key -passout pass:p4ssphrase 2048 6 | openssl rsa -in certs/server/server.key -passin pass:p4ssphrase -out certs/server/server.key 7 | openssl req -new -nodes -key certs/server/server.key -out certs/server/server.csr -subj "/CN=postgresql" 8 | openssl x509 -req -in certs/server/server.csr -days 365 -CA certs/ca.crt -CAkey certs/ca.key -CAcreateserial -out certs/server/server.crt 9 | sudo chmod -R 600 certs/server/ 10 | sudo chown -R 1001 certs/server/ 11 | 12 | mkdir certs/client 13 | openssl genrsa -des3 -out certs/client/client.key -passout pass:p4ssphrase 2048 14 | openssl rsa -in certs/client/client.key -passin pass:p4ssphrase -out certs/client/client-no-pass.key 15 | openssl req -new -nodes -key certs/client/client.key -passin pass:p4ssphrase -out certs/client/client.csr -subj "/CN=postgres" 16 | openssl x509 -req -in certs/client/client.csr -days 365 -CA certs/ca.crt -CAkey certs/ca.key -CAcreateserial -out certs/client/client.crt 17 | 18 | mkdir plugin-jdbc-postgres/src/test/resources/ssl/ 19 | cp certs/client/* plugin-jdbc-postgres/src/test/resources/ssl/ 20 | cp certs/ca.crt plugin-jdbc-postgres/src/test/resources/ssl/ 21 | 22 | docker compose -f docker-compose-ci.yml up --quiet-pull -d mariadb sqlserver 23 | docker compose -f docker-compose-ci.yml up --quiet-pull -d --wait 24 | sleep 3 25 | 26 | docker exec -i plugin-jdbc-mariadb-1 mariadb -uroot -pmariadb_passwd --database=kestra -e """ 27 | INSTALL SONAME 'auth_ed25519'; 28 | CREATE USER 'ed25519'@'%' IDENTIFIED VIA ed25519 USING PASSWORD('secret'); 29 | GRANT SELECT ON kestra.* TO 'ed25519'@'%' IDENTIFIED VIA ed25519 USING PASSWORD('secret'); 30 | """ 31 | 32 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: 4 | schedule: 5 | - cron: '0 4 * * 1,2,3,4,5' 6 | push: 7 | branches: 8 | - master 9 | - main 10 | - releases/* 11 | tags: 12 | - v* 13 | 14 | pull_request: 15 | branches: 16 | - master 17 | - main 18 | - releases/* 19 | 20 | workflow_dispatch: 21 | inputs: 22 | skip-test: 23 | description: 'Skip test' 24 | type: choice 25 | required: true 26 | default: 'false' 27 | options: 28 | - "true" 29 | - "false" 30 | 31 | jobs: 32 | check: 33 | uses: kestra-io/actions/.github/workflows/plugins.yml@main 34 | with: 35 | skip-test: ${{ github.event.inputs.skip-test == 'true' }} 36 | secrets: inherit 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | .DS_Store 3 | .gradle 4 | build/ 5 | target/ 6 | out/ 7 | .idea 8 | .vscode 9 | *.iml 10 | *.ipr 11 | *.iws 12 | .project 13 | .settings 14 | .classpath 15 | .attach* 16 | plugin-jdbc-redshift/src/test/resources/application-test.yml 17 | plugin-jdbc-snowflake/src/test/resources/application-test.yml 18 | certs/ 19 | plugin-jdbc-postgres/src/test/resources/ssl/ 20 | openssl.cnf 21 | 22 | plugin-jdbc-sqlite/temp 23 | plugin-jdbc-duckdb/*.db 24 | -------------------------------------------------------------------------------- /dockerfiles/snowflake-cli.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.11-slim 2 | LABEL org.opencontainers.image.source=https://github.com/kestra-io/plugin-jdbc 3 | LABEL org.opencontainers.image.description="Image with the latest snowflake-cli package" 4 | RUN pip install --upgrade pip 5 | RUN pip install --no-cache snowflake-cli 6 | -------------------------------------------------------------------------------- /environment_db2: -------------------------------------------------------------------------------- 1 | LICENSE=accept 2 | DB2INSTANCE=db2inst1 3 | DB2INST1_PASSWORD=password 4 | DBNAME=testdb 5 | BLU=false 6 | ENABLE_ORACLE_COMPATIBILITY=false 7 | UPDATEAVAIL=NO 8 | TO_CREATE_SAMPLEDB=false 9 | REPODB=false 10 | IS_OSXFS=false 11 | PERSISTENT_HOME=true 12 | HADR_ENABLED=false 13 | ETCD_ENDPOINT= 14 | ETCD_USERNAME= 15 | ETCD_PASSWORD= -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | version=0.24.0-SNAPSHOT 2 | kestraVersion=[0.23,) 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kestra-io/plugin-jdbc/8d9476dee87f40d42dd46acb99ad4ee2e6f53ce3/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /lombok.config: -------------------------------------------------------------------------------- 1 | config.stopBubbling = true 2 | lombok.addLombokGeneratedAnnotation = true 3 | lombok.anyConstructor.addConstructorProperties = true 4 | lombok.equalsAndHashCode.callSuper = call 5 | lombok.tostring.callsuper = call 6 | -------------------------------------------------------------------------------- /plugin-jdbc-arrow-flight/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Query a compatible database using the Kestra Apache Arrow Flight SQL JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Arrow Flight SQL", 8 | "X-Kestra-Group": project.group + ".jdbc.arrowflight", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation("org.apache.arrow:flight-sql-jdbc-driver:18.3.0") 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-arrow-flight/src/main/java/io/kestra/plugin/jdbc/arrowflight/ArrowFlightCellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.arrowflight; 2 | 3 | import io.kestra.plugin.jdbc.AbstractCellConverter; 4 | 5 | import java.sql.Connection; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.time.ZoneId; 9 | 10 | public class ArrowFlightCellConverter extends AbstractCellConverter { 11 | 12 | public ArrowFlightCellConverter(ZoneId zoneId) { 13 | super(zoneId); 14 | } 15 | 16 | @Override 17 | public Object convertCell(int columnIndex, ResultSet resultSet, Connection connection) throws SQLException { 18 | return super.convert(columnIndex, resultSet); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-arrow-flight/src/main/java/io/kestra/plugin/jdbc/arrowflight/ArrowFlightConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.arrowflight; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface ArrowFlightConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:arrow-flight-sql"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-arrow-flight/src/main/java/io/kestra/plugin/jdbc/arrowflight/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing a database through Apache Arrow Flight SQL.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.arrowflight; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-arrow-flight/src/main/resources/icons/plugin-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /plugin-jdbc-as400/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Query AS400 databases using the Kestra JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "AS400", 8 | "X-Kestra-Group": project.group + ".jdbc.as400", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation 'net.sf.jt400:jt400:21.0.4' 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-as400/src/main/java/io/kestra/plugin/jdbc/as400/As400CellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.as400; 2 | 3 | import io.kestra.plugin.jdbc.AbstractCellConverter; 4 | 5 | import java.sql.Connection; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.time.ZoneId; 9 | 10 | /** 11 | * Copied from the DB2 code as we cannot test AS400 we assume it works like DB2 12 | */ 13 | public class As400CellConverter extends AbstractCellConverter { 14 | public As400CellConverter(ZoneId zoneId) { 15 | super(zoneId); 16 | } 17 | 18 | @Override 19 | public Object convertCell(int columnIndex, ResultSet rs, Connection connection) throws SQLException { 20 | Object data = rs.getObject(columnIndex); 21 | 22 | if (data == null) { 23 | return null; 24 | } 25 | 26 | String columnTypeName = rs.getMetaData().getColumnTypeName(columnIndex); 27 | 28 | return switch (columnTypeName.toLowerCase()) { 29 | case "char", "varchar" -> ((com.ibm.as400.access.AS400JDBCResultSet) rs).getString(columnIndex); 30 | case "date" -> ((com.ibm.as400.access.AS400JDBCResultSet) rs).getDate(columnIndex).toLocalDate(); 31 | case "time" -> ((com.ibm.as400.access.AS400JDBCResultSet) rs).getTime(columnIndex).toLocalTime(); 32 | case "timestamp" -> ((com.ibm.as400.access.AS400JDBCResultSet) rs).getTimestamp(columnIndex).toInstant(); 33 | case "blob" -> ((com.ibm.as400.access.AS400JDBCResultSet) rs).getBlob(columnIndex); 34 | case "clob" -> ((com.ibm.as400.access.AS400JDBCResultSet) rs).getClob(columnIndex); 35 | case "nclob" -> ((com.ibm.as400.access.AS400JDBCResultSet) rs).getNClob(columnIndex); 36 | case "xml" -> ((com.ibm.as400.access.AS400JDBCResultSet) rs).getSQLXML(columnIndex); 37 | default -> super.convert(columnIndex, rs); 38 | }; 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /plugin-jdbc-as400/src/main/java/io/kestra/plugin/jdbc/as400/As400ConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.as400; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface As400ConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:as400"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-as400/src/main/java/io/kestra/plugin/jdbc/as400/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the AS400 database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.as400; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-as400/src/test/java/io/kestra/plugin/jdbc/as400/As400DriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.as400; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class As400DriverTest extends AbstractJdbcDriverTest { 10 | 11 | @Override 12 | protected Class getDriverClass() { 13 | return com.ibm.as400.access.AS400JDBCDriver.class; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /plugin-jdbc-as400/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-as400/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Query ClickHouse databases using Kestra\'s JDBC plugin integration.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "ClickHouse", 8 | "X-Kestra-Group": project.group + ".jdbc.clickhouse", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation 'com.clickhouse:clickhouse-jdbc:0.8.6' 17 | implementation 'org.lz4:lz4-java:1.8.0' 18 | 19 | implementation project(':plugin-jdbc') 20 | 21 | compileOnly group: "io.kestra", name: "script", version: kestraVersion 22 | 23 | testImplementation group: "io.kestra", name: "script", version: kestraVersion 24 | 25 | testImplementation project(':plugin-jdbc').sourceSets.test.output 26 | } 27 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/main/java/io/kestra/plugin/jdbc/clickhouse/ClickhouseConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.clickhouse; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface ClickhouseConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:clickhouse"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/main/java/io/kestra/plugin/jdbc/clickhouse/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the ClickHouse database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.clickhouse; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/main/resources/icons/io.kestra.plugin.jdbc.clickhouse.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/main/resources/icons/plugin-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/test/java/io/kestra/plugin/jdbc/clickhouse/AbstractClickHouseTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.clickhouse; 2 | 3 | import io.kestra.plugin.jdbc.AbstractRdbmsTest; 4 | 5 | public abstract class AbstractClickHouseTest extends AbstractRdbmsTest { 6 | 7 | @Override 8 | protected String getUsername() { 9 | return "myuser"; 10 | } 11 | 12 | @Override 13 | protected String getPassword() { 14 | return "mypassword"; 15 | } 16 | 17 | @Override 18 | protected String getUrl() { 19 | return "jdbc:clickhouse://127.0.0.1:28123/default"; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/test/java/io/kestra/plugin/jdbc/clickhouse/ClickHouseDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.clickhouse; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class ClickHouseDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return com.clickhouse.jdbc.ClickHouseDriver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/test/java/io/kestra/plugin/jdbc/clickhouse/ClickHouseLocalCLITest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.clickhouse; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.core.models.property.Property; 5 | import io.kestra.core.runners.RunContext; 6 | import io.kestra.core.runners.RunContextFactory; 7 | import io.kestra.core.utils.IdUtils; 8 | import io.kestra.core.utils.TestsUtils; 9 | import io.kestra.plugin.scripts.exec.scripts.models.ScriptOutput; 10 | import jakarta.inject.Inject; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import static org.hamcrest.MatcherAssert.assertThat; 17 | import static org.hamcrest.Matchers.is; 18 | 19 | @KestraTest 20 | public class ClickHouseLocalCLITest { 21 | 22 | @Inject 23 | private RunContextFactory runContextFactory; 24 | 25 | @Test 26 | void run() throws Exception { 27 | ClickHouseLocalCLI clickhouseLocalCLI = ClickHouseLocalCLI.builder() 28 | .id(IdUtils.create()) 29 | .type(ClickHouseLocalCLI.class.getName()) 30 | .commands(Property.of(List.of("SELECT * FROM system.tables"))) 31 | .build(); 32 | 33 | RunContext runContext = TestsUtils.mockRunContext(runContextFactory, clickhouseLocalCLI, Map.of()); 34 | 35 | ScriptOutput output = clickhouseLocalCLI.run(runContext); 36 | 37 | assertThat(output.getExitCode(), is(0)); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/test/java/io/kestra/plugin/jdbc/clickhouse/ClickHouseTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.clickhouse; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.io.FileNotFoundException; 8 | import java.net.URISyntaxException; 9 | import java.sql.SQLException; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.hamcrest.Matchers.is; 15 | 16 | @KestraTest 17 | class ClickHouseTriggerTest extends AbstractJdbcTriggerTest { 18 | 19 | @Test 20 | void run() throws Exception { 21 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","clickhouse-listen"); 22 | 23 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 24 | assertThat(rows.size(), is(1)); 25 | } 26 | 27 | @Override 28 | protected String getUsername() { 29 | return "myuser"; 30 | } 31 | 32 | @Override 33 | protected String getPassword() { 34 | return "mypassword"; 35 | } 36 | 37 | @Override 38 | protected String getUrl() { 39 | return "jdbc:clickhouse://127.0.0.1:28123/default"; 40 | } 41 | 42 | @Override 43 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 44 | executeSqlScript("scripts/clickhouse.sql"); 45 | } 46 | } -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/test/resources/flows/clickhouse-listen.yml: -------------------------------------------------------------------------------- 1 | id: clickhouse-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.clickhouse.Trigger 7 | sql: SELECT * FROM clickhouse_types 8 | url: jdbc:clickhouse://127.0.0.1:28123/default 9 | username: myuser 10 | password: mypassword 11 | fetchType: FETCH 12 | interval: PT10S 13 | 14 | tasks: 15 | - id: end 16 | type: io.kestra.plugin.core.debug.Return 17 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-clickhouse/src/test/resources/scripts/clickhouse_queries.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS kestra; 2 | 3 | -- Create table employee 4 | DROP TABLE IF EXISTS employee; 5 | 6 | CREATE TABLE employee ( 7 | firstName String, 8 | lastName String, 9 | age Int8, 10 | employee_id Int64 11 | ) 12 | ENGINE = MergeTree() 13 | ORDER BY (employee_id) 14 | SETTINGS index_granularity = 8192; 15 | 16 | INSERT INTO employee (firstName, lastName, age, employee_id) 17 | VALUES 18 | ('John', 'Doe', 45, 1), 19 | ('Bryan', 'Grant', 33, 2), 20 | ('Jude', 'Philips', 25, 3), 21 | ('Michael', 'Page', 62, 4); 22 | 23 | -- Create table laptop 24 | DROP TABLE IF EXISTS laptop; 25 | 26 | CREATE TABLE laptop 27 | ( 28 | brand String, 29 | model String, 30 | cpu_frequency Decimal(3, 2), 31 | laptop_id Int64 32 | ) ENGINE = MergeTree() 33 | ORDER BY (laptop_id) 34 | SETTINGS index_granularity = 8192; 35 | 36 | INSERT INTO laptop (brand, model, cpu_frequency, laptop_id) 37 | VALUES 38 | ('Apple', 'MacBookPro M1 13', 2.20, 1), 39 | ('Apple', 'MacBookPro M3 16', 1.50, 2), 40 | ('LG', 'Gram', 1.95, 3), 41 | ('Lenovo', 'ThinkPad', 1.05, 4); -------------------------------------------------------------------------------- /plugin-jdbc-db2/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Query DB2 databases using the Kestra JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "DB2", 8 | "X-Kestra-Group": project.group + ".jdbc.db2", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation 'com.ibm.db2.jcc:db2jcc:db2jcc4' 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-db2/src/main/java/io/kestra/plugin/jdbc/db2/Db2CellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.db2; 2 | 3 | import io.kestra.plugin.jdbc.AbstractCellConverter; 4 | 5 | import java.sql.Connection; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.time.ZoneId; 9 | 10 | public class Db2CellConverter extends AbstractCellConverter { 11 | public Db2CellConverter(ZoneId zoneId) { 12 | super(zoneId); 13 | } 14 | 15 | @Override 16 | public Object convertCell(int columnIndex, ResultSet rs, Connection connection) throws SQLException { 17 | Object data = rs.getObject(columnIndex); 18 | 19 | if (data == null) { 20 | return null; 21 | } 22 | 23 | String columnTypeName = rs.getMetaData().getColumnTypeName(columnIndex); 24 | 25 | return switch (columnTypeName.toLowerCase()) { 26 | case "char", "varchar" -> ((com.ibm.db2.jcc.am.ResultSet) rs).getString(columnIndex); 27 | case "date" -> ((com.ibm.db2.jcc.am.ResultSet) rs).getDate(columnIndex).toLocalDate(); 28 | case "time" -> ((com.ibm.db2.jcc.am.ResultSet) rs).getTime(columnIndex).toLocalTime(); 29 | case "timestamp" -> ((com.ibm.db2.jcc.am.ResultSet) rs).getTimestamp(columnIndex).toInstant(); 30 | case "blob" -> ((com.ibm.db2.jcc.am.ResultSet) rs).getBlob(columnIndex); 31 | case "clob" -> ((com.ibm.db2.jcc.am.ResultSet) rs).getClob(columnIndex); 32 | case "nclob" -> ((com.ibm.db2.jcc.am.ResultSet) rs).getNClob(columnIndex); 33 | case "xml" -> ((com.ibm.db2.jcc.am.ResultSet) rs).getSQLXML(columnIndex); 34 | default -> super.convert(columnIndex, rs); 35 | }; 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /plugin-jdbc-db2/src/main/java/io/kestra/plugin/jdbc/db2/Db2ConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.db2; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface Db2ConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:db2"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-db2/src/main/java/io/kestra/plugin/jdbc/db2/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the DB2 database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.db2; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-db2/src/test/java/io/kestra/plugin/jdbc/db2/Db2DriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.db2; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class Db2DriverTest extends AbstractJdbcDriverTest { 10 | 11 | @Override 12 | protected Class getDriverClass() { 13 | return com.ibm.db2.jcc.DB2Driver.class; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /plugin-jdbc-db2/src/test/java/io/kestra/plugin/jdbc/db2/Db2TriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.db2; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.condition.DisabledIf; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.net.URISyntaxException; 10 | import java.sql.SQLException; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.is; 16 | 17 | @KestraTest 18 | @DisabledIf( 19 | value = "isDisabled", 20 | disabledReason = "The tests are disabled for CI, as db2 container have long time initialization" 21 | ) 22 | class Db2TriggerTest extends AbstractJdbcTriggerTest { 23 | 24 | static boolean isDisabled() { 25 | return true; 26 | } 27 | 28 | @Test 29 | void run() throws Exception { 30 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","db2-listen"); 31 | 32 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 33 | assertThat(rows.size(), is(1)); 34 | } 35 | 36 | @Override 37 | protected String getUrl() { 38 | return "jdbc:db2://localhost:5023/testdb"; 39 | } 40 | 41 | @Override 42 | protected String getUsername() { 43 | return "db2inst1"; 44 | } 45 | 46 | @Override 47 | protected String getPassword() { 48 | return "password"; 49 | } 50 | 51 | @Override 52 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 53 | executeSqlScript("scripts/db2.sql"); 54 | } 55 | } -------------------------------------------------------------------------------- /plugin-jdbc-db2/src/test/resources/flows/db2-listen.yml: -------------------------------------------------------------------------------- 1 | id: db2-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.db2.Trigger 7 | url: jdbc:db2://localhost:5023/testdb 8 | username: db2inst1 9 | password: password 10 | sql: select * from db2_types 11 | fetchType: FETCH 12 | interval: PT10S 13 | 14 | tasks: 15 | - id: end 16 | type: io.kestra.plugin.core.debug.Return 17 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-db2/src/test/resources/flows/read_db2.yml: -------------------------------------------------------------------------------- 1 | id: read_db2 2 | namespace: io.kestra.jdbc.db2 3 | 4 | tasks: 5 | - id: read 6 | type: io.kestra.plugin.jdbc.db2.Query 7 | url: jdbc:db2://localhost:5023/testdb 8 | username: db2inst1 9 | password: password 10 | sql: select * from db2_types 11 | fetchType: FETCH_ONE 12 | - id: flow-id 13 | type: io.kestra.plugin.core.debug.Return 14 | format: "{{outputs.update.row}}" 15 | -------------------------------------------------------------------------------- /plugin-jdbc-db2/src/test/resources/scripts/db2.sql: -------------------------------------------------------------------------------- 1 | -- Drop the db2_types table if it exists 2 | DROP TABLE IF EXISTS DB2INST1.db2_types; 3 | 4 | -- Create the db2_types table 5 | CREATE TABLE DB2INST1.db2_types ( 6 | ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 7 | INTEGER_col INT, 8 | BIGINT_col BIGINT, 9 | DECIMAL_col DECIMAL(10,2), 10 | REAL_col REAL, 11 | DOUBLE_col DOUBLE, 12 | CHARACTER_col CHAR, 13 | VARCHAR_col VARCHAR(255), 14 | GRAPHIC_col GRAPHIC, 15 | VARGRAPHIC_col VARGRAPHIC(255), 16 | DATE_col DATE, 17 | TIME_col TIME, 18 | TIMESTAMP_col TIMESTAMP, 19 | BLOB_col BLOB(1024), 20 | CLOB_col CLOB(1024), 21 | XML_col XML 22 | ); 23 | 24 | -- Insert values into the db2_types table 25 | INSERT INTO DB2INST1.db2_types 26 | (INTEGER_col, BIGINT_col, DECIMAL_col, REAL_col, DOUBLE_col, CHARACTER_col, VARCHAR_col, GRAPHIC_col, VARGRAPHIC_col, DATE_col, TIME_col, TIMESTAMP_col) 27 | VALUES 28 | (123, 1234567890123456789, 123.45, 123.45, 123.45, 'c', 'var character', 'g', 'var graphic', '2024-03-22', '12:51:25', '2024-03-22T12:51:25'); -------------------------------------------------------------------------------- /plugin-jdbc-db2/src/test/resources/scripts/db2_queries.sql: -------------------------------------------------------------------------------- 1 | -- Create table employee 2 | DROP TABLE IF EXISTS DB2INST1.employee; 3 | 4 | CREATE TABLE DB2INST1.employee ( 5 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 6 | firstName VARCHAR(200), 7 | lastName VARCHAR(200), 8 | age INT 9 | ); 10 | 11 | INSERT INTO DB2INST1.employee (firstName, lastName, age) 12 | VALUES 13 | ('John', 'Doe', 45), 14 | ('Bryan', 'Grant', 33), 15 | ('Jude', 'Philips', 25), 16 | ('Michael', 'Page', 62); 17 | 18 | 19 | -- Create table laptop 20 | DROP TABLE IF EXISTS DB2INST1.laptop; 21 | 22 | CREATE TABLE DB2INST1.laptop 23 | ( 24 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 25 | brand VARCHAR(200), 26 | model VARCHAR(200), 27 | cpu_frequency DOUBLE 28 | ); 29 | 30 | INSERT INTO DB2INST1.laptop (brand, model, cpu_frequency) 31 | VALUES 32 | ('Apple', 'MacBookPro M1 13', 2.2), 33 | ('Apple', 'MacBookPro M3 16', 1.5), 34 | ('LG', 'Gram', 1.95), 35 | ('Lenovo', 'ThinkPad', 1.05); -------------------------------------------------------------------------------- /plugin-jdbc-dremio/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Query Dremio database using the Kestra JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Dremio", 8 | "X-Kestra-Group": project.group + ".jdbc.dremio", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation("com.dremio.distribution:dremio-jdbc-driver:3.1.1-201901281837140761-30c9d74") 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-dremio/src/main/java/io/kestra/plugin/jdbc/dremio/DremioCellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.dremio; 2 | 3 | import io.kestra.plugin.jdbc.AbstractCellConverter; 4 | 5 | import java.sql.Connection; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.time.ZoneId; 9 | 10 | public class DremioCellConverter extends AbstractCellConverter { 11 | 12 | public DremioCellConverter(ZoneId zoneId) { 13 | super(zoneId); 14 | } 15 | 16 | @Override 17 | public Object convertCell(int columnIndex, ResultSet resultSet, Connection connection) throws SQLException { 18 | return super.convert(columnIndex, resultSet); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-dremio/src/main/java/io/kestra/plugin/jdbc/dremio/DremioConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.dremio; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface DremioConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:dremio"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-dremio/src/main/java/io/kestra/plugin/jdbc/dremio/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Dremio database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.dremio; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-druid/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Connect and query Apache Druid databases using Kestra\'s JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Apache Druid", 8 | "X-Kestra-Group": project.group + ".jdbc.druid", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation("org.apache.calcite.avatica:avatica-core:1.26.0"){ 17 | // exclude libraries already provided by Kestra 18 | exclude group: 'com.fasterxml.jackson.core' 19 | } 20 | implementation project(':plugin-jdbc') 21 | 22 | testImplementation project(':plugin-jdbc').sourceSets.test.output 23 | } 24 | -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/main/java/io/kestra/plugin/jdbc/druid/DruidCellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.druid; 2 | 3 | import io.kestra.plugin.jdbc.AbstractCellConverter; 4 | import lombok.SneakyThrows; 5 | 6 | import java.sql.Connection; 7 | import java.sql.ResultSet; 8 | import java.sql.SQLException; 9 | import java.time.ZoneId; 10 | 11 | public class DruidCellConverter extends AbstractCellConverter { 12 | public DruidCellConverter(ZoneId zoneId) { 13 | super(zoneId); 14 | } 15 | 16 | @SneakyThrows 17 | @Override 18 | public Object convertCell(int columnIndex, ResultSet rs, Connection connection) throws SQLException { 19 | return super.convert(columnIndex, rs); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/main/java/io/kestra/plugin/jdbc/druid/DruidConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.druid; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface DruidConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:avatica"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/main/java/io/kestra/plugin/jdbc/druid/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Druid database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.druid; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/main/resources/icons/plugin-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | Apache Druid icon -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/test/java/io/kestra/plugin/jdbc/druid/DruidDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.druid; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | @KestraTest 8 | public class DruidDriverTest extends AbstractJdbcDriverTest { 9 | @Override 10 | protected Class getDriverClass() { 11 | return org.apache.calcite.avatica.remote.Driver.class; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/test/java/io/kestra/plugin/jdbc/druid/DruidQueriesTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.druid; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.core.models.property.Property; 5 | import io.kestra.core.runners.RunContext; 6 | import io.kestra.core.runners.RunContextFactory; 7 | import io.kestra.plugin.jdbc.AbstractJdbcQueries; 8 | import jakarta.inject.Inject; 9 | import org.junit.jupiter.api.BeforeAll; 10 | import org.junit.jupiter.api.Test; 11 | 12 | import java.util.Map; 13 | 14 | import static io.kestra.core.models.tasks.common.FetchType.FETCH; 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.*; 17 | 18 | @KestraTest 19 | public class DruidQueriesTest { 20 | @Inject 21 | RunContextFactory runContextFactory; 22 | 23 | @BeforeAll 24 | public static void startServer() throws Exception { 25 | DruidTestHelper.initServer(); 26 | } 27 | 28 | @Test 29 | void insertAndQuery() throws Exception { 30 | RunContext runContext = runContextFactory.of(Map.of()); 31 | 32 | Queries task = Queries.builder() 33 | .url(Property.of("jdbc:avatica:remote:url=http://localhost:8888/druid/v2/sql/avatica/;transparent_reconnection=true")) 34 | .fetchType(Property.of(FETCH)) 35 | .timeZoneId(Property.of("Europe/Paris")) 36 | .parameters(Property.of(Map.of( 37 | "limitLow", 2, 38 | "limitHigh", 10)) 39 | ) 40 | .sql(Property.of(""" 41 | select * from products limit :limitLow; 42 | select * from products limit :limitHigh; 43 | """)) 44 | .build(); 45 | 46 | AbstractJdbcQueries.MultiQueryOutput runOutput = task.run(runContext); 47 | assertThat(runOutput.getOutputs(), notNullValue()); 48 | assertThat(runOutput.getOutputs().getFirst().getRows().size(), is(2)); 49 | assertThat(runOutput.getOutputs().getLast().getRows().size(), is(10)); 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/test/java/io/kestra/plugin/jdbc/druid/DruidTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.druid; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.net.URISyntaxException; 10 | import java.sql.SQLException; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.is; 16 | 17 | @KestraTest 18 | class DruidTriggerTest extends AbstractJdbcTriggerTest { 19 | 20 | @BeforeAll 21 | public static void startServer() throws Exception { 22 | DruidTestHelper.initServer(); 23 | } 24 | 25 | @Test 26 | void run() throws Exception { 27 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","druid-listen"); 28 | 29 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 30 | assertThat(rows.size(), is(1)); 31 | } 32 | 33 | @Override 34 | protected String getUrl() { 35 | return "jdbc:avatica:remote:url=http://localhost:8888/druid/v2/sql/avatica/;transparent_reconnection=true"; 36 | } 37 | 38 | @Override 39 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 40 | // nothing here, already done in @BeforeAll. 41 | } 42 | } -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/test/resources/flows/druid-listen.yml: -------------------------------------------------------------------------------- 1 | id: druid-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.druid.Trigger 7 | sql: | 8 | select 9 | -- NULL as t_null, 10 | 'string' AS t_string, 11 | CAST(2147483647 AS INT) as t_integer, 12 | CAST(12345.124 AS FLOAT) as t_float, 13 | CAST(12345.124 AS DOUBLE) as t_double 14 | from products 15 | limit 1 16 | url: jdbc:avatica:remote:url=http://localhost:8888/druid/v2/sql/avatica/;transparent_reconnection=true 17 | fetchType: FETCH 18 | interval: PT30S 19 | 20 | tasks: 21 | - id: end 22 | type: io.kestra.plugin.core.debug.Return 23 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-druid/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Manage data in DuckDB with Kestra\'s JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "DuckDB", 8 | "X-Kestra-Group": project.group + ".jdbc.duckdb", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation("org.duckdb:duckdb_jdbc:1.3.0.0") 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/main/java/io/kestra/plugin/jdbc/duckdb/DuckDbQueryInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.duckdb; 2 | 3 | import io.kestra.core.models.annotations.PluginProperty; 4 | import io.kestra.core.models.property.Property; 5 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 6 | import io.swagger.v3.oas.annotations.media.Schema; 7 | 8 | import java.util.List; 9 | 10 | public interface DuckDbQueryInterface extends JdbcConnectionInterface { 11 | @Schema( 12 | title = "Input files to be loaded from DuckDb.", 13 | description = "Describe a files map that will be written and usable by DuckDb. " + 14 | "You can reach files by their filename, example: `SELECT * FROM read_csv_auto('myfile.csv');` " 15 | ) 16 | @PluginProperty( 17 | additionalProperties = String.class, 18 | dynamic = true 19 | ) 20 | Object getInputFiles(); 21 | 22 | @Schema( 23 | title = "Output file list that will be uploaded to internal storage.", 24 | description = "List of keys that will generate temporary files.\n" + 25 | "On the SQL query, you can just use a variable named `outputFiles.key` for the corresponding file.\n" + 26 | "If you add a file with `[\"first\"]`, you can use the special vars `COPY tbl TO '{{ outputFiles.first }}' (HEADER, DELIMITER ',');`" + 27 | " and use this file in others tasks using `{{ outputs.taskId.outputFiles.first }}`." 28 | ) 29 | Property> getOutputFiles(); 30 | 31 | @Schema( 32 | title = "Database URI", 33 | description = "Kestra's URI to an existing Duck DB database file" 34 | ) 35 | Property getDatabaseUri(); 36 | 37 | @Schema( 38 | title = "Output the database file.", 39 | description = "This property lets you define if you want to output the in-memory database as a file for further processing." 40 | ) 41 | Property getOutputDbFile(); 42 | 43 | @Override 44 | default String getScheme() { 45 | return "jdbc:duckdb"; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/main/java/io/kestra/plugin/jdbc/duckdb/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the DuckDB database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.duckdb; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/java/io/kestra/plugin/jdbc/duckdb/DuckDBTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.duckdb; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.io.FileNotFoundException; 8 | import java.net.URISyntaxException; 9 | import java.sql.SQLException; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.hamcrest.Matchers.is; 15 | 16 | @KestraTest 17 | class DuckDBTriggerTest extends AbstractJdbcTriggerTest { 18 | @Test 19 | void run() throws Exception { 20 | // trigger the flow 21 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","duckdb-listen"); 22 | 23 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 24 | assertThat(rows.size(), is(1)); 25 | } 26 | 27 | @Override 28 | protected String getUrl() { 29 | return null; 30 | } 31 | 32 | @Override 33 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 34 | // do nothing as we init the database manually from the test method. 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/java/io/kestra/plugin/jdbc/duckdb/DuckDbDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.duckdb; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class DuckDbDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return org.duckdb.DuckDBDriver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/java/io/kestra/plugin/jdbc/duckdb/DuckDbTestUtils.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.duckdb; 2 | 3 | import io.kestra.core.storages.StorageInterface; 4 | import io.kestra.core.tenant.TenantService; 5 | import io.kestra.core.utils.IdUtils; 6 | 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.IOException; 10 | import java.net.URI; 11 | import java.net.URISyntaxException; 12 | import java.util.Objects; 13 | 14 | public class DuckDbTestUtils { 15 | public static URI getCsvSourceUri(StorageInterface storageInterface) throws URISyntaxException, IOException { 16 | return storageInterface.put( 17 | TenantService.MAIN_TENANT, 18 | null, 19 | new URI("/" + IdUtils.create()), 20 | new FileInputStream(new File(Objects.requireNonNull(DuckDbTest.class.getClassLoader() 21 | .getResource("full.csv")) 22 | .toURI()) 23 | ) 24 | ); 25 | } 26 | 27 | public static URI getDatabaseFileSourceUri(StorageInterface storageInterface) throws IOException, URISyntaxException { 28 | return storageInterface.put( 29 | TenantService.MAIN_TENANT, 30 | null, 31 | new URI("/" + IdUtils.create()), 32 | new FileInputStream(new File(Objects.requireNonNull(DuckDbTest.class.getClassLoader() 33 | .getResource("db/file.db")) 34 | .toURI()) 35 | ) 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/java/io/kestra/plugin/jdbc/duckdb/RunnerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.duckdb; 2 | 3 | import io.kestra.core.junit.annotations.ExecuteFlow; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import io.kestra.core.models.executions.Execution; 6 | import io.kestra.core.models.flows.State; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.hasSize; 11 | import static org.hamcrest.Matchers.is; 12 | 13 | @KestraTest(startRunner = true) 14 | class RunnerTest { 15 | @Test 16 | @ExecuteFlow("sanity-checks/all_duckdb.yaml") 17 | void duck(Execution execution) { 18 | assertThat(execution.getTaskRunList(), hasSize(7)); 19 | assertThat(execution.getState().getCurrent(), is(State.Type.SUCCESS)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/resources/db/duck.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kestra-io/plugin-jdbc/8d9476dee87f40d42dd46acb99ad4ee2e6f53ce3/plugin-jdbc-duckdb/src/test/resources/db/duck.db -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/resources/db/file.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kestra-io/plugin-jdbc/8d9476dee87f40d42dd46acb99ad4ee2e6f53ce3/plugin-jdbc-duckdb/src/test/resources/db/file.db -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/resources/flows/duckdb-listen.yml: -------------------------------------------------------------------------------- 1 | id: duckdb-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.duckdb.Trigger 7 | sql: SHOW DATABASES; 8 | fetchType: FETCH 9 | interval: PT10S 10 | 11 | tasks: 12 | - id: end 13 | type: io.kestra.plugin.core.debug.Return 14 | format: "{{task.id}} > {{taskrun.startDate}}" 15 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/resources/full.csv: -------------------------------------------------------------------------------- 1 | id,name,nameNullable,email,enum,long,double,boolean,date,timeMillis,timestampMillis,timestampMicros 2 | 4814976,Viva,,alidgertwood0@nbcnews.com,Female,-867174862080523000,1783477.3480111,true,2017/11/16,5:14,2017-02-07T11:23:39Z,2013-02-05T11:07:59Z 3 | 1010871,Voomm,,pbickardike1@ask.com,Female,-543538211523588000,336497.290186367,false,2013/10/23,20:13,2013-02-22T17:23:16Z,2014-03-31T03:58:14Z 4 | 6782048,Ailane,,atallman2@behance.net,Female,811100629418909000,3960012.24870472,false,2018/12/29,5:48,2014-06-26T14:00:40Z,2013-05-29T14:52:27Z 5 | 989670,Livetube,,bhalden3@latimes.com,Male,-296867021871686000,-827942.531367063,true,2017/04/11,4:40,2015-11-27T07:07:59Z,2019-01-09T23:21:09Z 6 | 1696964,Quinu,Cassin-Kuvalis,vburnett4@booking.com,Male,-34235845432045000,7159701.2827758,false,2015/11/10,16:16,2017-12-14T02:56:11Z,2014-01-23T16:28:06Z 7 | 8761731,Quamba,,akenealy5@de.vu,Male,-703765021147379000,6645902.42050891,false,2019/02/19,14:28,2013-11-08T12:17:16Z,2015-05-14T15:31:35Z 8 | 5768523,Tagcat,,cbutten6@wp.com,Male,-225371364113854000,-5819992.97849869,true,2012/06/11,2:39,2017-01-15T00:36:03Z,2013-01-09T14:01:03Z 9 | 6702408,Roomm,Lehner-Spinka,coakenford7@usgs.gov,Female,-671713890705882000,-8714693.00524589,true,2014/01/24,13:27,2013-09-27T20:08:50Z,2018-07-22T23:06:24Z 10 | 3896245,Flashspan,McClure Inc,jgantley8@timesonline.co.uk,Female,293778321842392000,-3969041.18500936,false,2014/02/25,23:14,2017-03-16T23:48:44Z,2018-04-06T11:46:45Z 11 | 946749,Browsebug,,acandish9@ucoz.ru,Male,-16657286794668100,5309576.03110703,true,2018/11/29,11:55,2014-02-27T07:37:35Z,2014-05-02T01:51:06Z 12 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-duckdb/src/test/resources/sanity-checks/all_duckdb.yaml: -------------------------------------------------------------------------------- 1 | id: all_duckdb 2 | namespace: sanitychecks.plugin-jdbc 3 | 4 | tasks: 5 | - id: http_download 6 | type: io.kestra.plugin.core.http.Download 7 | uri: "https://huggingface.co/datasets/kestra/datasets/raw/main/csv/orders.csv" 8 | 9 | - id: check_query 10 | type: io.kestra.plugin.jdbc.duckdb.Query 11 | url: 'jdbc:duckdb:' 12 | inputFiles: 13 | data.csv: "{{ outputs.http_download.uri }}" 14 | fetchType: STORE 15 | sql: | 16 | SELECT * FROM read_csv_auto('data.csv', header=True); 17 | 18 | 19 | - id: check_queries 20 | type: io.kestra.plugin.jdbc.duckdb.Queries 21 | url: 'jdbc:duckdb:' 22 | inputFiles: 23 | data.csv: "{{ outputs.http_download.uri }}" 24 | fetchType: STORE 25 | sql: | 26 | CREATE TABLE t1 AS SELECT * FROM read_csv_auto('data.csv', header=True); 27 | INSERT INTO t1 SELECT * FROM t1 LIMIT 3; 28 | SELECT * FROM t1; 29 | SELECT * FROM t1 LIMIT 2; 30 | 31 | - id: assert_size 32 | type: io.kestra.plugin.core.execution.Fail 33 | condition: "{{ outputs.check_queries.outputs[0].size != 103}}" 34 | 35 | - id: assert_size2 36 | type: io.kestra.plugin.core.execution.Fail 37 | condition: "{{ outputs.check_queries.outputs[1].size != 2}}" 38 | 39 | 40 | - id: check_query_fetch 41 | type: io.kestra.plugin.jdbc.duckdb.Query 42 | url: 'jdbc:duckdb:' 43 | inputFiles: 44 | data.csv: "{{ outputs.http_download.uri }}" 45 | fetchType: FETCH_ONE 46 | sql: | 47 | SELECT * FROM read_csv_auto('data.csv', header=True); 48 | 49 | - id: assert_size3 50 | type: io.kestra.plugin.core.execution.Fail 51 | condition: "{{ outputs.check_query_fetch.size != 1}}" -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Query MariaDB databases using the Kestra JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "MariaDB", 8 | "X-Kestra-Group": project.group + ".jdbc.mariadb", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation 'org.mariadb.jdbc:mariadb-java-client:3.5.3' 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/main/java/io/kestra/plugin/jdbc/mariadb/MariaDbCellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.mariadb; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import io.kestra.core.serializers.JacksonMapper; 5 | import io.kestra.plugin.jdbc.AbstractCellConverter; 6 | import io.kestra.plugin.jdbc.AbstractJdbcBatch; 7 | 8 | import java.sql.Connection; 9 | import java.sql.PreparedStatement; 10 | import java.sql.ResultSet; 11 | import java.sql.SQLException; 12 | import java.time.ZoneId; 13 | 14 | public class MariaDbCellConverter extends AbstractCellConverter { 15 | public MariaDbCellConverter(ZoneId zoneId) { 16 | super(zoneId); 17 | } 18 | 19 | @Override 20 | public Object convertCell(int columnIndex, ResultSet rs, Connection connection) throws SQLException { 21 | Object data = rs.getObject(columnIndex); 22 | 23 | if (data == null) { 24 | return null; 25 | } 26 | 27 | String columnTypeName = rs.getMetaData().getColumnTypeName(columnIndex); 28 | 29 | return switch (columnTypeName.toLowerCase()) { 30 | case "blob" -> rs.getBytes(columnIndex); 31 | case "json" -> { 32 | try { 33 | yield JacksonMapper.ofJson(false).readValue(rs.getString(columnIndex), Object.class); 34 | } catch (JsonProcessingException e) { 35 | throw new SQLException(e); 36 | } 37 | } 38 | default -> super.convert(columnIndex, rs); 39 | }; 40 | 41 | } 42 | 43 | @Override 44 | public PreparedStatement addPreparedStatementValue(PreparedStatement ps, AbstractJdbcBatch.ParameterType parameterType, Object value, int index, Connection connection) throws Exception { 45 | throw new UnsupportedOperationException(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/main/java/io/kestra/plugin/jdbc/mariadb/MariaDbConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.mariadb; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface MariaDbConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:mariadb"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/main/java/io/kestra/plugin/jdbc/mariadb/MariaDbUtils.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.mariadb; 2 | 3 | import io.micronaut.http.uri.UriBuilder; 4 | 5 | import java.net.URI; 6 | import java.nio.file.Path; 7 | import java.util.Properties; 8 | 9 | public abstract class MariaDbUtils { 10 | protected static Properties createMariaDbProperties(Properties props, Path workingDirectory, boolean isMultiQuery) { 11 | URI url = URI.create((String) props.get("jdbc.url")); 12 | url = URI.create(url.getSchemeSpecificPart()); 13 | 14 | UriBuilder builder = UriBuilder.of(url); 15 | 16 | // see https://dev.mariadb.com/doc/connector-j/8.0/en/connector-j-reference-implementation-notes.html 17 | // By default, ResultSets are completely retrieved and stored in memory. 18 | builder.replaceQueryParam("useCursorFetch", true); 19 | 20 | builder.scheme("jdbc:mariadb"); 21 | 22 | if(isMultiQuery) { 23 | builder.queryParam("allowMultiQueries", true); 24 | } 25 | 26 | props.put("jdbc.url", builder.build().toString()); 27 | 28 | return props; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/main/java/io/kestra/plugin/jdbc/mariadb/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the MariaDB database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.mariadb; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/main/resources/icons/io.kestra.plugin.jdbc.mariadb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/main/resources/icons/plugin-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/test/java/io/kestra/plugin/jdbc/mariadb/MariaDbDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.mariadb; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class MariaDbDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return org.mariadb.jdbc.Driver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/test/java/io/kestra/plugin/jdbc/mariadb/MariaDbTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.mariadb; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.io.FileNotFoundException; 8 | import java.net.URISyntaxException; 9 | import java.sql.SQLException; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.hamcrest.Matchers.is; 15 | 16 | @KestraTest 17 | class MariaDbTriggerTest extends AbstractJdbcTriggerTest { 18 | 19 | @Test 20 | void run() throws Exception { 21 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","mariadb-listen"); 22 | 23 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 24 | assertThat(rows.size(), is(1)); 25 | } 26 | 27 | @Override 28 | protected String getUrl() { 29 | return "jdbc:mariadb://127.0.0.1:64791/kestra"; 30 | } 31 | 32 | @Override 33 | protected String getUsername() { 34 | return "root"; 35 | } 36 | 37 | @Override 38 | protected String getPassword() { 39 | return "mariadb_passwd"; 40 | } 41 | 42 | @Override 43 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 44 | executeSqlScript("scripts/mariadb.sql"); 45 | } 46 | } -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/test/resources/flows/mysql-listen.yml: -------------------------------------------------------------------------------- 1 | id: mariadb-listen 2 | namespace: io.kestra.jdbc.mariadb 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.mariadb.Trigger 7 | sql: SELECT * FROM mariadb_types 8 | url: jdbc:mariadb://127.0.0.1:64791/kestra 9 | username: root 10 | password: mariadb_passwd 11 | fetchType: FETCH 12 | interval: PT10S 13 | 14 | tasks: 15 | - id: end 16 | type: io.kestra.plugin.core.debug.Return 17 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/test/resources/flows/read_mysql.yaml: -------------------------------------------------------------------------------- 1 | id: read_mariadb 2 | namespace: io.kestra.jdbc.mariadb.trigger 3 | 4 | tasks: 5 | - id: read 6 | type: io.kestra.plugin.jdbc.mariadb.Query 7 | url: jdbc:mariadb://127.0.0.1:56982/ 8 | username: root 9 | password: mariadb_passwd 10 | sql: select * from mariadb_types 11 | fetchType: FETCH_ONE 12 | - id: flow-id 13 | type: io.kestra.plugin.core.debug.Return 14 | format: "{{outputs.update.row}}" 15 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/test/resources/load.csv: -------------------------------------------------------------------------------- 1 | id,title,expired date,amount 2 | 1,"Spring Break 2014",20140401,20 3 | 2,"Back to school 2014",20140901,25 4 | 3,"Summer 2014",20140825,10 5 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/test/resources/scripts/mariadb_insert.sql: -------------------------------------------------------------------------------- 1 | USE kestra; 2 | 3 | DROP TABLE IF EXISTS mariadb_types; 4 | DROP TABLE IF EXISTS namedInsert; 5 | 6 | CREATE TABLE mariadb_types ( 7 | concert_id SERIAL, 8 | available TINYINT not null, 9 | a CHAR(4) not null, 10 | b VARCHAR(30) not null, 11 | c TEXT not null, 12 | d VARCHAR(10), 13 | play_time BIGINT not null, 14 | library_record BIGINT not null, 15 | bitn_test BIT(6), 16 | floatn_test FLOAT not null, 17 | double_test DOUBLE not null, 18 | doublen_test DOUBLE(18,4) not null, 19 | numeric_test NUMERIC(3,2) not null, 20 | salary_decimal DECIMAL(5,2), 21 | date_type DATE not null, 22 | datetime_type DATETIME(6) not null, 23 | time_type TIME not null, 24 | timestamp_type TIMESTAMP(6) not null, 25 | year_type YEAR(4) not null, 26 | json_type JSON not null, 27 | blob_type BLOB not null, 28 | PRIMARY KEY (concert_id) 29 | ); 30 | 31 | CREATE TABLE namedInsert ( 32 | id SERIAL, 33 | name VARCHAR(10), 34 | address VARCHAR(30), 35 | PRIMARY KEY (id) 36 | ); 37 | -------------------------------------------------------------------------------- /plugin-jdbc-mariadb/src/test/resources/scripts/mariadb_queries.sql: -------------------------------------------------------------------------------- 1 | USE kestra; 2 | 3 | DROP TABLE IF EXISTS employee; 4 | 5 | CREATE TABLE employee ( 6 | employee_id SERIAL NOT NULL, 7 | firstName VARCHAR(30), 8 | lastName VARCHAR(30), 9 | age INT, 10 | PRIMARY KEY (employee_id) 11 | ); 12 | 13 | INSERT INTO employee (employee_id, firstName, lastName, age) 14 | VALUES 15 | (1, 'John', 'Doe', 45), 16 | (2, 'Bryan', 'Grant', 33), 17 | (3, 'Jude', 'Philips', 25), 18 | (4, 'Michael', 'Page', 62); 19 | 20 | DROP TABLE IF EXISTS laptop; 21 | 22 | CREATE TABLE laptop 23 | ( 24 | laptop_id SERIAL NOT NULL, 25 | brand VARCHAR(30), 26 | model VARCHAR(30), 27 | cpu_frequency FLOAT, 28 | PRIMARY KEY (laptop_id) 29 | ); 30 | INSERT INTO laptop (laptop_id, brand, model, cpu_frequency) 31 | VALUES 32 | (1, 'Apple', 'MacBookPro M1 13', 2.2), 33 | (2, 'Apple', 'MacBookPro M3 16', 1.5), 34 | (3, 'LG', 'Gram', 1.95), 35 | (4, 'Lenovo', 'ThinkPad', 1.05); 36 | 37 | 38 | /* Table for testing transactionnal queries */ 39 | DROP TABLE IF EXISTS test_transaction; 40 | CREATE TABLE test_transaction 41 | ( 42 | id MEDIUMINT NOT NULL AUTO_INCREMENT, 43 | name VARCHAR(30) NOT NULL, 44 | PRIMARY KEY (id) 45 | ); -------------------------------------------------------------------------------- /plugin-jdbc-mysql/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Query MySQL databases using the Kestra JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "MySQL", 8 | "X-Kestra-Group": project.group + ".jdbc.mysql", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | jdbcDriver 'mysql:mysql-connector-java:8.0.33' 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/main/java/io/kestra/plugin/jdbc/mysql/MySqlConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.mysql; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | import io.micronaut.http.uri.UriBuilder; 5 | 6 | import java.net.URI; 7 | import java.nio.file.Path; 8 | import java.util.Properties; 9 | 10 | public interface MySqlConnectionInterface extends JdbcConnectionInterface { 11 | @Override 12 | default String getScheme() { 13 | return "jdbc:mysql"; 14 | } 15 | 16 | default Properties createMysqlProperties(Properties props, Path workingDirectory, 17 | boolean isMultiQuery) { 18 | URI url = URI.create((String) props.get("jdbc.url")); 19 | url = URI.create(url.getSchemeSpecificPart()); 20 | 21 | UriBuilder builder = UriBuilder.of(url); 22 | 23 | // allow local in file for current worker and prevent the global one 24 | builder.queryParam("allowLoadLocalInfileInPath", workingDirectory.toAbsolutePath().toString()); 25 | builder.replaceQueryParam("allowLoadLocalInfile", false); 26 | 27 | // see https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-implementation-notes.html 28 | // By default, ResultSets are completely retrieved and stored in memory. 29 | builder.replaceQueryParam("useCursorFetch", true); 30 | 31 | builder.scheme("jdbc:mysql"); 32 | 33 | if(isMultiQuery) { 34 | builder.queryParam("allowMultiQueries", true); 35 | } 36 | 37 | props.put("jdbc.url", builder.build().toString()); 38 | 39 | return props; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/main/java/io/kestra/plugin/jdbc/mysql/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the MySQL database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.mysql; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/java/io/kestra/plugin/jdbc/mysql/MySqlTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.mysql; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.io.FileNotFoundException; 8 | import java.net.URISyntaxException; 9 | import java.sql.SQLException; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.hamcrest.Matchers.is; 15 | 16 | @KestraTest 17 | class MySqlTriggerTest extends AbstractJdbcTriggerTest { 18 | 19 | @Test 20 | void run() throws Exception { 21 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","mysql-listen"); 22 | 23 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 24 | assertThat(rows.size(), is(1)); 25 | } 26 | 27 | @Override 28 | protected String getUrl() { 29 | return "jdbc:mysql://127.0.0.1:64790/kestra"; 30 | } 31 | 32 | @Override 33 | protected String getUsername() { 34 | return "root"; 35 | } 36 | 37 | @Override 38 | protected String getPassword() { 39 | return "mysql_passwd"; 40 | } 41 | 42 | @Override 43 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 44 | executeSqlScript("scripts/mysql.sql"); 45 | } 46 | } -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/java/io/kestra/plugin/jdbc/mysql/MysqlDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.mysql; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class MysqlDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return com.mysql.cj.jdbc.Driver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/resources/flows/mysql-listen.yml: -------------------------------------------------------------------------------- 1 | id: mysql-listen 2 | namespace: io.kestra.jdbc.mysql 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.mysql.Trigger 7 | sql: SELECT * FROM mysql_types 8 | url: jdbc:mysql://127.0.0.1:64790/kestra 9 | username: root 10 | password: mysql_passwd 11 | fetchType: FETCH 12 | interval: PT10S 13 | 14 | tasks: 15 | - id: end 16 | type: io.kestra.plugin.core.debug.Return 17 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/resources/flows/read_mysql.yaml: -------------------------------------------------------------------------------- 1 | id: read_mysql 2 | namespace: io.kestra.jdbc.mysql.trigger 3 | 4 | tasks: 5 | - id: read 6 | type: io.kestra.plugin.jdbc.mysql.Query 7 | url: jdbc:mysql://127.0.0.1:56982/ 8 | username: root 9 | password: mysql_passwd 10 | sql: select * from mysql_types 11 | fetchType: FETCH_ONE 12 | - id: flow-id 13 | type: io.kestra.plugin.core.debug.Return 14 | format: "{{outputs.update.row}}" 15 | -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/resources/load.csv: -------------------------------------------------------------------------------- 1 | id,title,expired date,amount 2 | 1,"Spring Break 2014",20140401,20 3 | 2,"Back to school 2014",20140901,25 4 | 3,"Summer 2014",20140825,10 5 | -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/resources/scripts/mysql.sql: -------------------------------------------------------------------------------- 1 | 2 | USE kestra; 3 | 4 | DROP TABLE IF EXISTS mysql_types; 5 | 6 | CREATE TABLE mysql_types ( 7 | concert_id SERIAL, 8 | available TINYINT not null, 9 | a CHAR(4) not null, 10 | b VARCHAR(30) not null, 11 | c TEXT not null, 12 | d VARCHAR(10), 13 | play_time BIGINT not null, 14 | library_record BIGINT not null, 15 | bitn_test BIT(6) not null, 16 | floatn_test FLOAT not null, 17 | double_test DOUBLE not null, 18 | doublen_test DOUBLE(18,4) not null, 19 | numeric_test NUMERIC(3,2) not null, 20 | salary_decimal DECIMAL(5,2), 21 | date_type DATE not null, 22 | datetime_type DATETIME(6) not null, 23 | time_type TIME not null, 24 | timestamp_type TIMESTAMP(6) not null, 25 | year_type YEAR(4) not null, 26 | json_type JSON not null, 27 | blob_type BLOB not null, 28 | PRIMARY KEY (concert_id) 29 | ); 30 | 31 | 32 | -- Insert 33 | INSERT INTO mysql_types 34 | (concert_id, 35 | available, 36 | a, 37 | b, 38 | c, 39 | d, 40 | play_time, 41 | library_record, 42 | bitn_test, 43 | floatn_test, 44 | double_test, 45 | doublen_test, 46 | numeric_test, 47 | salary_decimal, 48 | date_type, 49 | datetime_type, 50 | time_type, 51 | timestamp_type, 52 | year_type, 53 | json_type, 54 | blob_type) 55 | VALUES ( DEFAULT, 56 | true, 57 | 'four', 58 | 'This is a varchar', 59 | 'This is a text column data', 60 | NULL, 61 | -9223372036854775808, 62 | 1844674407370955161, 63 | b'000101', 64 | 9223372036854776000, 65 | 9223372036854776000, 66 | 2147483645.1234, 67 | 5.36, 68 | 999.99, 69 | '2030-12-25', 70 | '2050-12-31 22:59:57.150150', 71 | '04:05:30', 72 | '2004-10-19 10:23:54.999999', 73 | '2025', 74 | '{"color":"red","value":"#f00"}', 75 | x'DEADBEEF' ); -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/resources/scripts/mysql_insert.sql: -------------------------------------------------------------------------------- 1 | USE kestra; 2 | 3 | DROP TABLE IF EXISTS mysql_types; 4 | DROP TABLE IF EXISTS namedInsert; 5 | 6 | CREATE TABLE mysql_types ( 7 | concert_id SERIAL, 8 | available TINYINT not null, 9 | a CHAR(4) not null, 10 | b VARCHAR(30) not null, 11 | c TEXT not null, 12 | d VARCHAR(10), 13 | play_time BIGINT not null, 14 | library_record BIGINT not null, 15 | bitn_test BIT(6), 16 | floatn_test FLOAT not null, 17 | double_test DOUBLE not null, 18 | doublen_test DOUBLE(18,4) not null, 19 | numeric_test NUMERIC(3,2) not null, 20 | salary_decimal DECIMAL(5,2), 21 | date_type DATE not null, 22 | datetime_type DATETIME(6) not null, 23 | time_type TIME not null, 24 | timestamp_type TIMESTAMP(6) not null, 25 | year_type YEAR(4) not null, 26 | json_type JSON not null, 27 | blob_type BLOB not null, 28 | PRIMARY KEY (concert_id) 29 | ); 30 | 31 | CREATE TABLE namedInsert ( 32 | id SERIAL, 33 | name VARCHAR(10), 34 | address VARCHAR(30), 35 | PRIMARY KEY (id) 36 | ); 37 | -------------------------------------------------------------------------------- /plugin-jdbc-mysql/src/test/resources/scripts/mysql_queries.sql: -------------------------------------------------------------------------------- 1 | USE kestra; 2 | 3 | DROP TABLE IF EXISTS employee; 4 | 5 | CREATE TABLE employee ( 6 | employee_id SERIAL NOT NULL, 7 | firstName VARCHAR(30), 8 | lastName VARCHAR(30), 9 | age INT, 10 | PRIMARY KEY (employee_id) 11 | ); 12 | 13 | INSERT INTO employee (employee_id, firstName, lastName, age) 14 | VALUES 15 | (1, 'John', 'Doe', 45), 16 | (2, 'Bryan', 'Grant', 33), 17 | (3, 'Jude', 'Philips', 25), 18 | (4, 'Michael', 'Page', 62); 19 | 20 | DROP TABLE IF EXISTS laptop; 21 | 22 | CREATE TABLE laptop 23 | ( 24 | laptop_id SERIAL NOT NULL, 25 | brand VARCHAR(30), 26 | model VARCHAR(30), 27 | cpu_frequency FLOAT, 28 | PRIMARY KEY (laptop_id) 29 | ); 30 | INSERT INTO laptop (laptop_id, brand, model, cpu_frequency) 31 | VALUES 32 | (1, 'Apple', 'MacBookPro M1 13', 2.2), 33 | (2, 'Apple', 'MacBookPro M3 16', 1.5), 34 | (3, 'LG', 'Gram', 1.95), 35 | (4, 'Lenovo', 'ThinkPad', 1.05); 36 | 37 | 38 | /* Table for testing transactionnal queries */ 39 | DROP TABLE IF EXISTS test_transaction; 40 | CREATE TABLE test_transaction 41 | ( 42 | id MEDIUMINT NOT NULL AUTO_INCREMENT, 43 | name VARCHAR(30) NOT NULL, 44 | PRIMARY KEY (id) 45 | ); -------------------------------------------------------------------------------- /plugin-jdbc-oracle/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Access Oracle databases with Kestra\'s JDBC plugin integration.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Oracle", 8 | "X-Kestra-Group": project.group + ".jdbc.oracle", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation("com.oracle.database.jdbc:ojdbc11:23.8.0.25.04") 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | 22 | // https://stackoverflow.com/questions/9156379/ora-01882-timezone-region-not-found 23 | test { 24 | systemProperty "user.timezone", "Europe/Paris" 25 | } 26 | -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/main/java/io/kestra/plugin/jdbc/oracle/OracleConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.oracle; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface OracleConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:oracle"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/main/java/io/kestra/plugin/jdbc/oracle/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Oracle database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.oracle; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/test/java/io/kestra/plugin/jdbc/oracle/OracleDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.oracle; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class OracleDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return oracle.jdbc.OracleDriver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/test/java/io/kestra/plugin/jdbc/oracle/OracleTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.oracle; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.h2.tools.RunScript; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.io.StringReader; 10 | import java.net.URISyntaxException; 11 | import java.sql.SQLException; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.is; 17 | 18 | @KestraTest 19 | class OracleTriggerTest extends AbstractJdbcTriggerTest { 20 | 21 | @Test 22 | void run() throws Exception { 23 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","oracle-listen"); 24 | 25 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 26 | assertThat(rows.size(), is(1)); 27 | } 28 | 29 | @Override 30 | protected String getUrl() { 31 | return "jdbc:oracle:thin:@localhost:49161:XE"; 32 | } 33 | 34 | @Override 35 | protected String getUsername() { 36 | return "system"; 37 | } 38 | 39 | @Override 40 | protected String getPassword() { 41 | return "oracle"; 42 | } 43 | 44 | @Override 45 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 46 | try { 47 | RunScript.execute(getConnection(), new StringReader("DROP TABLE oracle_types;")); 48 | } catch (Exception ignored) { 49 | 50 | } 51 | 52 | executeSqlScript("scripts/oracle.sql"); 53 | } 54 | } -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/test/resources/flows/oracle-listen.yml: -------------------------------------------------------------------------------- 1 | id: oracle-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.oracle.Trigger 7 | sql: SELECT * FROM oracle_types 8 | url: jdbc:oracle:thin:@localhost:49161:XE 9 | username: system 10 | password: oracle 11 | fetchType: FETCH 12 | interval: PT10S 13 | 14 | tasks: 15 | - id: end 16 | type: io.kestra.plugin.core.debug.Return 17 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/test/resources/scripts/oracle.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE TABLE oracle_types ( 3 | t_NULL VARCHAR2(2), 4 | t_CHAR CHAR(2) NOT NULL, 5 | t_VARCHAR VARCHAR2(2) NOT NULL, 6 | t_VARCHAR2 VARCHAR(2) NOT NULL, 7 | t_NVARCHAR NCHAR(2) NOT NULL, 8 | t_NVARCHAR2 NVARCHAR2(2) NOT NULL, 9 | t_BLOB BLOB NOT NULL, 10 | t_CLOB CLOB NOT NULL, 11 | t_NCLOB NCLOB NOT NULL, 12 | -- t_BFILE BFILE NOT NULL, 13 | t_NUMBER NUMBER NOT NULL, 14 | t_NUMBER_1 NUMBER(*,1) NOT NULL, 15 | t_NUMBER_2 NUMBER(9) NOT NULL, 16 | t_NUMBER_3 NUMBER(9,2) NOT NULL, 17 | t_NUMBER_4 NUMBER(9,1) NOT NULL, 18 | t_NUMBER_5 NUMBER(7,-2) NOT NULL, 19 | t_BINARY_FLOAT BINARY_FLOAT NOT NULL, 20 | t_BINARY_DOUBLE BINARY_DOUBLE NOT NULL, 21 | t_DATE DATE NOT NULL, 22 | t_TIMESTAMP TIMESTAMP NOT NULL, 23 | t_TIMESTAMP_TIME_ZONE TIMESTAMP WITH TIME ZONE NOT NULL, 24 | t_TIMESTAMP_LOCAL TIMESTAMP WITH LOCAL TIME ZONE NOT NULL 25 | ); 26 | 27 | 28 | INSERT INTO oracle_types 29 | ( 30 | t_NULL, 31 | t_CHAR, 32 | t_VARCHAR, 33 | t_VARCHAR2, 34 | t_NVARCHAR, 35 | t_NVARCHAR2, 36 | t_BLOB, 37 | t_CLOB, 38 | t_NCLOB, 39 | -- t_BFILE, 40 | t_NUMBER, 41 | t_NUMBER_1, 42 | t_NUMBER_2, 43 | t_NUMBER_3, 44 | t_NUMBER_4, 45 | t_NUMBER_5, 46 | t_BINARY_FLOAT, 47 | t_BINARY_DOUBLE, 48 | t_DATE, 49 | t_TIMESTAMP, 50 | t_TIMESTAMP_TIME_ZONE, 51 | t_TIMESTAMP_LOCAL 52 | ) 53 | VALUES 54 | ( 55 | NULL, 56 | 'aa', 57 | 'bb', 58 | 'cc', 59 | 'dd', 60 | 'ee', 61 | UTL_RAW.CAST_TO_RAW('ff'), 62 | 'gg', 63 | 'hh', 64 | -- BFILENAME('STUFF', 'WD.pdf'), 65 | 7456123.89, 66 | 7456123.89, 67 | 7456123.89, 68 | 7456123.89, 69 | 7456123.89, 70 | 7456123.89, 71 | 7456123.89, 72 | 7456123.89, 73 | TO_DATE('November 13, 1992', 'MONTH DD, YYYY'), 74 | TIMESTAMP'1998-1-23 6:00:00-5:00', 75 | TIMESTAMP'1998-1-23 6:00:00-5:00', 76 | TIMESTAMP'1998-1-23 6:00:00-5:00' 77 | ); 78 | -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/test/resources/scripts/oracle_insert.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE oracle_types ( 2 | t_CHAR CHAR(2) NOT NULL, 3 | t_NULL VARCHAR2(2), 4 | t_VARCHAR VARCHAR2(2) NOT NULL, 5 | t_VARCHAR2 VARCHAR(2) NOT NULL, 6 | t_NVARCHAR NCHAR(2) NOT NULL, 7 | t_NVARCHAR2 NVARCHAR2(2) NOT NULL, 8 | t_BLOB BLOB NOT NULL, 9 | t_CLOB CLOB NOT NULL, 10 | t_NCLOB NCLOB NOT NULL, 11 | t_NUMBER NUMBER NOT NULL, 12 | t_NUMBER_1 NUMBER(*,1) NOT NULL, 13 | t_NUMBER_2 NUMBER(9) NOT NULL, 14 | t_NUMBER_3 NUMBER(9,2) NOT NULL, 15 | t_NUMBER_4 NUMBER(9,1) NOT NULL, 16 | t_NUMBER_5 NUMBER(7,-2) NOT NULL, 17 | t_BINARY_FLOAT BINARY_FLOAT NOT NULL, 18 | t_BINARY_DOUBLE BINARY_DOUBLE NOT NULL, 19 | t_DATE DATE NOT NULL, 20 | t_TIMESTAMP TIMESTAMP NOT NULL, 21 | t_TIMESTAMP_TIME_ZONE TIMESTAMP WITH TIME ZONE NOT NULL, 22 | t_TIMESTAMP_LOCAL TIMESTAMP WITH LOCAL TIME ZONE NOT NULL 23 | ); 24 | 25 | CREATE TABLE namedInsert ( 26 | t_id NUMBER, 27 | t_name VARCHAR(20), 28 | t_address VARCHAR(20) 29 | ); 30 | 31 | -------------------------------------------------------------------------------- /plugin-jdbc-oracle/src/test/resources/scripts/oracle_queries.sql: -------------------------------------------------------------------------------- 1 | -- Create table employee 2 | CREATE TABLE employee ( 3 | firstName VARCHAR(100), 4 | lastName VARCHAR(100), 5 | age INTEGER 6 | ); 7 | 8 | INSERT INTO employee(firstName, lastName, age) VALUES ('John', 'Doe', 45); 9 | INSERT INTO employee(firstName, lastName, age) VALUES ('Bryan', 'Grant', 33); 10 | INSERT INTO employee(firstName, lastName, age) VALUES ('Jude', 'Philips', 25); 11 | INSERT INTO employee(firstName, lastName, age) VALUES ('Michael', 'Page', 62); 12 | 13 | 14 | -- Create table laptop 15 | CREATE TABLE laptop 16 | ( 17 | brand VARCHAR(100), 18 | model VARCHAR(100), 19 | cpu_frequency BINARY_DOUBLE 20 | ); 21 | 22 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M1 13', 2.2); 23 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M3 16', 1.5); 24 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('LG', 'Gram', 1.95); 25 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Lenovo', 'ThinkPad', 1.05); -------------------------------------------------------------------------------- /plugin-jdbc-pinot/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Connect and query Apache Pinot databases using Kestra\'s JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Apache Pinot", 8 | "X-Kestra-Group": project.group + ".jdbc.pinot", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation("org.apache.pinot:pinot-jdbc-client:1.3.0") { 17 | exclude group: 'org.slf4j' 18 | exclude group: 'com.fasterxml.jackson.core' 19 | } 20 | implementation project(':plugin-jdbc') 21 | 22 | testImplementation project(':plugin-jdbc').sourceSets.test.output 23 | } 24 | -------------------------------------------------------------------------------- /plugin-jdbc-pinot/src/main/java/io/kestra/plugin/jdbc/pinot/PinotCellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.pinot; 2 | 3 | import io.kestra.plugin.jdbc.AbstractCellConverter; 4 | import lombok.SneakyThrows; 5 | 6 | import java.sql.Connection; 7 | import java.sql.ResultSet; 8 | import java.sql.SQLException; 9 | import java.time.ZoneId; 10 | 11 | public class PinotCellConverter extends AbstractCellConverter { 12 | public PinotCellConverter(ZoneId zoneId) { 13 | super(zoneId); 14 | } 15 | 16 | @SneakyThrows 17 | @Override 18 | public Object convertCell(int columnIndex, ResultSet rs, Connection connection) throws SQLException { 19 | return super.convert(columnIndex, rs); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /plugin-jdbc-pinot/src/main/java/io/kestra/plugin/jdbc/pinot/PinotConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.pinot; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface PinotConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:pinot"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-pinot/src/main/java/io/kestra/plugin/jdbc/pinot/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Apache Pinot database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.pinot; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-pinot/src/test/java/io/kestra/plugin/jdbc/pinot/PinotDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.pinot; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | import org.apache.pinot.client.PinotDriver; 6 | 7 | import java.sql.Driver; 8 | 9 | @KestraTest 10 | public class PinotDriverTest extends AbstractJdbcDriverTest { 11 | @Override 12 | protected Class getDriverClass() { 13 | return PinotDriver.class; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /plugin-jdbc-pinot/src/test/java/io/kestra/plugin/jdbc/pinot/PinotQueriesTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.pinot; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import io.kestra.core.models.property.Property; 6 | import io.kestra.core.runners.RunContext; 7 | import io.kestra.core.runners.RunContextFactory; 8 | import io.kestra.plugin.jdbc.AbstractJdbcQueries; 9 | import io.kestra.plugin.jdbc.AbstractJdbcQuery; 10 | import jakarta.inject.Inject; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import java.util.Map; 14 | 15 | import static io.kestra.core.models.tasks.common.FetchType.FETCH_ONE; 16 | import static org.hamcrest.MatcherAssert.assertThat; 17 | import static org.hamcrest.Matchers.*; 18 | 19 | /** 20 | * See : 21 | * - https://docs.pinot.apache.org/configuration-reference/schema 22 | */ 23 | @KestraTest 24 | class PinotQueriesTest { 25 | @Inject 26 | RunContextFactory runContextFactory; 27 | 28 | @Test 29 | void multiSelect() throws Exception { 30 | RunContext runContext = runContextFactory.of(ImmutableMap.of()); 31 | 32 | Queries task = Queries.builder() 33 | .url(Property.of("jdbc:pinot://localhost:49000")) 34 | .fetchType(Property.of(FETCH_ONE)) 35 | .timeZoneId(Property.of("Europe/Paris")) 36 | .sql(Property.of(""" 37 | select count(*) as count from airlineStats; 38 | """)) 39 | .build(); 40 | 41 | AbstractJdbcQueries.MultiQueryOutput runOutput = task.run(runContext); 42 | assertThat(runOutput.getOutputs().getFirst().getRow(), notNullValue()); 43 | assertThat(runOutput.getOutputs().getFirst().getRow().get("count"), is(9746L)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /plugin-jdbc-pinot/src/test/java/io/kestra/plugin/jdbc/pinot/PinotTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.pinot; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.io.FileNotFoundException; 8 | import java.net.URISyntaxException; 9 | import java.sql.SQLException; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.hamcrest.Matchers.is; 15 | 16 | @KestraTest 17 | class PinotTriggerTest extends AbstractJdbcTriggerTest { 18 | 19 | @Test 20 | void run() throws Exception { 21 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","pinot-listen"); 22 | 23 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 24 | assertThat(rows.size(), is(1)); 25 | } 26 | 27 | @Override 28 | protected String getUrl() { 29 | return "jdbc:pinot://localhost:49000"; 30 | } 31 | 32 | @Override 33 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 34 | // nothing here, we use Pinot samples. 35 | } 36 | } -------------------------------------------------------------------------------- /plugin-jdbc-pinot/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-pinot/src/test/resources/flows/pinot-listen.yml: -------------------------------------------------------------------------------- 1 | id: pinot-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.pinot.Trigger 7 | sql: | 8 | select 9 | -- NULL as t_null, 10 | 'string' AS t_string, 11 | CAST(2147483647 AS INT) as t_integer, 12 | CAST(9223372036854775807 AS LONG) as t_long, 13 | CAST(12345.124 AS FLOAT) as t_float, 14 | CAST(12345.124 AS DOUBLE) as t_double, 15 | ST_GeogFromText('LINESTRING (30 10, 10 30, 40 40)') as t_geo, 16 | ToDateTime(1639137263000, 'yyyy-MM-dd') as t_date, 17 | ToEpochSeconds(1613472303000) AS t_epoch 18 | from airlineStats 19 | limit 1 20 | url: jdbc:pinot://localhost:49000 21 | fetchType: FETCH 22 | interval: PT10S 23 | 24 | tasks: 25 | - id: end 26 | type: io.kestra.plugin.core.debug.Return 27 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-pinot/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-postgres/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Access PostgreSQL databases using Kestra\'s JDBC plugin integration.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "PostgreSQL", 8 | "X-Kestra-Group": project.group + ".jdbc.postgresql", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | jdbcDriver 'org.postgresql:postgresql:42.7.6' 17 | implementation project(':plugin-jdbc') 18 | api 'org.bouncycastle:bcprov-jdk18on:1.80' 19 | api 'org.bouncycastle:bcpkix-jdk18on:1.80' 20 | api 'name.neuhalfen.projects.crypto.bouncycastle.openpgp:bouncy-gpg:2.3.0' 21 | 22 | testImplementation project(':plugin-jdbc').sourceSets.test.output 23 | } 24 | -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/main/java/io/kestra/plugin/jdbc/postgresql/PostgresConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.postgresql; 2 | 3 | import io.kestra.core.models.property.Property; 4 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 5 | import io.swagger.v3.oas.annotations.media.Schema; 6 | 7 | public interface PostgresConnectionInterface extends JdbcConnectionInterface { 8 | @Schema( 9 | title = "Is the connection SSL?" 10 | ) 11 | Property getSsl(); 12 | 13 | @Schema( 14 | title = "The SSL mode." 15 | ) 16 | Property getSslMode(); 17 | 18 | @Schema( 19 | title = "The SSL root cert.", 20 | description = "Must be a PEM encoded certificate" 21 | ) 22 | Property getSslRootCert(); 23 | 24 | @Schema( 25 | title = "The SSL cert.", 26 | description = "Must be a PEM encoded certificate" 27 | ) 28 | Property getSslCert(); 29 | 30 | @Schema( 31 | title = "The SSL key.", 32 | description = "Must be a PEM encoded key" 33 | ) 34 | Property getSslKey(); 35 | 36 | @Schema( 37 | title = "The SSL key password." 38 | ) 39 | Property getSslKeyPassword(); 40 | 41 | enum SslMode { 42 | DISABLE, 43 | ALLOW, 44 | PREFER, 45 | REQUIRE, 46 | VERIFY_CA, 47 | VERIFY_FULL 48 | } 49 | 50 | @Override 51 | default String getScheme() { 52 | return "jdbc:postgresql"; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/main/java/io/kestra/plugin/jdbc/postgresql/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the PostgreSQL database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.postgresql; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/test/java/io/kestra/plugin/jdbc/postgresql/PgsqlDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.postgresql; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class PgsqlDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return org.postgresql.Driver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/test/java/io/kestra/plugin/jdbc/postgresql/PgsqlTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.postgresql; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.junit.jupiter.api.Disabled; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.net.URISyntaxException; 10 | import java.sql.SQLException; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.is; 16 | 17 | @KestraTest 18 | @Disabled("Disable for now as refactory may be done to split SSL test") 19 | class PgsqlTriggerTest extends AbstractJdbcTriggerTest { 20 | 21 | @Test 22 | void run() throws Exception { 23 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","pgsql-listen"); 24 | 25 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 26 | assertThat(rows.size(), is(1)); 27 | } 28 | 29 | @Override 30 | protected String getUrl() { 31 | return "jdbc:postgresql://127.0.0.1:56982/"; 32 | } 33 | 34 | @Override 35 | protected String getUsername() { 36 | return "postgres"; 37 | } 38 | 39 | @Override 40 | protected String getPassword() { 41 | return "pg_passwd"; 42 | } 43 | 44 | @Override 45 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 46 | executeSqlScript("scripts/postgres.sql"); 47 | } 48 | } -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/test/java/io/kestra/plugin/jdbc/postgresql/TestUtils.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.postgresql; 2 | 3 | import com.google.common.io.CharStreams; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.net.URISyntaxException; 10 | import java.util.Objects; 11 | 12 | public abstract class TestUtils { 13 | public static File resourceToFile(String file) { 14 | try { 15 | return new File(Objects.requireNonNull(TestUtils.class.getClassLoader() 16 | .getResource(file)) 17 | .toURI()); 18 | } catch (URISyntaxException e) { 19 | throw new RuntimeException(e); 20 | } 21 | } 22 | 23 | public static String url() { 24 | return "jdbc:postgresql://127.0.0.1:56982/"; 25 | } 26 | 27 | public static String username() { 28 | return "postgres"; 29 | } 30 | 31 | public static String password() { 32 | return "pg_passwd"; 33 | } 34 | 35 | public static boolean ssl() { 36 | return true; 37 | } 38 | 39 | public static PostgresConnectionInterface.SslMode sslMode() { 40 | return PostgresConnectionInterface.SslMode.REQUIRE; 41 | } 42 | 43 | public static String content(String file) { 44 | try { 45 | return CharStreams.toString(new InputStreamReader(new FileInputStream(resourceToFile(file)))); 46 | } catch (IOException e) { 47 | throw new RuntimeException(e); 48 | } 49 | } 50 | 51 | public static String cert() { 52 | return content("ssl/client.crt"); 53 | } 54 | 55 | public static String key() { 56 | return content("ssl/client.key"); 57 | } 58 | 59 | public static String keyNoPass() { 60 | return content("ssl/client-no-pass.key"); 61 | } 62 | 63 | public static String keyPass() { 64 | return "p4ssphrase"; 65 | } 66 | 67 | public static String ca() { 68 | return content("ssl/ca.crt"); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/test/resources/flows/pgsql-listen.yml: -------------------------------------------------------------------------------- 1 | id: pgsql-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.postgresql.Trigger 7 | sql: SELECT * FROM pgsql_types 8 | url: jdbc:postgresql://127.0.0.1:56982/ 9 | username: postgres 10 | password: pg_passwd 11 | fetchType: FETCH 12 | interval: PT10S 13 | 14 | tasks: 15 | - id: end 16 | type: io.kestra.plugin.core.debug.Return 17 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/test/resources/flows/update_postgres.yaml: -------------------------------------------------------------------------------- 1 | id: update_postgres 2 | namespace: io.kestra.jdbc.postgres 3 | 4 | inputs: 5 | - id: sslRootCert 6 | type: STRING 7 | - id: sslCert 8 | type: STRING 9 | - id: sslKey 10 | type: STRING 11 | 12 | tasks: 13 | - id: update 14 | type: io.kestra.plugin.jdbc.postgresql.Query 15 | url: jdbc:postgresql://127.0.0.1:56982/ 16 | username: postgres 17 | password: pg_passwd 18 | sslMode: VERIFY_CA 19 | sslRootCert: '{{ inputs.sslRootCert }}' 20 | sslCert: '{{ inputs.sslCert }}' 21 | sslKey: '{{ inputs.sslKey }}' 22 | sql: select concert_id, available, a, b, c, d, play_time, library_record, floatn_test, double_test, real_test, numeric_test, date_type, time_type, timez_type, timestamp_type, timestampz_type, interval_type, pay_by_quarter, schedule, json_type, blob_type, hstore_type from pgsql_types 23 | fetchType: FETCH 24 | - id: use-fetched-data 25 | type: io.kestra.plugin.jdbc.postgresql.Query 26 | url: jdbc:postgresql://127.0.0.1:56982/ 27 | username: postgres 28 | password: pg_passwd 29 | sslMode: VERIFY_CA 30 | sslRootCert: '{{ inputs.sslRootCert }}' 31 | sslCert: '{{ inputs.sslCert }}' 32 | sslKey: '{{ inputs.sslKey }}' 33 | sql: "{% for row in outputs.update.rows %} INSERT INTO pl_store_distribute (year_month,store_code, update_date) values ({{row.play_time}}, {{row.concert_id}}, TO_TIMESTAMP('{{row.timestamp_type}}', 'YYYY-MM-DDTHH:MI:SS.US') ); {% endfor %}" 34 | -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/test/resources/scripts/postgres_insert.sql: -------------------------------------------------------------------------------- 1 | 2 | DROP TABLE IF EXISTS pgsql_types; 3 | DROP TABLE IF EXISTS pgsql_nosql; 4 | DROP TABLE IF EXISTS namedInsert; 5 | 6 | CREATE TABLE pgsql_types ( 7 | concert_id serial NOT NULL, 8 | available boolean not null, 9 | a CHAR(4) not null, 10 | b VARCHAR(30) not null, 11 | c TEXT not null, 12 | d VARCHAR(10), 13 | play_time smallint not null, 14 | library_record BIGINT not null, 15 | -- money_type money not null, 16 | floatn_test float8 not null, 17 | double_test double precision not null, 18 | real_test real not null, 19 | numeric_test numeric not null, 20 | date_type DATE not null, 21 | time_type TIME not null, 22 | timez_type TIME WITH TIME ZONE not null, 23 | timestamp_type TIMESTAMP not null, 24 | timestampz_type TIMESTAMP WITH TIME ZONE not null, 25 | interval_type INTERVAL not null, 26 | pay_by_quarter integer[] not null, 27 | schedule text[][] not null, 28 | json_type JSON not null, 29 | jsonb_type JSONB not null, 30 | blob_type bytea not null, 31 | tsvector_col TSVECTOR not null 32 | ); 33 | 34 | 35 | CREATE TABLE pgsql_nosql ( 36 | concert_id serial NOT NULL, 37 | available boolean not null, 38 | a CHAR(4) not null, 39 | b VARCHAR(30) not null, 40 | c TEXT not null, 41 | d VARCHAR(10), 42 | play_time smallint not null, 43 | library_record BIGINT not null, 44 | -- money_type money not null, 45 | floatn_test float8 not null, 46 | double_test double precision not null, 47 | real_test real not null, 48 | numeric_test numeric not null, 49 | date_type DATE not null, 50 | time_type TIME not null, 51 | timez_type TIME WITH TIME ZONE not null, 52 | timestamp_type TIMESTAMP not null, 53 | timestampz_type TIMESTAMP WITH TIME ZONE not null, 54 | interval_type INTERVAL not null, 55 | pay_by_quarter integer[] not null, 56 | schedule text[][] not null, 57 | json_type JSON not null, 58 | blob_type bytea not null 59 | ); 60 | 61 | 62 | CREATE TABLE namedInsert ( 63 | id integer, 64 | name VARCHAR, 65 | address VARCHAR 66 | ); 67 | -------------------------------------------------------------------------------- /plugin-jdbc-postgres/src/test/resources/scripts/postgres_queries.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS employee; 2 | 3 | CREATE TABLE employee ( 4 | employee_id SERIAL, 5 | first_name VARCHAR(30), 6 | last_name VARCHAR(30), 7 | age SMALLINT, 8 | PRIMARY KEY (employee_id) 9 | ); 10 | 11 | INSERT INTO employee (first_name, last_name, age) 12 | VALUES 13 | ( 'John', 'Doe', 45), 14 | ( 'Bryan', 'Grant', 33), 15 | ( 'Jude', 'Philips', 25), 16 | ( 'Michael', 'Page', 62); 17 | 18 | DROP TABLE IF EXISTS laptop; 19 | 20 | CREATE TABLE laptop 21 | ( 22 | laptop_id SERIAL, 23 | brand VARCHAR(30), 24 | model VARCHAR(30), 25 | cpu_frequency REAL, 26 | PRIMARY KEY (laptop_id) 27 | ); 28 | INSERT INTO laptop (brand, model, cpu_frequency) 29 | VALUES 30 | ('Apple', 'MacBookPro M1 13', 2.2), 31 | ('Apple', 'MacBookPro M3 16', 1.5), 32 | ('LG', 'Gram', 1.95), 33 | ('Lenovo', 'ThinkPad', 1.05); 34 | 35 | 36 | /* Table for testing transactionnal queries */ 37 | DROP TABLE IF EXISTS test_transaction; 38 | CREATE TABLE test_transaction 39 | ( 40 | id SERIAL, 41 | name VARCHAR(30) NOT NULL, 42 | PRIMARY KEY (id) 43 | ); -------------------------------------------------------------------------------- /plugin-jdbc-redshift/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Connect to Redshift databases using Kestra\'s JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Amazon Redshift", 8 | "X-Kestra-Group": project.group + ".jdbc.redshift", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | jdbcDriver 'com.amazon.redshift:redshift-jdbc42:2.1.0.33' 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/main/java/io/kestra/plugin/jdbc/redshift/RedshiftConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.redshift; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface RedshiftConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:redshift"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/main/java/io/kestra/plugin/jdbc/redshift/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Amazon Redshift database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.redshift; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/main/resources/icons/io.kestra.plugin.jdbc.redshift.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/main/resources/icons/plugin-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/test/java/io/kestra/plugin/jdbc/redshift/RedshiftTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.redshift; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.micronaut.context.annotation.Value; 5 | import io.kestra.core.junit.annotations.KestraTest; 6 | import org.junit.jupiter.api.Disabled; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.io.FileNotFoundException; 10 | import java.net.URISyntaxException; 11 | import java.sql.SQLException; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.is; 17 | 18 | @KestraTest 19 | @Disabled("no server for unit test") 20 | class RedshiftTriggerTest extends AbstractJdbcTriggerTest { 21 | @Value("${redshift.url}") 22 | protected String url; 23 | 24 | 25 | @Value("${redshift.user}") 26 | protected String user; 27 | 28 | @Value("${redshift.password}") 29 | protected String password; 30 | @Test 31 | void run() throws Exception { 32 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","redshift-listen"); 33 | 34 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 35 | assertThat(rows.size(), is(1)); 36 | } 37 | 38 | @Override 39 | protected String getUrl() { 40 | return url; 41 | } 42 | 43 | @Override 44 | protected String getUsername() { 45 | return user; 46 | } 47 | 48 | @Override 49 | protected String getPassword() { 50 | return password; 51 | } 52 | 53 | @Override 54 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 55 | executeSqlScript("scripts/redshift.sql"); 56 | } 57 | } -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/test/resources/flows/redshift-listen.yml: -------------------------------------------------------------------------------- 1 | # Not used as we cannot run redshift locally 2 | id: redshift-listen 3 | namespace: io.kestra.tests 4 | 5 | triggers: 6 | - id: watch 7 | type: io.kestra.plugin.jdbc.redshift.Trigger 8 | sql: SELECT * FROM pgsql_types 9 | url: ??? 10 | username: ??? 11 | password: ??? 12 | fetchType: FETCH 13 | interval: PT10S 14 | 15 | tasks: 16 | - id: end 17 | type: io.kestra.plugin.core.debug.Return 18 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/test/resources/scripts/redshift.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS pgsql_types; 2 | 3 | CREATE TABLE pgsql_types ( 4 | available boolean not null, 5 | a CHAR(4) not null, 6 | b VARCHAR(30) not null, 7 | c TEXT not null, 8 | d VARCHAR(10), 9 | play_time smallint not null, 10 | library_record BIGINT not null, 11 | -- money_type money not null, 12 | floatn_test float8 not null, 13 | double_test double precision not null, 14 | real_test real not null, 15 | numeric_test numeric not null, 16 | date_type DATE not null, 17 | time_type TIME not null, 18 | timez_type TIME WITH TIME ZONE not null, 19 | timestamp_type TIMESTAMP not null, 20 | timestampz_type TIMESTAMP WITH TIME ZONE not null, 21 | pay_by_quarter super encode zstd not null, 22 | schedule super encode zstd not null/*, 23 | hllsketch_type hllsketch not null*/ 24 | ); 25 | 26 | 27 | -- Insert 28 | INSERT INTO pgsql_types 29 | ( 30 | available, 31 | a, 32 | b, 33 | c, 34 | d, 35 | play_time, 36 | library_record, 37 | -- money_type, 38 | floatn_test, 39 | double_test, 40 | real_test, 41 | numeric_test, 42 | date_type, 43 | time_type, 44 | timez_type, 45 | timestamp_type, 46 | timestampz_type, 47 | pay_by_quarter, 48 | schedule/*, 49 | hllsketch_type*/ 50 | ) 51 | VALUES 52 | ( 53 | true, 54 | 'four', 55 | 'This is a varchar', 56 | 'This is a text column data', 57 | NULL, 58 | 32767, 59 | 9223372036854775807, 60 | -- 999999.999, 61 | 9223372036854776000, 62 | 9223372036854776000, 63 | 9223372036854776000, 64 | 2147483645.1234, 65 | '2030-12-25', 66 | '04:05:30', 67 | '04:05:06 PST', 68 | '2004-10-19 10:23:54.999999', 69 | '2004-10-19 10:23:54.250+04', 70 | json_parse('[100,200,300]'), 71 | json_parse('[{"type": "meeting", "name": "lunch"},{"type": "training", "name": "presentation"}]')/*, 72 | '{"logm":15,"sparse":{"indices":[4878,9559,14523],"values":[1,2,1]}}'*/ 73 | ); 74 | 75 | -------------------------------------------------------------------------------- /plugin-jdbc-redshift/src/test/resources/scripts/redshift_queries.sql: -------------------------------------------------------------------------------- 1 | -- Create table employee 2 | DROP TABLE IF EXISTS employee; 3 | CREATE TABLE employee ( 4 | firstName VARCHAR(100), 5 | lastName VARCHAR(100), 6 | age INTEGER 7 | ); 8 | 9 | INSERT INTO employee(firstName, lastName, age) VALUES ('John', 'Doe', 45); 10 | INSERT INTO employee(firstName, lastName, age) VALUES ('Bryan', 'Grant', 33); 11 | INSERT INTO employee(firstName, lastName, age) VALUES ('Jude', 'Philips', 25); 12 | INSERT INTO employee(firstName, lastName, age) VALUES ('Michael', 'Page', 62); 13 | 14 | 15 | -- Create table laptop 16 | DROP TABLE IF EXISTS laptop; 17 | CREATE TABLE laptop 18 | ( 19 | brand VARCHAR(100), 20 | model VARCHAR(100), 21 | cpu_frequency DECIMAL 22 | ); 23 | 24 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M1 13', 2.2); 25 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M3 16', 1.5); 26 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('LG', 'Gram', 1.95); 27 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Lenovo', 'ThinkPad', 1.05); 28 | 29 | -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Leverage Snowflake data warehouse using Kestra\'s JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Snowflake", 8 | "X-Kestra-Group": project.group + ".jdbc.snowflake", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation("net.snowflake:snowflake-jdbc:3.24.2") 17 | implementation project(':plugin-jdbc') 18 | implementation("org.bouncycastle:bcpkix-jdk18on:1.80") 19 | 20 | compileOnly group: "io.kestra", name: "script", version: kestraVersion 21 | 22 | testImplementation group: "io.kestra", name: "script", version: kestraVersion 23 | testImplementation project(':plugin-jdbc').sourceSets.test.output 24 | } 25 | -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/src/main/java/io/kestra/plugin/jdbc/snowflake/AbstractSnowflakeConnection.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.snowflake; 2 | 3 | import io.kestra.core.models.annotations.PluginProperty; 4 | import io.kestra.core.models.property.Property; 5 | import io.kestra.core.models.tasks.Task; 6 | import io.kestra.core.runners.RunContext; 7 | import lombok.EqualsAndHashCode; 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | import lombok.ToString; 11 | import lombok.experimental.SuperBuilder; 12 | 13 | import java.sql.DriverManager; 14 | import java.sql.SQLException; 15 | import java.util.Properties; 16 | 17 | @SuperBuilder 18 | @ToString 19 | @EqualsAndHashCode 20 | @Getter 21 | @NoArgsConstructor 22 | public abstract class AbstractSnowflakeConnection extends Task implements SnowflakeInterface { 23 | @PluginProperty(group = "connection") 24 | private Property url; 25 | 26 | @PluginProperty(group = "connection") 27 | private Property username; 28 | 29 | @PluginProperty(group = "connection") 30 | private Property password; 31 | 32 | @PluginProperty(group = "connection") 33 | private Property privateKey; 34 | 35 | @PluginProperty(group = "connection") 36 | private Property privateKeyPassword; 37 | 38 | @Override 39 | public void registerDriver() throws SQLException { 40 | DriverManager.registerDriver(new net.snowflake.client.jdbc.SnowflakeDriver()); 41 | } 42 | 43 | @Override 44 | public Properties connectionProperties(RunContext runContext) throws Exception { 45 | Properties properties = SnowflakeInterface.super.connectionProperties(runContext); 46 | 47 | this.renderProperties(runContext, properties); 48 | 49 | return properties; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/src/main/java/io/kestra/plugin/jdbc/snowflake/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Snowflake database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.snowflake; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/src/test/java/io/kestra/plugin/jdbc/snowflake/SnowflakeCLITest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.snowflake; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.core.models.property.Property; 5 | import io.kestra.core.runners.RunContext; 6 | import io.kestra.core.runners.RunContextFactory; 7 | import io.kestra.core.utils.IdUtils; 8 | import io.kestra.core.utils.TestsUtils; 9 | import io.kestra.plugin.scripts.exec.scripts.models.ScriptOutput; 10 | import jakarta.inject.Inject; 11 | import org.junit.jupiter.api.Disabled; 12 | import org.junit.jupiter.api.Test; 13 | 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | import static org.hamcrest.MatcherAssert.assertThat; 18 | import static org.hamcrest.Matchers.is; 19 | 20 | @KestraTest 21 | @Disabled("Create a Snowflake account for unit testing") 22 | public class SnowflakeCLITest { 23 | 24 | @Inject 25 | private RunContextFactory runContextFactory; 26 | 27 | protected String account = ""; 28 | protected String username = ""; 29 | protected String password = ""; 30 | 31 | @Test 32 | void run() throws Exception { 33 | 34 | var snowflakeCLI = SnowflakeCLI.builder() 35 | .id(IdUtils.create()) 36 | .type(SnowflakeCLI.class.getName()) 37 | .account(Property.of(account)) 38 | .username(Property.of(username)) 39 | .password(Property.of(password)) 40 | .commands( 41 | Property.of(List.of("snow connection test"))) 42 | .build(); 43 | 44 | RunContext runContext = TestsUtils.mockRunContext(runContextFactory, snowflakeCLI, Map.of()); 45 | 46 | ScriptOutput output = snowflakeCLI.run(runContext); 47 | 48 | assertThat(output.getExitCode(), is(0)); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/src/test/java/io/kestra/plugin/jdbc/snowflake/SnowflakeDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.snowflake; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class SnowflakeDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return net.snowflake.client.jdbc.SnowflakeDriver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/src/test/resources/flows/snowflake-listen.yml: -------------------------------------------------------------------------------- 1 | # Not used as we cannot run snowflake locally 2 | id: snowflake-listen 3 | namespace: io.kestra.tests 4 | 5 | triggers: 6 | - id: watch 7 | type: io.kestra.plugin.jdbc.snowflake.Trigger 8 | sql: SELECT * FROM snowflake_types 9 | wharehouse: COMPUTE_WH 10 | database: UNITTEST 11 | schema: public 12 | url: ??? 13 | username: ??? 14 | password: ??? 15 | fetchType: FETCH 16 | interval: PT10S 17 | 18 | tasks: 19 | - id: end 20 | type: io.kestra.plugin.core.debug.Return 21 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/src/test/resources/scripts/snowflake.sql: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE TABLE snowflake_types ( 2 | nu text NULL, 3 | n number, 4 | num10 number(10,1), 5 | dec decimal(20,2), 6 | numeric numeric(30,3), 7 | int int, 8 | integer integer, 9 | f float, 10 | dp double precision, 11 | r real, 12 | v50 varchar(50), 13 | c char, 14 | c10 char(10), 15 | s string, 16 | s20 string(20), 17 | t text, 18 | t30 text(30), 19 | b boolean, 20 | d date, 21 | ti time, 22 | ts timestamp, 23 | ts_tz timestamp_tz, 24 | ts_ntz timestamp_ntz, 25 | ts_ltz timestamp_ltz, 26 | v variant, 27 | o object, 28 | a array, 29 | g geography 30 | ); 31 | 32 | INSERT INTO snowflake_types 33 | ( 34 | nu, 35 | n, 36 | num10, 37 | dec, 38 | numeric, 39 | int, 40 | integer, 41 | f, 42 | dp, 43 | r, 44 | v50, 45 | c, 46 | c10, 47 | s, 48 | s20, 49 | t, 50 | t30, 51 | b, 52 | d, 53 | ti, 54 | ts, 55 | ts_tz, 56 | ts_ntz, 57 | ts_ltz, 58 | v, 59 | o, 60 | a, 61 | g 62 | ) 63 | SELECT 64 | NULL, 65 | 2147483645.1234, 66 | 123456.1, 67 | 2147483645.1234, 68 | 2147483645.1234, 69 | 2147483645, 70 | 2147483645, 71 | 2147483645.1234, 72 | 2147483645.1234, 73 | 2147483645.1234, 74 | 'aa', 75 | 'b', 76 | 'cc', 77 | 'dd', 78 | 'ee', 79 | 'ff', 80 | 'gg', 81 | TRUE, 82 | date '2011-10-29', 83 | time '10:03:56', 84 | timestamp '2009-09-15 10:59:43', 85 | '2017-01-01 12:00:00'::timestamp_tz, 86 | '2014-01-02 16:00:00 +00:00', 87 | '2014-01-02 16:00:00 +08:00', 88 | to_variant(parse_json('{"key3": "value3", "key4": "value4"}')), 89 | object_construct( 90 | 'name', 'Jones'::variant, 91 | 'age', 42::variant 92 | ), 93 | array_construct(12, 'twelve', null), 94 | 'POINT(-122.35 37.55)' -- 'LINESTRING(-124.20 42.00, -120.01 41.99)' 95 | -------------------------------------------------------------------------------- /plugin-jdbc-snowflake/src/test/resources/scripts/snowflake_queries.sql: -------------------------------------------------------------------------------- 1 | -- Create table employee 2 | USE KESTRA; 3 | CREATE OR REPLACE TABLE employee ( 4 | firstName VARCHAR(100), 5 | lastName VARCHAR(100), 6 | age INTEGER 7 | ); 8 | 9 | INSERT INTO employee(firstName, lastName, age) VALUES ('John', 'Doe', 45); 10 | INSERT INTO employee(firstName, lastName, age) VALUES ('Bryan', 'Grant', 33); 11 | INSERT INTO employee(firstName, lastName, age) VALUES ('Jude', 'Philips', 25); 12 | INSERT INTO employee(firstName, lastName, age) VALUES ('Michael', 'Page', 62); 13 | 14 | 15 | -- Create table laptop 16 | CREATE OR REPLACE TABLE laptop 17 | ( 18 | brand VARCHAR(100), 19 | model VARCHAR(100), 20 | cpu_frequency DOUBLE PRECISION 21 | ); 22 | 23 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M1 13', 2.2); 24 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M3 16', 1.5); 25 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('LG', 'Gram', 1.95); 26 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Lenovo', 'ThinkPad', 1.05); 27 | 28 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Interact with SQLite databases using Kestra\'s JDBC plugin integration.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "SQLite", 8 | "X-Kestra-Group": project.group + ".jdbc.sqlite", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | jdbcDriver 'org.xerial:sqlite-jdbc:3.50.1.0' 17 | implementation project(':plugin-jdbc') 18 | api 'org.bouncycastle:bcprov-jdk18on:1.80' 19 | api 'org.bouncycastle:bcpkix-jdk18on:1.80' 20 | api 'name.neuhalfen.projects.crypto.bouncycastle.openpgp:bouncy-gpg:2.3.0' 21 | 22 | testImplementation project(':plugin-jdbc').sourceSets.test.output 23 | } 24 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/main/java/io/kestra/plugin/jdbc/sqlite/SqliteCellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sqlite; 2 | 3 | import io.kestra.plugin.jdbc.AbstractCellConverter; 4 | 5 | import java.sql.Connection; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.time.LocalDate; 9 | import java.time.LocalTime; 10 | import java.time.ZoneId; 11 | 12 | public class SqliteCellConverter extends AbstractCellConverter { 13 | 14 | public SqliteCellConverter(ZoneId zoneId) { 15 | super(zoneId); 16 | } 17 | 18 | @Override 19 | public Object convertCell(int columnIndex, ResultSet resultSet, Connection connection) throws SQLException { 20 | Object data = resultSet.getObject(columnIndex); 21 | 22 | if (data == null) { 23 | return null; 24 | } 25 | 26 | String columnTypeName = resultSet.getMetaData().getColumnTypeName(columnIndex); 27 | 28 | return switch (columnTypeName.toLowerCase()) { 29 | case "date" -> LocalDate.parse(resultSet.getString(columnIndex)); 30 | case "datetime", "timestamp" -> resultSet.getTimestamp(columnIndex).toInstant(); 31 | case "time" -> LocalTime.parse(resultSet.getString(columnIndex)); 32 | default -> super.convert(columnIndex, resultSet); 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/main/java/io/kestra/plugin/jdbc/sqlite/SqliteQueryInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sqlite; 2 | 3 | import io.kestra.core.models.annotations.PluginProperty; 4 | import io.kestra.core.models.property.Property; 5 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 6 | import io.swagger.v3.oas.annotations.media.Schema; 7 | 8 | import java.sql.DriverManager; 9 | import java.sql.SQLException; 10 | 11 | public interface SqliteQueryInterface extends JdbcConnectionInterface { 12 | @PluginProperty(group = "connection") 13 | @Schema( 14 | title = "Add sqlite file.", 15 | description = "The file must be from Kestra's internal storage" 16 | ) 17 | Property getSqliteFile(); 18 | 19 | @Schema( 20 | title = "Output the database file.", 21 | description = "This property lets you define if you want to output the provided `sqliteFile` database file for further processing." 22 | ) 23 | Property getOutputDbFile(); 24 | 25 | 26 | default void registerDriver() throws SQLException { 27 | DriverManager.registerDriver(new org.sqlite.JDBC()); 28 | } 29 | 30 | @Override 31 | default String getScheme() { 32 | return "jdbc:sqlite"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/main/java/io/kestra/plugin/jdbc/sqlite/SqliteQueryUtils.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sqlite; 2 | 3 | import io.kestra.core.models.tasks.runners.PluginUtilsService; 4 | import io.kestra.core.runners.RunContext; 5 | import io.micronaut.http.uri.UriBuilder; 6 | 7 | import java.net.URI; 8 | import java.nio.file.Path; 9 | import java.util.Map; 10 | import java.util.Properties; 11 | 12 | public class SqliteQueryUtils { 13 | protected static Properties buildSqliteProperties(Properties properties, RunContext runContext) { 14 | URI url = URI.create((String) properties.get("jdbc.url")); 15 | 16 | // get file name from url scheme parts 17 | String filename = url.getSchemeSpecificPart().split(":")[1]; 18 | 19 | Path path = runContext.workingDir().resolve(Path.of(filename)); 20 | if (path.toFile().exists()) { 21 | url = URI.create(path.toString()); 22 | UriBuilder builder = UriBuilder.of(url); 23 | builder.scheme("jdbc:sqlite"); 24 | properties.put("jdbc.url", builder.build().toString()); 25 | } 26 | 27 | return properties; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/main/java/io/kestra/plugin/jdbc/sqlite/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for interacting with SQLite databases.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.sqlite; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/main/resources/icons/io.kestra.plugin.jdbc.sqlite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/main/resources/icons/plugin-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/test/java/io/kestra/plugin/jdbc/sqlite/SqliteDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sqlite; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | class SqliteDriverTest extends AbstractJdbcDriverTest { 10 | 11 | @Override 12 | protected Class getDriverClass() { 13 | return org.sqlite.JDBC.class; 14 | } 15 | } -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/test/java/io/kestra/plugin/jdbc/sqlite/SqliteTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sqlite; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.junit.jupiter.api.Disabled; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.net.URISyntaxException; 10 | import java.sql.SQLException; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.is; 16 | 17 | @KestraTest 18 | class SqliteTriggerTest extends AbstractJdbcTriggerTest { 19 | 20 | @Test 21 | void run() throws Exception { 22 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","sqlite-listen"); 23 | 24 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 25 | assertThat(rows.size(), is(1)); 26 | } 27 | 28 | @Override 29 | protected String getUrl() { 30 | return TestUtils.url(); 31 | } 32 | 33 | @Override 34 | protected String getUsername() { 35 | return TestUtils.username(); 36 | } 37 | 38 | @Override 39 | protected String getPassword() { 40 | return TestUtils.password(); 41 | } 42 | 43 | @Override 44 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 45 | executeSqlScript("scripts/sqlite.sql"); 46 | } 47 | } -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/test/java/io/kestra/plugin/jdbc/sqlite/TestUtils.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sqlite; 2 | 3 | public abstract class TestUtils { 4 | 5 | public static String url() { 6 | return "jdbc:sqlite:temp"; 7 | } 8 | 9 | public static String username() { 10 | return ""; 11 | } 12 | 13 | public static String password() { 14 | return ""; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/test/resources/db/Chinook_Sqlite.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kestra-io/plugin-jdbc/8d9476dee87f40d42dd46acb99ad4ee2e6f53ce3/plugin-jdbc-sqlite/src/test/resources/db/Chinook_Sqlite.sqlite -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/test/resources/flows/sqlite-listen.yml: -------------------------------------------------------------------------------- 1 | id: sqlite-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.sqlite.Trigger 7 | sql: SELECT * FROM lite_types 8 | url: jdbc:sqlite:temp 9 | fetchType: FETCH 10 | interval: PT10S 11 | 12 | tasks: 13 | - id: end 14 | type: io.kestra.plugin.core.debug.Return 15 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/test/resources/scripts/sqlite.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS lite_types; 2 | 3 | -- Create a table with columns resembling the requested data types 4 | CREATE TABLE lite_types ( 5 | id INTEGER PRIMARY KEY, 6 | boolean_column BOOLEAN, 7 | text_column TEXT, 8 | float_column REAL, -- SQLite doesn't have a FLOAT data type, REAL is used for floating-point values 9 | double_column REAL, -- Use REAL for double-precision floating-point values 10 | int_column INTEGER, 11 | date_column DATE, 12 | datetime_column DATETIME, 13 | time_column TIME, 14 | timestamp_column TIMESTAMP, 15 | year_column INTEGER, -- SQLite doesn't have a YEAR data type, use INTEGER 16 | json_column TEXT, -- SQLite doesn't have a native JSON data type 17 | blob_column BLOB, 18 | d TEXT 19 | ); 20 | 21 | -- Insert sample data into the table 22 | INSERT INTO lite_types ( 23 | boolean_column, 24 | text_column, 25 | float_column, 26 | double_column, 27 | int_column, 28 | date_column, 29 | datetime_column, 30 | time_column, 31 | timestamp_column, 32 | year_column, 33 | json_column, 34 | blob_column, 35 | d 36 | ) VALUES ( 37 | 1, 38 | 'Sample Text', 39 | 3.14, 40 | 3.14159265359, 41 | 42, 42 | '2023-10-30', 43 | '2023-10-30 22:59:57.150150', 44 | '14:30:00', 45 | '2023-10-30 14:30:00.000', 46 | 2023, 47 | '{"key": "value"}', 48 | X'0102030405060708', 49 | NULL 50 | ); -------------------------------------------------------------------------------- /plugin-jdbc-sqlite/src/test/resources/scripts/sqlite_queries.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Create table employee 3 | DROP TABLE IF EXISTS employee; 4 | 5 | CREATE TABLE employee ( 6 | employee_id INTEGER PRIMARY KEY, 7 | firstName TEXT, 8 | lastName TEXT, 9 | age INTEGER 10 | ); 11 | 12 | INSERT INTO employee (employee_id, firstName, lastName, age) 13 | VALUES 14 | (1, 'John', 'Doe', 45), 15 | (2, 'Bryan', 'Grant', 33), 16 | (3, 'Jude', 'Philips', 25), 17 | (4, 'Michael', 'Page', 62); 18 | 19 | 20 | -- Create table laptop 21 | DROP TABLE IF EXISTS laptop; 22 | 23 | CREATE TABLE laptop 24 | ( 25 | laptop_id INTEGER PRIMARY KEY, 26 | brand TEXT, 27 | model TEXT, 28 | cpu_frequency REAL 29 | ); 30 | 31 | INSERT INTO laptop (laptop_id, brand, model, cpu_frequency) 32 | VALUES 33 | (1, 'Apple', 'MacBookPro M1 13', 2.2), 34 | (2, 'Apple', 'MacBookPro M3 16', 1.5), 35 | (3, 'LG', 'Gram', 1.95), 36 | (4, 'Lenovo', 'ThinkPad', 1.05); -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Query SQL Server databases with Kestra\'s JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Microsoft SQL Server", 8 | "X-Kestra-Group": project.group + ".jdbc.sqlserver", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | // Library that gives the ability to obtain tokens from Azure AD v2 17 | implementation("com.microsoft.azure:msal4j:1.21.0") 18 | implementation("com.microsoft.sqlserver:mssql-jdbc:12.10.0.jre11") 19 | implementation project(':plugin-jdbc') 20 | 21 | // Connect using Microsoft Entra 22 | // https://learn.microsoft.com/en-us/sql/connect/jdbc/connecting-using-azure-active-directory-authentication?view=sql-server-ver16#connect-using-activedirectorydefault-authentication-mode 23 | api (group: 'com.azure', name: 'azure-identity') { 24 | // exclude libraries already provided by Kestra 25 | exclude group: 'com.fasterxml.jackson.core' 26 | exclude group: 'com.fasterxml.jackson.dataformat', module: 'jackson-dataformat-xml' 27 | exclude group: 'com.fasterxml.jackson.datatype', module: 'jackson-datatype-jdk8' 28 | exclude group: 'com.fasterxml.jackson.datatype', module: 'jackson-datatype-jsr310' 29 | exclude group: 'com.fasterxml.jackson.datatype', module: 'jackson-datatype-guava' 30 | } 31 | 32 | testImplementation project(':plugin-jdbc').sourceSets.test.output 33 | } 34 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/main/java/io/kestra/plugin/jdbc/sqlserver/SqlServerConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sqlserver; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface SqlServerConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:sqlserver"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/main/java/io/kestra/plugin/jdbc/sqlserver/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the SQL Sever database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.sqlserver; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/test/java/io/kestra/plugin/jdbc/sqlserver/SqlServerDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sqlserver; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class SqlServerDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return com.microsoft.sqlserver.jdbc.SQLServerDriver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/test/java/io/kestra/plugin/jdbc/sqlserver/SqlServerTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sqlserver; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.h2.tools.RunScript; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.io.StringReader; 10 | import java.net.URISyntaxException; 11 | import java.sql.SQLException; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.is; 17 | 18 | @KestraTest 19 | class SqlServerTriggerTest extends AbstractJdbcTriggerTest { 20 | 21 | @Test 22 | void run() throws Exception { 23 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","sqlserver-listen"); 24 | 25 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 26 | assertThat(rows.size(), is(1)); 27 | } 28 | 29 | @Override 30 | protected String getUrl() { 31 | return "jdbc:sqlserver://localhost:41433;trustServerCertificate=true"; 32 | } 33 | 34 | @Override 35 | protected String getUsername() { 36 | return "sa"; 37 | } 38 | 39 | @Override 40 | protected String getPassword() { 41 | return "Sqls3rv3r_Pa55word!"; 42 | } 43 | 44 | @Override 45 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 46 | executeSqlScript("scripts/sqlserver.sql"); 47 | } 48 | } -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/test/resources/flows/sqlserver-listen.yml: -------------------------------------------------------------------------------- 1 | id: sqlserver-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.sqlserver.Trigger 7 | sql: SELECT * FROM sqlserver_types 8 | url: jdbc:sqlserver://localhost:41433;trustServerCertificate=true 9 | username: sa 10 | password: Sqls3rv3r_Pa55word! 11 | fetchType: FETCH 12 | interval: PT10S 13 | 14 | tasks: 15 | - id: end 16 | type: io.kestra.plugin.core.debug.Return 17 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/test/resources/scripts/sqlserver.sql: -------------------------------------------------------------------------------- 1 | -- noinspection SqlNoDataSourceInspectionForFile 2 | DROP TABLE IF EXISTS sqlserver_types; 3 | 4 | CREATE TABLE sqlserver_types ( 5 | t_null VARCHAR(2), 6 | t_bigint BIGINT, 7 | t_int INT, 8 | t_smallint SMALLINT, 9 | t_tinyint TINYINT, 10 | t_float FLOAT, 11 | t_real REAL, 12 | t_decimal DECIMAL(5, 2), 13 | t_numeric NUMERIC(10, 5), 14 | t_bit BIT, 15 | t_smallmoney SMALLMONEY, 16 | t_money MONEY, 17 | t_char CHAR(10), 18 | t_varchar VARCHAR(10), 19 | t_nchar NCHAR(10), 20 | t_nvarchar NVARCHAR(10), 21 | t_text TEXT, 22 | t_ntext NTEXT, 23 | t_time TIME, 24 | t_date DATE, 25 | t_smalldatetime SMALLDATETIME, 26 | t_datetime DATETIME, 27 | t_datetime2 DATETIME2, 28 | t_datetimeoffset DATETIMEOFFSET, 29 | ); 30 | 31 | 32 | INSERT INTO sqlserver_types 33 | ( 34 | t_null, 35 | t_bigint, 36 | t_int, 37 | t_smallint, 38 | t_tinyint, 39 | t_float, 40 | t_real, 41 | t_decimal, 42 | t_numeric, 43 | t_bit, 44 | t_smallmoney, 45 | t_money, 46 | t_char, 47 | t_varchar, 48 | t_nchar, 49 | t_nvarchar, 50 | t_text, 51 | t_ntext, 52 | t_time, 53 | t_date, 54 | t_smalldatetime, 55 | t_datetime, 56 | t_datetime2, 57 | t_datetimeoffset 58 | ) 59 | VALUES 60 | ( 61 | NULL, 62 | 9223372036854775807, 63 | 2147483647, 64 | 32767, 65 | 255, 66 | 12345.12345, 67 | 12345.12345, 68 | 123.456, 69 | 12345.12345, 70 | 1, 71 | 3148.2929, 72 | 3148.1234, 73 | 'test', 74 | 'test', 75 | 'test', 76 | 'test', 77 | 'test', 78 | 'test', 79 | '12:35:29.1234567', 80 | '2007-05-08', 81 | '2007-05-08 12:35:00', 82 | '2007-05-08 12:35:29.123', 83 | '2007-05-08 12:35:29.1234567', 84 | '2007-05-08 12:35:29.1234567 +12:15' 85 | ); 86 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/test/resources/scripts/sqlserver_insert.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE sqlserver_types ( 2 | t_bigint BIGINT, 3 | t_int INT, 4 | t_smallint SMALLINT, 5 | t_tinyint TINYINT, 6 | t_float FLOAT, 7 | t_real REAL, 8 | t_decimal DECIMAL(5, 2), 9 | t_numeric NUMERIC(10, 5), 10 | t_bit BIT, 11 | t_smallmoney SMALLMONEY, 12 | t_money MONEY, 13 | t_char CHAR(10), 14 | t_varchar VARCHAR(10), 15 | t_nchar NCHAR(10), 16 | t_nvarchar NVARCHAR(10), 17 | t_text TEXT, 18 | t_ntext NTEXT, 19 | t_time TIME, 20 | t_date DATE, 21 | t_smalldatetime SMALLDATETIME, 22 | t_datetime DATETIME, 23 | t_datetime2 DATETIME2, 24 | t_datetimeoffset DATETIMEOFFSET, 25 | ); 26 | 27 | CREATE TABLE namedInsert ( 28 | t_id INT, 29 | t_name VARCHAR(20), 30 | t_address VARCHAR(20) 31 | ); 32 | 33 | -------------------------------------------------------------------------------- /plugin-jdbc-sqlserver/src/test/resources/scripts/sqlserver_queries.sql: -------------------------------------------------------------------------------- 1 | -- Create table employee 2 | DROP TABLE IF EXISTS employee; 3 | 4 | CREATE TABLE employee ( 5 | firstName VARCHAR(100), 6 | lastName VARCHAR(100), 7 | age INT 8 | ); 9 | 10 | INSERT INTO employee (firstName, lastName, age) 11 | VALUES 12 | ('John', 'Doe', 45), 13 | ('Bryan', 'Grant', 33), 14 | ('Jude', 'Philips', 25), 15 | ('Michael', 'Page', 62); 16 | 17 | 18 | -- Create table laptop 19 | DROP TABLE IF EXISTS laptop; 20 | 21 | CREATE TABLE laptop 22 | ( 23 | brand VARCHAR(100), 24 | model VARCHAR(100), 25 | cpu_frequency REAL 26 | ); 27 | 28 | INSERT INTO laptop (brand, model, cpu_frequency) 29 | VALUES 30 | ('Apple', 'MacBookPro M1 13', 2.2), 31 | ('Apple', 'MacBookPro M3 16', 1.5), 32 | ('LG', 'Gram', 1.95), 33 | ('Lenovo', 'ThinkPad', 1.05); -------------------------------------------------------------------------------- /plugin-jdbc-sybase/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Query Sybase databases using the Kestra JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Sybase", 8 | "X-Kestra-Group": project.group + ".jdbc.sybase", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation 'jdbc.sybase:jconn4:16.0' 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/main/java/io/kestra/plugin/jdbc/sybase/SybaseCellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sybase; 2 | 3 | import io.kestra.plugin.jdbc.AbstractCellConverter; 4 | 5 | import java.sql.Connection; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.time.LocalDateTime; 9 | import java.time.ZoneId; 10 | 11 | public class SybaseCellConverter extends AbstractCellConverter { 12 | public SybaseCellConverter(ZoneId zoneId) { 13 | super(zoneId); 14 | } 15 | 16 | @Override 17 | public Object convertCell(int columnIndex, ResultSet rs, Connection connection) throws SQLException { 18 | Object data = rs.getObject(columnIndex); 19 | 20 | if (data == null) { 21 | return null; 22 | } 23 | 24 | String columnTypeName = rs.getMetaData().getColumnTypeName(columnIndex); 25 | 26 | return switch (columnTypeName.toLowerCase()) { 27 | case "time" -> rs.getTime(columnIndex).toLocalTime(); 28 | case "datetime" -> LocalDateTime.of(rs.getDate(columnIndex).toLocalDate(), rs.getTime(columnIndex).toLocalTime()); 29 | default -> super.convert(columnIndex, rs); 30 | }; 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/main/java/io/kestra/plugin/jdbc/sybase/SybaseConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sybase; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface SybaseConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:sybase"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/main/java/io/kestra/plugin/jdbc/sybase/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Sybase database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.sybase; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/test/java/io/kestra/plugin/jdbc/sybase/SybaseDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sybase; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class SybaseDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return com.sybase.jdbc4.jdbc.SybDriver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/test/java/io/kestra/plugin/jdbc/sybase/SybaseTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.sybase; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 5 | import org.junit.jupiter.api.Disabled; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.net.URISyntaxException; 10 | import java.sql.SQLException; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.is; 16 | 17 | @KestraTest 18 | @Disabled("Lauching Sybase via our docker-compose crash the CI") 19 | class SybaseTriggerTest extends AbstractJdbcTriggerTest { 20 | 21 | @Test 22 | void run() throws Exception { 23 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","sybase-listen"); 24 | 25 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 26 | assertThat(rows.size(), is(1)); 27 | } 28 | 29 | @Override 30 | protected String getUrl() { 31 | return "jdbc:sybase:Tds:127.0.0.1:5000/kestra"; 32 | } 33 | 34 | @Override 35 | protected String getUsername() { 36 | return "sa"; 37 | } 38 | 39 | @Override 40 | protected String getPassword() { 41 | return "myPassword"; 42 | } 43 | 44 | @Override 45 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 46 | executeSqlScript("scripts/sybase.sql"); 47 | } 48 | } -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/test/resources/flows/read_sybase.yaml: -------------------------------------------------------------------------------- 1 | id: read_sybase 2 | namespace: io.kestra.jdbc.sybase 3 | 4 | tasks: 5 | - id: read 6 | type: io.kestra.plugin.jdbc.sybase.Query 7 | url: jdbc:sybase:Tds:127.0.0.1:5000/kestra 8 | username: sa 9 | password: myPassword 10 | sql: select * from syb_types 11 | fetchType: FETCH_ONE 12 | - id: flow-id 13 | type: io.kestra.plugin.core.debug.Return 14 | format: "{{outputs.update.row}}" 15 | -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/test/resources/flows/sybase-listen.yml: -------------------------------------------------------------------------------- 1 | id: sybase-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.sybase.Trigger 7 | sql: SELECT * FROM syb_types 8 | url: jdbc:sybase:Tds:127.0.0.1:5000/kestra 9 | username: sa 10 | password: myPassword 11 | fetchType: FETCH 12 | interval: PT10S 13 | 14 | tasks: 15 | - id: end 16 | type: io.kestra.plugin.core.debug.Return 17 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/test/resources/scripts/sybase.sql: -------------------------------------------------------------------------------- 1 | IF EXISTS(select 1 from sysobjects where name='syb_types' and type='U') 2 | DROP TABLE syb_types; 3 | 4 | CREATE TABLE syb_types( 5 | concert_id INT IDENTITY PRIMARY KEY, 6 | available TINYINT NOT NULL, 7 | a CHAR(4) NOT NULL, 8 | b VARCHAR(30) NOT NULL, 9 | c TEXT NOT NULL, 10 | d VARCHAR(10) NULL, 11 | play_time BIGINT NOT NULL, 12 | library_record BIGINT NOT NULL, 13 | bitn_test BIT NOT NULL, 14 | floatn_test REAL, 15 | double_test FLOAT, 16 | doublen_test FLOAT, 17 | numeric_test DECIMAL(5,2), 18 | salary_decimal DECIMAL(5,2), 19 | date_type DATE NOT NULL, 20 | datetime_type DATETIME NOT NULL, 21 | time_type TIME NOT NULL, 22 | timestamp_type DATETIME NOT NULL, 23 | blob_type IMAGE NOT NULL -- BLOB type is not directly supported in Sybase ASE, using IMAGE as an alternative 24 | ); 25 | 26 | -- Insert 27 | INSERT INTO syb_types 28 | (available, 29 | a, 30 | b, 31 | c, 32 | d, 33 | play_time, 34 | library_record, 35 | bitn_test, 36 | floatn_test, 37 | double_test, 38 | doublen_test, 39 | numeric_test, 40 | salary_decimal, 41 | date_type, 42 | datetime_type, 43 | time_type, 44 | timestamp_type, 45 | blob_type) 46 | VALUES ( 47 | 1, 48 | 'four', 49 | 'This is a varchar', 50 | 'This is a text column data', 51 | NULL, 52 | -9223372036854775808, 53 | 1844674407370955161, 54 | 1, 55 | 9.223372, 56 | 9.223372, 57 | 2147483645.1234, 58 | 5.36, 59 | 999.99, 60 | '2030-12-25', 61 | '2050-12-31 22:59:57.150150', 62 | '04:05:30', 63 | '2004-10-19 10:23:54.999999', 64 | 0x123456 65 | ); -------------------------------------------------------------------------------- /plugin-jdbc-sybase/src/test/resources/scripts/sybase_queries.sql: -------------------------------------------------------------------------------- 1 | IF EXISTS(select 1 from sysobjects where name='employee' and type='U') DROP TABLE employee; 2 | 3 | CREATE TABLE employee ( 4 | employee_id INT IDENTITY PRIMARY KEY, 5 | firstName VARCHAR(30), 6 | lastName VARCHAR(30), 7 | age INT 8 | ); 9 | 10 | INSERT INTO employee (firstName, lastName, age) VALUES ('John', 'Doe', 45); 11 | INSERT INTO employee (firstName, lastName, age) VALUES ('Bryan', 'Grant', 33); 12 | INSERT INTO employee (firstName, lastName, age) VALUES ('Jude', 'Philips', 25); 13 | INSERT INTO employee (firstName, lastName, age) VALUES ('Michael', 'Page', 62); 14 | 15 | IF EXISTS(select 1 from sysobjects where name='laptop' and type='U') DROP TABLE laptop; 16 | 17 | CREATE TABLE laptop 18 | ( 19 | laptop_id INT IDENTITY PRIMARY KEY, 20 | brand VARCHAR(30), 21 | model VARCHAR(30), 22 | cpu_frequency REAL 23 | ); 24 | 25 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M1 13', 2.2); 26 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M3 16', 1.5); 27 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('LG', 'Gram', 1.95); 28 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Lenovo', 'ThinkPad', 1.05); -------------------------------------------------------------------------------- /plugin-jdbc-trino/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Connect to Trino databases using Kestra\'s JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Trino", 8 | "X-Kestra-Group": project.group + ".jdbc.trino", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation("io.trino:trino-jdbc:476") 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-trino/src/main/java/io/kestra/plugin/jdbc/trino/TrinoConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.trino; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface TrinoConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:trino"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-trino/src/main/java/io/kestra/plugin/jdbc/trino/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Trino database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.trino; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-trino/src/test/java/io/kestra/plugin/jdbc/trino/TrinoDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.trino; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | 6 | import java.sql.Driver; 7 | 8 | @KestraTest 9 | public class TrinoDriverTest extends AbstractJdbcDriverTest { 10 | @Override 11 | protected Class getDriverClass() { 12 | return io.trino.jdbc.TrinoDriver.class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc-trino/src/test/java/io/kestra/plugin/jdbc/trino/TrinoTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.trino; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.kestra.core.junit.annotations.KestraTest; 5 | import org.h2.tools.RunScript; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.io.StringReader; 10 | import java.net.URISyntaxException; 11 | import java.sql.SQLException; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.is; 17 | 18 | @KestraTest 19 | class TrinoTriggerTest extends AbstractJdbcTriggerTest { 20 | 21 | @Test 22 | void run() throws Exception { 23 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","trino-listen"); 24 | 25 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 26 | assertThat(rows.size(), is(1)); 27 | } 28 | 29 | @Override 30 | protected String getUrl() { 31 | return "jdbc:trino://localhost:48080/memory/default"; 32 | } 33 | 34 | @Override 35 | protected String getUsername() { 36 | return "fake"; 37 | } 38 | 39 | @Override 40 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 41 | executeSqlScript("scripts/trino.sql"); 42 | } 43 | } -------------------------------------------------------------------------------- /plugin-jdbc-trino/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-trino/src/test/resources/flows/trino-listen.yml: -------------------------------------------------------------------------------- 1 | id: trino-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.trino.Trigger 7 | sql: SELECT * FROM trino_types 8 | url: jdbc:trino://localhost:48080/memory/default 9 | username: fake 10 | fetchType: FETCH 11 | interval: PT10S 12 | 13 | tasks: 14 | - id: end 15 | type: io.kestra.plugin.core.debug.Return 16 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-trino/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-trino/src/test/resources/scripts/trino.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS trino_types; 2 | 3 | CREATE TABLE trino_types ( 4 | t_null VARCHAR(2), 5 | t_boolean BOOLEAN, 6 | t_tinyint TINYINT, 7 | t_smallint SMALLINT, 8 | t_integer INTEGER, 9 | t_bigint BIGINT, 10 | t_real REAL, 11 | t_double DOUBLE, 12 | t_decimal DECIMAL(10, 5), 13 | t_varchar VARCHAR(10), 14 | t_char CHAR(10), 15 | t_varbinary VARBINARY, 16 | t_json JSON, 17 | t_date DATE, 18 | t_time TIME(6), 19 | t_time_tz TIME WITH TIME ZONE, 20 | t_timestamp TIMESTAMP(6), 21 | t_timestamp_tz TIMESTAMP(6) WITH TIME ZONE, 22 | t_interval_year INTERVAL YEAR TO MONTH, 23 | t_interval_day INTERVAL DAY TO SECOND, 24 | -- t_array ARRAY, 25 | -- t_map MAP, 26 | -- t_row ROW, 27 | t_ipaddress IPADDRESS, 28 | t_uuid UUID 29 | ); 30 | 31 | 32 | INSERT INTO trino_types 33 | ( 34 | t_null, 35 | t_boolean, 36 | t_tinyint, 37 | t_smallint, 38 | t_integer, 39 | t_bigint, 40 | t_real, 41 | t_double, 42 | t_decimal, 43 | t_varchar, 44 | t_char, 45 | t_varbinary, 46 | t_json, 47 | t_date, 48 | t_time, 49 | t_time_tz, 50 | t_timestamp, 51 | t_timestamp_tz, 52 | t_interval_year, 53 | t_interval_day, 54 | -- -- t_array, 55 | -- -- t_map, 56 | -- -- t_row, 57 | t_ipaddress, 58 | t_uuid 59 | ) 60 | VALUES 61 | ( 62 | NULL, 63 | TRUE, 64 | 127, 65 | 32767, 66 | 2147483647, 67 | 9223372036854775807, 68 | 12345.12345, 69 | 12345.12345, 70 | 123.456, 71 | 'test', 72 | 'test', 73 | X'65683F', 74 | JSON '{"a": "b"}', 75 | DATE '2001-08-22', 76 | TIME '01:02:03.456', 77 | TIME '01:02:03.456 -08:00', 78 | TIMESTAMP '2020-06-10 15:55:23.383345', 79 | TIMESTAMP '2001-08-22 03:04:05.321 -08:00', 80 | INTERVAL '3' MONTH, 81 | INTERVAL '2' DAY, 82 | -- -- ARRAY[1, 2, 3], 83 | -- -- MAP(ARRAY['foo', 'bar'], ARRAY[1, 2]), 84 | -- -- CAST(ROW(1, 2e0) AS ROW(x BIGINT, y DOUBLE)), 85 | IPADDRESS '10.0.0.1', 86 | UUID '12151fd2-7586-11e9-8f9e-2a86e4085a59' 87 | ); 88 | -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Integrate Vectorwise analytical databases with Kestra\'s JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Actian Vector", 8 | "X-Kestra-Group": project.group + ".jdbc.vectorwise", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | jdbcDriver 'org.talend.libraries:iijdbc:6.0.0' 17 | implementation project(':plugin-jdbc') 18 | testImplementation project(':plugin-jdbc').sourceSets.test.output 19 | } 20 | -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/main/java/io/kestra/plugin/jdbc/vectorwise/VectorwiseCellConverter.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.vectorwise; 2 | 3 | import io.kestra.plugin.jdbc.AbstractCellConverter; 4 | 5 | import java.sql.Connection; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.sql.Timestamp; 9 | import java.time.Instant; 10 | import java.time.LocalTime; 11 | import java.time.ZoneId; 12 | 13 | public class VectorwiseCellConverter extends AbstractCellConverter { 14 | public VectorwiseCellConverter(ZoneId zoneId) { 15 | super(zoneId); 16 | } 17 | 18 | @Override 19 | public Object convertCell(int columnIndex, ResultSet rs, Connection connection) throws SQLException { 20 | Object data = rs.getObject(columnIndex); 21 | 22 | if (data == null) { 23 | return null; 24 | } 25 | 26 | Object columnVal = rs.getObject(columnIndex); 27 | String columnTypeName = rs.getMetaData().getColumnTypeName(columnIndex); 28 | String columnName = rs.getMetaData().getColumnLabel(columnIndex); 29 | 30 | if (columnTypeName.equals("timetz")) { 31 | java.sql.Time col = ((java.sql.Time) columnVal); 32 | return col.toLocalTime().atOffset(zoneId.getRules().getOffset(Instant.now())); 33 | } 34 | 35 | if (columnTypeName.equals("timestamp without time zone")) { 36 | return ((Timestamp) data).toLocalDateTime(); 37 | } 38 | 39 | if (columnTypeName.equals("time with time zone")) { 40 | // FIXME : Since Time uses 01-01-1970 by default, timezone needs to be adjusted 41 | return LocalTime.from(rs.getTimestamp(columnIndex).toInstant().atZone(zoneId)); 42 | } 43 | 44 | if (columnTypeName.equals("timestamp")) { 45 | return rs.getTimestamp(columnIndex).toLocalDateTime(); 46 | } 47 | 48 | if (columnTypeName.equals("timestamp with time zone")) { 49 | return rs.getTimestamp(columnIndex).toInstant().atZone(zoneId); 50 | } 51 | 52 | return super.convert(columnIndex, rs); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/main/java/io/kestra/plugin/jdbc/vectorwise/VetorwiseConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.vectorwise; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface VetorwiseConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:vectorwise"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/main/java/io/kestra/plugin/jdbc/vectorwise/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Vectorwise database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.vectorwise; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/main/resources/icons/io.kestra.plugin.jdbc.vectorwise.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/main/resources/icons/plugin-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/test/java/io/kestra/plugin/jdbc/vectorwise/VectorwiseTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.vectorwise; 2 | 3 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 4 | import io.micronaut.context.annotation.Value; 5 | import io.kestra.core.junit.annotations.KestraTest; 6 | import org.junit.jupiter.api.Disabled; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.io.FileNotFoundException; 10 | import java.net.URISyntaxException; 11 | import java.sql.SQLException; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.is; 17 | 18 | @KestraTest 19 | @Disabled("no server for unit test") 20 | class VectorwiseTriggerTest extends AbstractJdbcTriggerTest { 21 | @Value("jdbc:ingres://url:port/db") 22 | protected String url; 23 | 24 | @Value("user") 25 | protected String user; 26 | 27 | @Value("password") 28 | protected String password; 29 | 30 | @Test 31 | void run() throws Exception { 32 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","vectorwise-listen"); 33 | 34 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 35 | assertThat(rows.size(), is(1)); 36 | } 37 | 38 | @Override 39 | protected String getUrl() { 40 | return this.url; 41 | } 42 | 43 | @Override 44 | protected String getUsername() { 45 | return this.user; 46 | } 47 | 48 | @Override 49 | protected String getPassword() { 50 | return this.password; 51 | } 52 | 53 | @Override 54 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 55 | executeSqlScript("scripts/vectorwise.sql"); 56 | } 57 | } -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/test/resources/flows/vectorwise-listen.yml: -------------------------------------------------------------------------------- 1 | # not used as we cannot run it locally 2 | id: vectorwise-listen 3 | namespace: io.kestra.tests 4 | 5 | triggers: 6 | - id: watch 7 | type: io.kestra.plugin.jdbc.vectorwise.Trigger 8 | sql: SELECT * FROM vectorwise_types 9 | url: ??? 10 | username: ??? 11 | password: ??? 12 | fetchType: FETCH 13 | interval: PT10S 14 | 15 | tasks: 16 | - id: end 17 | type: io.kestra.plugin.core.debug.Return 18 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-vectorwise/src/test/resources/scripts/vectorwise.sql: -------------------------------------------------------------------------------- 1 | select 2 | tinyint(125) as tinyint, 3 | int2(32000) as smallint, 4 | int(2147483640) as integer, 5 | bigint(9007199254740991) as bigint, 6 | decimal(1.554,5,2) as decimal, 7 | float8(1.12365125789541258974561236512578954125897456) as float8, 8 | float4(1.2) as float, 9 | money(100.50) as money, 10 | char('y') as char, 11 | varchar('yoplait') as varchar, 12 | nchar('test',3) as nchar, 13 | nvarchar('autretest',6) as nvarchar, 14 | date('1900-10-04 22:23:00') as datetime, 15 | ansidate('2006-05-16') as ansidate, 16 | ansidate('2006-05-16 22:23:00') as ansidatetime, 17 | TIME_WO_TZ('04:05:30') as timeNoTz, 18 | TIME_WITH_TZ('04:05:30') as timeTZ, 19 | TIME_LOCAL('04:05:30') as timeLocalTz, 20 | TIMESTAMP_WO_TZ('2006-05-16 00:00:00.000') as timestampNoTz, 21 | TIMESTAMP_WITH_TZ('2006-05-16 00:00:00.000') as timestampTZ, 22 | TIMESTAMP_LOCAL('2006-05-16 00:00:00.000') as timestampLocalTZ, 23 | INTERVAL_YTOM('2007-10') as intervalYtoM, 24 | INTERVAL_DTOS(date('2007-05-16') - date('2007-05-12')) as intervalDtoS, 25 | boolean(true) as boolean -------------------------------------------------------------------------------- /plugin-jdbc-vertica/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Manage data in Vertica databases with Kestra\'s JDBC plugin.' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Vertica", 8 | "X-Kestra-Group": project.group + ".jdbc.vertica", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | jdbcDriver 'com.vertica.jdbc:vertica-jdbc:24.4.0-0' 17 | implementation project(':plugin-jdbc') 18 | 19 | testImplementation project(':plugin-jdbc').sourceSets.test.output 20 | } 21 | -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/main/java/io/kestra/plugin/jdbc/vertica/VerticaConnectionInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.vertica; 2 | 3 | import io.kestra.plugin.jdbc.JdbcConnectionInterface; 4 | 5 | public interface VerticaConnectionInterface extends JdbcConnectionInterface { 6 | @Override 7 | default String getScheme() { 8 | return "jdbc:vertica"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/main/java/io/kestra/plugin/jdbc/vertica/package-info.java: -------------------------------------------------------------------------------- 1 | @PluginSubGroup( 2 | description = "This sub-group of plugins contains tasks for accessing the Vetica database.", 3 | categories = PluginSubGroup.PluginCategory.DATABASE 4 | ) 5 | package io.kestra.plugin.jdbc.vertica; 6 | 7 | import io.kestra.core.models.annotations.PluginSubGroup; -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/main/resources/icons/io.kestra.plugin.jdbc.vertica.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 9 | 10 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/main/resources/icons/plugin-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 9 | 10 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/test/java/io/kestra/plugin/jdbc/vertica/VerticaDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.vertica; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcDriverTest; 5 | import org.junit.jupiter.api.Disabled; 6 | 7 | import java.sql.Driver; 8 | 9 | @KestraTest 10 | @Disabled("Issue with EOFException") 11 | public class VerticaDriverTest extends AbstractJdbcDriverTest { 12 | @Override 13 | protected Class getDriverClass() { 14 | return com.vertica.jdbc.Driver.class; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/test/java/io/kestra/plugin/jdbc/vertica/VerticaTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc.vertica; 2 | 3 | import io.kestra.core.junit.annotations.KestraTest; 4 | import io.kestra.plugin.jdbc.AbstractJdbcTriggerTest; 5 | import org.junit.jupiter.api.Disabled; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.net.URISyntaxException; 10 | import java.sql.SQLException; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.is; 16 | 17 | @KestraTest 18 | @Disabled("Issue with EOFException") 19 | class VerticaTriggerTest extends AbstractJdbcTriggerTest { 20 | @Test 21 | void run() throws Exception { 22 | var execution = triggerFlow(this.getClass().getClassLoader(), "flows","vertica-listen"); 23 | 24 | var rows = (List>) execution.getTrigger().getVariables().get("rows"); 25 | assertThat(rows.size(), is(1)); 26 | } 27 | @Override 28 | protected String getUrl() { 29 | return "jdbc:vertica://127.0.0.1:25433/docker"; 30 | } 31 | 32 | @Override 33 | protected String getUsername() { 34 | return "dbadmin"; 35 | } 36 | 37 | @Override 38 | protected String getPassword() { 39 | return "vertica_passwd"; 40 | } 41 | 42 | @Override 43 | protected void initDatabase() throws SQLException, FileNotFoundException, URISyntaxException { 44 | executeSqlScript("scripts/vertica.sql"); 45 | } 46 | } -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/test/resources/flows/vectica-listen.yml: -------------------------------------------------------------------------------- 1 | id: vertica-listen 2 | namespace: io.kestra.tests 3 | 4 | triggers: 5 | - id: watch 6 | type: io.kestra.plugin.jdbc.vertica.Trigger 7 | sql: SELECT * FROM vertica_types 8 | url: jdbc:vertica://127.0.0.1:25433/docker 9 | username: dbadmin 10 | password: vertica_passwd 11 | fetchType: FETCH 12 | interval: PT10S 13 | 14 | tasks: 15 | - id: end 16 | type: io.kestra.plugin.core.debug.Return 17 | format: "{{task.id}} > {{taskrun.startDate}}" -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/test/resources/scripts/vertica_insert.sql: -------------------------------------------------------------------------------- 1 | 2 | DROP TABLE IF EXISTS vertica_types; 3 | DROP TABLE IF EXISTS namedInsert; 4 | CREATE TABLE vertica_types ( 5 | "binary" BINARY, 6 | varbinary VARBINARY, 7 | long_varbinary LONG VARBINARY, 8 | bytea BYTEA, 9 | raw RAW, 10 | "boolean" BOOLEAN, 11 | char CHAR(4), 12 | varchar VARCHAR, 13 | long_varchar LONG VARCHAR, 14 | date DATE, 15 | time TIME, 16 | datetime DATETIME, 17 | smalldatetime SMALLDATETIME, 18 | time_with_timezone TIME WITH TIMEZONE, 19 | timestamp TIMESTAMP, 20 | timestamp_with_timezone TIMESTAMP WITH TIMEZONE, 21 | "interval" INTERVAL, 22 | interval_day_to_second INTERVAL DAY TO SECOND, 23 | interval_year_to_month INTERVAL YEAR TO MONTH, 24 | double_precision DOUBLE PRECISION, 25 | float FLOAT, 26 | float_n FLOAT(8), 27 | float8 FLOAT8, 28 | real REAL, 29 | integer INTEGER, 30 | int INT, 31 | bigint BIGINT, 32 | int8 INT8, 33 | smallint SMALLINT, 34 | tinyint TINYINT, 35 | decimal DECIMAL(14, 4), 36 | numeric NUMERIC(14, 4), 37 | number NUMBER(14, 4), 38 | money MONEY(14, 4) 39 | -- geometry GEOMETRY, 40 | -- geography GEOGRAPHY, 41 | -- uuid UUID 42 | ); 43 | 44 | CREATE TABLE namedInsert ( 45 | id integer, 46 | name VARCHAR, 47 | address VARCHAR 48 | ); 49 | -------------------------------------------------------------------------------- /plugin-jdbc-vertica/src/test/resources/scripts/vertica_queries.sql: -------------------------------------------------------------------------------- 1 | -- Create table employee 2 | DROP TABLE IF EXISTS employee; 3 | 4 | CREATE TABLE employee ( 5 | firstName VARCHAR, 6 | lastName VARCHAR, 7 | age INTEGER 8 | ); 9 | 10 | INSERT INTO employee(firstName, lastName, age) VALUES ('John', 'Doe', 45); 11 | INSERT INTO employee(firstName, lastName, age) VALUES ('Bryan', 'Grant', 33); 12 | INSERT INTO employee(firstName, lastName, age) VALUES ('Jude', 'Philips', 25); 13 | INSERT INTO employee(firstName, lastName, age) VALUES ('Michael', 'Page', 62); 14 | 15 | 16 | -- Create table laptop 17 | DROP TABLE IF EXISTS laptop; 18 | 19 | CREATE TABLE laptop 20 | ( 21 | brand VARCHAR, 22 | model VARCHAR, 23 | cpu_frequency DOUBLE PRECISION 24 | ); 25 | 26 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M1 13', 2.2); 27 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Apple', 'MacBookPro M3 16', 1.5); 28 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('LG', 'Gram', 1.95); 29 | INSERT INTO laptop (brand, model, cpu_frequency) VALUES ('Lenovo', 'ThinkPad', 1.05); -------------------------------------------------------------------------------- /plugin-jdbc/build.gradle: -------------------------------------------------------------------------------- 1 | project.description = 'Abstract JDBC plugin for Kestra' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "X-Kestra-Name": project.name, 7 | "X-Kestra-Title": "Abstract JDBC", 8 | "X-Kestra-Group": project.group + ".jdbc", 9 | "X-Kestra-Description": project.description, 10 | "X-Kestra-Version": project.version 11 | ) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /plugin-jdbc/src/main/java/io/kestra/plugin/jdbc/JdbcQueriesInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc; 2 | 3 | import io.kestra.core.models.property.Property; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | 6 | import java.util.Map; 7 | 8 | public interface JdbcQueriesInterface { 9 | @Schema( 10 | title = "Transaction", 11 | description = "If one query failed, rollback transactions." 12 | ) 13 | Property getTransaction(); 14 | } 15 | -------------------------------------------------------------------------------- /plugin-jdbc/src/main/java/io/kestra/plugin/jdbc/JdbcStatementInterface.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc; 2 | 3 | import io.kestra.core.exceptions.IllegalVariableEvaluationException; 4 | import io.kestra.core.models.annotations.PluginProperty; 5 | import io.kestra.core.models.property.Property; 6 | import io.kestra.core.runners.RunContext; 7 | import io.swagger.v3.oas.annotations.media.Schema; 8 | 9 | import java.time.ZoneId; 10 | import java.util.TimeZone; 11 | 12 | public interface JdbcStatementInterface extends JdbcConnectionInterface { 13 | @Schema( 14 | title = "The time zone id to use for date/time manipulation. Default value is the worker's default time zone id." 15 | ) 16 | @PluginProperty(group = "connection") 17 | Property getTimeZoneId(); 18 | 19 | default ZoneId zoneId(RunContext runContext) throws IllegalVariableEvaluationException { 20 | if (this.getTimeZoneId() != null) { 21 | return ZoneId.of(runContext.render(this.getTimeZoneId()).as(String.class).orElseThrow()); 22 | } 23 | 24 | return TimeZone.getDefault().toZoneId(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /plugin-jdbc/src/test/java/io/kestra/plugin/jdbc/AbstractJdbcDriverTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.sql.Driver; 6 | import java.sql.DriverManager; 7 | import java.util.Collections; 8 | import java.util.List; 9 | 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.*; 12 | 13 | public abstract class AbstractJdbcDriverTest { 14 | protected abstract Class getDriverClass(); 15 | 16 | @Test 17 | public void loadDriver() { 18 | List drivers = Collections.list(DriverManager.getDrivers()); 19 | assertThat(drivers, hasItems(hasProperty("class", is(getDriverClass())))); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /plugin-jdbc/src/test/java/io/kestra/plugin/jdbc/JdbcTriggerTest.java: -------------------------------------------------------------------------------- 1 | package io.kestra.plugin.jdbc; 2 | 3 | import io.kestra.core.models.conditions.ConditionContext; 4 | import io.kestra.core.models.executions.Execution; 5 | import io.kestra.core.models.triggers.TriggerContext; 6 | import io.kestra.core.runners.RunContext; 7 | import io.kestra.core.runners.RunContextFactory; 8 | import io.kestra.core.junit.annotations.KestraTest; 9 | import jakarta.inject.Inject; 10 | import lombok.NoArgsConstructor; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import java.util.Optional; 14 | 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.is; 17 | 18 | @KestraTest 19 | class JdbcTriggerTest { 20 | @Inject 21 | protected RunContextFactory runContextFactory; 22 | 23 | @Test 24 | void noNpeOnNullSizeQueryOutput() throws Exception { 25 | Optional evaluate = new DoNothingTrigger().evaluate( 26 | ConditionContext.builder().runContext( 27 | runContextFactory.of() 28 | ).build(), 29 | new TriggerContext() 30 | ); 31 | 32 | assertThat(evaluate.isEmpty(), is(true)); 33 | } 34 | 35 | @NoArgsConstructor 36 | public static class DoNothingTrigger extends AbstractJdbcTrigger { 37 | @Override 38 | public void registerDriver() {} 39 | 40 | @Override 41 | public String getScheme() { return null; } 42 | 43 | @Override 44 | protected AbstractJdbcQuery.Output runQuery(RunContext runContext) { 45 | return AbstractJdbcQuery.Output.builder().build(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /plugin-jdbc/src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=build/allure-results 2 | -------------------------------------------------------------------------------- /plugin-jdbc/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | kestra: 2 | repository: 3 | type: memory 4 | queue: 5 | type: memory 6 | storage: 7 | type: local 8 | local: 9 | base-path: /tmp/unittest 10 | -------------------------------------------------------------------------------- /plugin-jdbc/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'plugin-jdbcs' 2 | 3 | include 'plugin-jdbc' 4 | include 'plugin-jdbc-clickhouse' 5 | include 'plugin-jdbc-druid' 6 | include 'plugin-jdbc-duckdb' 7 | include 'plugin-jdbc-mariadb' 8 | include 'plugin-jdbc-mysql' 9 | include 'plugin-jdbc-oracle' 10 | include 'plugin-jdbc-pinot' 11 | include 'plugin-jdbc-postgres' 12 | include 'plugin-jdbc-redshift' 13 | include 'plugin-jdbc-snowflake' 14 | include 'plugin-jdbc-sqlserver' 15 | include 'plugin-jdbc-trino' 16 | include 'plugin-jdbc-vectorwise' 17 | include 'plugin-jdbc-vertica' 18 | include 'plugin-jdbc-dremio' 19 | include 'plugin-jdbc-arrow-flight' 20 | include 'plugin-jdbc-sqlite' 21 | include 'plugin-jdbc-db2' 22 | include 'plugin-jdbc-as400' 23 | include 'plugin-jdbc-sybase' 24 | --------------------------------------------------------------------------------