Skip to content

Commit

Permalink
Fix appending of JDBC parameters to SQL Server JDBC URL
Browse files Browse the repository at this point in the history
Fixes gh-41146
  • Loading branch information
wilkinsona authored and philwebb committed Jun 20, 2024
1 parent 43cd241 commit 126e87e
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -68,20 +68,33 @@ public String build(RunningService service, String database) {

private String urlFor(RunningService service, String database) {
Assert.notNull(service, "Service must not be null");
String parameters = getParameters(service);
StringBuilder url = new StringBuilder("jdbc:%s://%s:%d".formatted(this.driverProtocol, service.host(),
service.ports().get(this.containerPort)));
if (StringUtils.hasLength(database)) {
url.append("/");
url.append(database);
}
url.append(parameters);
String parameters = getParameters(service);
if (StringUtils.hasLength(parameters)) {
appendParameters(url, parameters);
}
return url.toString();
}

/**
* Appends to the given {@code url} the given {@code parameters}.
* <p>
* The default implementation appends a {@code ?} followed by the {@code parameters}.
* @param url the url
* @param parameters the parameters
* @since 3.2.7
*/
protected void appendParameters(StringBuilder url, String parameters) {
url.append("?").append(parameters);
}

private String getParameters(RunningService service) {
String parameters = service.labels().get(PARAMETERS_LABEL);
return (StringUtils.hasLength(parameters)) ? "?" + parameters : "";
return service.labels().get(PARAMETERS_LABEL);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -47,7 +47,7 @@ protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeC
static class SqlServerJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
implements JdbcConnectionDetails {

private static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder("sqlserver", 1433);
private static final JdbcUrlBuilder jdbcUrlBuilder = new SqlServerJdbcUrlBuilder("sqlserver", 1433);

private final SqlServerEnvironment environment;

Expand All @@ -56,7 +56,7 @@ static class SqlServerJdbcDockerComposeConnectionDetails extends DockerComposeCo
SqlServerJdbcDockerComposeConnectionDetails(RunningService service) {
super(service);
this.environment = new SqlServerEnvironment(service.env());
this.jdbcUrl = disableEncryptionIfNecessary(jdbcUrlBuilder.build(service, ""));
this.jdbcUrl = disableEncryptionIfNecessary(jdbcUrlBuilder.build(service));
}

private String disableEncryptionIfNecessary(String jdbcUrl) {
Expand Down Expand Up @@ -86,6 +86,19 @@ public String getJdbcUrl() {
return this.jdbcUrl;
}

private static final class SqlServerJdbcUrlBuilder extends JdbcUrlBuilder {

private SqlServerJdbcUrlBuilder(String driverProtocol, int containerPort) {
super(driverProtocol, containerPort);
}

@Override
protected void appendParameters(StringBuilder url, String parameters) {
url.append(";").append(parameters);
}

}

}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -67,6 +67,20 @@ void buildWhenHasParamsLabelBuildsUrl() {
assertThat(url).isEqualTo("jdbc:mydb://myhost:456/mydb?foo=bar");
}

@Test
void buildWithCustomAppendParametersWhenHasParamsLabelBuildsUrl() {
RunningService service = mockService(456, Map.of("org.springframework.boot.jdbc.parameters", "foo=bar"));
String url = new JdbcUrlBuilder("mydb", 1234) {

@Override
protected void appendParameters(StringBuilder url, String parameters) {
url.append(";").append(parameters);
}

}.build(service, "mydb");
assertThat(url).isEqualTo("jdbc:mydb://myhost:456/mydb;foo=bar");
}

@Test
void buildWhenServiceIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.builder.build(null, "mydb"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,27 @@
disabledReason = "The SQL server image has no ARM support")
class SqlServerJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {

@SuppressWarnings("unchecked")
@DockerComposeTest(composeFile = "mssqlserver-compose.yaml", image = TestImage.SQL_SERVER)
void runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(JdbcConnectionDetails connectionDetails)
throws ClassNotFoundException, LinkageError {
assertThat(connectionDetails.getUsername()).isEqualTo("SA");
assertThat(connectionDetails.getPassword()).isEqualTo("verYs3cret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:sqlserver://");
checkDatabaseAccess(connectionDetails);
}

@DockerComposeTest(composeFile = "mssqlserver-with-jdbc-parameters-compose.yaml", image = TestImage.SQL_SERVER)
void runWithJdbcParametersCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(
JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
assertThat(connectionDetails.getUsername()).isEqualTo("SA");
assertThat(connectionDetails.getPassword()).isEqualTo("verYs3cret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:sqlserver://")
.contains(";sendStringParametersAsUnicode=false;");
checkDatabaseAccess(connectionDetails);
}

@SuppressWarnings("unchecked")
private void checkDatabaseAccess(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setUrl(connectionDetails.getJdbcUrl());
dataSource.setUsername(connectionDetails.getUsername());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
database:
image: '{imageName}'
ports:
- '1433'
environment:
- 'MSSQL_PID=express'
- 'MSSQL_SA_PASSWORD=verYs3cret'
- 'ACCEPT_EULA=yes'
labels:
org.springframework.boot.jdbc.parameters: sendStringParametersAsUnicode=false

0 comments on commit 126e87e

Please sign in to comment.