diff --git a/connectors/jdbc/pom.xml b/connectors/jdbc/pom.xml index 371ba64896..9bcefaffd0 100644 --- a/connectors/jdbc/pom.xml +++ b/connectors/jdbc/pom.xml @@ -50,18 +50,25 @@ 12.6.1.jre11 - - com.mysql - mysql-connector-j - 8.4.0 - - org.postgresql postgresql 42.7.3 + + + org.mariadb.jdbc + mariadb-java-client + 3.3.3 + + + + com.mysql + mysql-connector-j + 8.4.0 + test + org.testcontainers postgresql diff --git a/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/model/request/SupportedDatabase.java b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/model/request/SupportedDatabase.java index c738f8e35a..0e04baf7fd 100644 --- a/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/model/request/SupportedDatabase.java +++ b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/model/request/SupportedDatabase.java @@ -8,7 +8,7 @@ public enum SupportedDatabase { MSSQL("com.microsoft.sqlserver.jdbc.SQLServerDriver", "jdbc:sqlserver://"), - MYSQL("com.mysql.cj.jdbc.Driver", "jdbc:mysql://"), + MYSQL("org.mariadb.jdbc.Driver", "jdbc:mysql://"), POSTGRESQL("org.postgresql.Driver", "jdbc:postgresql://"); private final String driverClassName; diff --git a/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionHelper.java b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionHelper.java index 39df331f1d..a79c9e1557 100644 --- a/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionHelper.java +++ b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionHelper.java @@ -8,7 +8,9 @@ import io.camunda.connector.api.error.ConnectorException; import io.camunda.connector.jdbc.model.request.JdbcRequest; +import io.camunda.connector.jdbc.model.request.SupportedDatabase; import io.camunda.connector.jdbc.model.request.connection.JdbcConnection; +import java.net.URISyntaxException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; @@ -20,20 +22,41 @@ public class ConnectionHelper { private static final Logger LOG = LoggerFactory.getLogger(ConnectionHelper.class); public static Connection openConnection(JdbcRequest request) { + SupportedDatabase database = request.database(); + String driverClassName = database.getDriverClassName(); try { LOG.debug("Executing JDBC request: {}", request); - LOG.debug("Loading JDBC driver: {}", request.database().getDriverClassName()); - Class.forName(request.database().getDriverClassName()); + LOG.debug("Loading JDBC driver: {}", driverClassName); + Class.forName(driverClassName); JdbcConnection connection = request.connection(); Connection conn = DriverManager.getConnection( - connection.getConnectionString(request.database()), connection.getProperties()); - LOG.debug("Connection established for Database {}: {}", request.database(), conn); + ensureMySQLCompatibleUrl(connection.getConnectionString(database), database), + connection.getProperties()); + LOG.debug("Connection established for Database {}: {}", database, conn); return conn; } catch (ClassNotFoundException e) { - throw new ConnectorException("Cannot find class: " + request.database().getDriverClassName()); + throw new ConnectorException("Cannot find class: " + driverClassName); + } catch (URISyntaxException e) { + throw new ConnectorException("Cannot parse the Database connection URL: " + e.getMessage()); } catch (SQLException e) { throw new ConnectorException("Cannot create the Database connection: " + e.getMessage()); } } + + /** + * Ensure MySQL compatibility as we are using MariaDB driver for MySQL. + * + * @return Properties with permitMysqlScheme set to true if the database is MySQL. + * @see Compatibility + * details + */ + private static String ensureMySQLCompatibleUrl(String url, SupportedDatabase database) + throws URISyntaxException { + if (database == SupportedDatabase.MYSQL) { + return ConnectionParameterHelper.addQueryParameterToURL(url, "permitMysqlScheme"); + } + return url; + } } diff --git a/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionParameterHelper.java b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionParameterHelper.java new file mode 100644 index 0000000000..0fa555711b --- /dev/null +++ b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionParameterHelper.java @@ -0,0 +1,48 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.jdbc.utils; + +import java.net.URI; +import java.net.URISyntaxException; + +/** + * Helper class to add parameters to a URL. Parameters values can be added to the URL as well, but + * it is optional. + * + * @see ConnectionParameterHelperTest for usage examples. + */ +public class ConnectionParameterHelper { + + public static String addQueryParameterToURL(String urlString, String paramName) + throws URISyntaxException { + return addQueryParameterToURL(urlString, paramName, null); + } + + public static String addQueryParameterToURL(String urlString, String paramName, String paramValue) + throws URISyntaxException { + URI uri = new URI(urlString); + // Check if the URL already has query parameters + int queryParamsIndex = urlString.indexOf('?'); + String query; + if (queryParamsIndex == -1) { + // No query parameters + query = "?"; + } else { + // Query parameters already exist let's add the new one + query = "&"; + } + query += paramName; + // Value is optional + if (paramValue != null) { + query += "=" + paramValue; + } + // jdbc:mysql//localhost:3306?paramName=paramValue for instance is not detected as a regular + // URI, + // so we need to reconstruct the URI using the scheme and the scheme specific part + return new URI(uri.getScheme() + ":" + uri.getSchemeSpecificPart() + query).toString(); + } +} diff --git a/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionStringHelper.java b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionStringHelper.java index ae490a52cb..91fb96ace0 100644 --- a/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionStringHelper.java +++ b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/utils/ConnectionStringHelper.java @@ -15,35 +15,13 @@ public class ConnectionStringHelper { public static String buildConnectionString( SupportedDatabase database, DetailedConnection connection) { return switch (database) { - case MYSQL -> buildMySqlConnectionString(database, connection); - case POSTGRESQL -> buildPostgresConnectionString(database, connection); + case MYSQL, POSTGRESQL -> buildCommonConnectionString(database, connection); case MSSQL -> buildMssqlConnectionString(database, connection); default -> throw new ConnectorException("Unsupported database: " + database); }; } - private static String buildMySqlConnectionString( - SupportedDatabase database, DetailedConnection connection) { - String host = connection.host(); - String port = connection.port(); - String username = connection.username(); - String password = connection.password(); - String databaseName = connection.databaseName(); - String authentication = ""; - if (username != null && !username.isEmpty()) { - authentication += username; - if (password != null && !password.isEmpty()) { - authentication += ":" + password + "@"; - } - } - String connectionString = database.getUrlSchema() + authentication + host + ":" + port; - if (databaseName != null && !databaseName.isEmpty()) { - connectionString += "/" + databaseName; - } - return connectionString; - } - - private static String buildPostgresConnectionString( + private static String buildCommonConnectionString( SupportedDatabase database, DetailedConnection connection) { String host = connection.host(); String port = connection.port(); diff --git a/connectors/jdbc/src/test/java/io/camunda/connector/jdbc/utils/ConnectionParameterHelperTest.java b/connectors/jdbc/src/test/java/io/camunda/connector/jdbc/utils/ConnectionParameterHelperTest.java new file mode 100644 index 0000000000..f85f5868a9 --- /dev/null +++ b/connectors/jdbc/src/test/java/io/camunda/connector/jdbc/utils/ConnectionParameterHelperTest.java @@ -0,0 +1,74 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.jdbc.utils; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +public class ConnectionParameterHelperTest { + @Test + void shouldCreateQueryParameters_whenNoExistingQueryParameters() throws Exception { + String urlString = "jdbc:mysql//localhost:3306"; + String paramName = "paramName"; + String paramValue = "paramValue"; + String result = + ConnectionParameterHelper.addQueryParameterToURL(urlString, paramName, paramValue); + assertThat(result).isEqualTo(urlString + "?paramName=paramValue"); + } + + @Test + void shouldNotCreateQueryParameters_whenExistingQueryParameters() throws Exception { + String urlString = "jdbc:mysql//localhost:3306?existingParam=existingValue"; + String paramName = "paramName"; + String paramValue = "paramValue"; + String result = + ConnectionParameterHelper.addQueryParameterToURL(urlString, paramName, paramValue); + assertThat(result).isEqualTo(urlString + "¶mName=paramValue"); + } + + @Test + void shouldCreateQueryParameters_whenNoParamValue() throws Exception { + String urlString = "jdbc:mysql//localhost:3306"; + String paramName = "paramName"; + String result = ConnectionParameterHelper.addQueryParameterToURL(urlString, paramName); + assertThat(result).isEqualTo(urlString + "?paramName"); + } + + @Test + void shouldCreateQueryParameters_whenNoParamValueAndExistingQueryParameters() throws Exception { + String urlString = "jdbc:mysql//localhost:3306?existingParam=existingValue"; + String paramName = "paramName"; + String result = ConnectionParameterHelper.addQueryParameterToURL(urlString, paramName); + assertThat(result).isEqualTo(urlString + "¶mName"); + } + + @Test + void shouldCreateQueryParametersAfterPath_whenQueryPathExistsAndNoParamValue() throws Exception { + String urlString = "jdbc:mysql//localhost:3306/database"; + String paramName = "paramName"; + String result = ConnectionParameterHelper.addQueryParameterToURL(urlString, paramName); + assertThat(result).isEqualTo(urlString + "?paramName"); + } + + @Test + void shouldCreateQueryParametersAfterPath_whenQueryPathExistsAndQueryParametersExist() + throws Exception { + String urlString = "jdbc:mysql//localhost:3306/database?existingParam=existingValue"; + String paramName = "paramName"; + String result = ConnectionParameterHelper.addQueryParameterToURL(urlString, paramName); + assertThat(result).isEqualTo(urlString + "¶mName"); + } + + @Test + void shouldCreateQueryParametersAfterPath_whenEmptyPath() throws Exception { + String urlString = "jdbc:mysql//localhost:3306/"; + String paramName = "paramName"; + String result = ConnectionParameterHelper.addQueryParameterToURL(urlString, paramName); + assertThat(result).isEqualTo(urlString + "?paramName"); + } +}