Skip to content

Commit f4a5779

Browse files
authored
Support IBM JDBC URL separators in DB2 connection URI parser (#1686)
The DB2 connection URI parser only accepted query-string style attributes (?key=value&key=value). IBM's documented URL syntax uses a colon to separate the database from the connection attributes and semicolons between key/value pairs: db2://host:port/database:user=app;password=secret; Accept this form in addition to the existing one. The attribute block is only allowed after a database name, and mixing it with & separators is rejected. Fixes #1118 Assisted-by: Anthropic Claude Fable (claude-fable-5) Signed-off-by: jnbdz <jn@yaloub.com>
1 parent 593c41f commit f4a5779

3 files changed

Lines changed: 91 additions & 5 deletions

File tree

vertx-db2-client/src/main/asciidoc/index.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ The URI format for a connection string is:
143143
db2://[user[:[password]]@]host[:port][/database][?<key1>=<value1>[&<key2>=<value2>]]
144144
----
145145

146+
The IBM JDBC URL syntax is supported as well, using `:` to separate the database from the parameters and `;` between parameter key/value pairs:
147+
148+
----
149+
db2://[user[:[password]]@]host[:port]/database:<key1>=<value1>;[<key2>=<value2>;]
150+
----
151+
146152
NOTE: Configuring parameters in connection URI will override the default properties.
147153

148154
Currently, the client supports the following parameter keys:

vertx-db2-client/src/main/java/io/vertx/db2client/impl/DB2ConnectionUriParser.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public class DB2ConnectionUriParser {
4040
private static final String USER_INFO_REGEX = "((?<userinfo>[a-zA-Z0-9\\-._~%!*]+(:[a-zA-Z0-9\\-._~%!*]*)?)@)?"; // username and password
4141
private static final String NET_LOCATION_REGEX = "(?<host>[0-9.]+|\\[[a-zA-Z0-9:]+]|[a-zA-Z0-9\\-._~%]+)"; // ip v4/v6 address or host name
4242
private static final String PORT_REGEX = "(:(?<port>\\d+))?"; // port
43-
private static final String DATABASE_REGEX = "(/(?<database>[a-zA-Z0-9\\-._~%!*]+))?"; // database name
43+
private static final String DATABASE_REGEX = "(/(?<database>[a-zA-Z0-9\\-._~%!*]+)"
44+
+ "(:(?<jdbcattributes>[^?&]*))?)?"; // database name, optionally followed by IBM JDBC style attributes
4445
private static final String ATTRIBUTES_REGEX = "(\\?(?<attributes>.*))?"; // attributes
4546

4647
private static final Pattern SCHEME_DESIGNATOR_PATTERN = Pattern.compile("^" + SCHEME_DESIGNATOR_REGEX);
@@ -84,8 +85,11 @@ private static void doParse(String connectionUri, JsonObject configuration) {
8485
// parse the database name
8586
parseDatabaseName(matcher.group("database"), configuration);
8687

88+
// parse the IBM JDBC style attributes, e.g. db2://localhost:50000/mydb:user=app;password=secret;
89+
parseAttributes(matcher.group("jdbcattributes"), configuration, ";");
90+
8791
// parse the attributes
88-
parseAttributes(matcher.group("attributes"), configuration);
92+
parseAttributes(matcher.group("attributes"), configuration, "&");
8993

9094
} else {
9195
throw new IllegalArgumentException("Wrong syntax of connection URI. Must match pattern: " + FULL_URI_PATTERN);
@@ -142,12 +146,12 @@ private static void parseDatabaseName(String schemaInfo, JsonObject configuratio
142146
configuration.put("database", decodeUrl(schemaInfo));
143147
}
144148

145-
private static void parseAttributes(String attributesInfo, JsonObject configuration) {
149+
private static void parseAttributes(String attributesInfo, JsonObject configuration, String separator) {
146150
if (attributesInfo == null || attributesInfo.isEmpty()) {
147151
return;
148152
}
149153
Map<String, String> properties = new HashMap<>();
150-
for (String parameterPair : attributesInfo.split("&")) {
154+
for (String parameterPair : attributesInfo.split(separator)) {
151155
if (parameterPair.isEmpty()) {
152156
continue;
153157
}
@@ -185,7 +189,9 @@ private static void parseAttributes(String attributesInfo, JsonObject configurat
185189
}
186190
}
187191
if (!properties.isEmpty()) {
188-
configuration.put("properties", properties);
192+
JsonObject props = configuration.getJsonObject("properties", new JsonObject());
193+
properties.forEach(props::put);
194+
configuration.put("properties", props);
189195
}
190196
}
191197

vertx-db2-client/src/test/java/io/vertx/tests/db2client/DB2ConnectionUriParserTest.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,4 +275,78 @@ public void testPartialMatching(){
275275
actualParsedResult = parse(uri, false);
276276
assertNull(actualParsedResult);
277277
}
278+
279+
@Test
280+
public void testParsingJdbcStyleAttributes() {
281+
uri = "db2://localhost:50000/hreact:user=hreact;password=hreact;";
282+
actualParsedResult = parse(uri);
283+
284+
expectedParsedResult = new JsonObject()
285+
.put("host", "localhost")
286+
.put("port", 50000)
287+
.put("database", "hreact")
288+
.put("user", "hreact")
289+
.put("password", "hreact");
290+
291+
assertEquals(expectedParsedResult, actualParsedResult);
292+
}
293+
294+
@Test
295+
public void testParsingJdbcStyleAttributesWithoutTrailingSemicolon() {
296+
uri = "db2://localhost/hreact:user=hreact;password=hreact";
297+
actualParsedResult = parse(uri);
298+
299+
expectedParsedResult = new JsonObject()
300+
.put("host", "localhost")
301+
.put("database", "hreact")
302+
.put("user", "hreact")
303+
.put("password", "hreact");
304+
305+
assertEquals(expectedParsedResult, actualParsedResult);
306+
}
307+
308+
@Test
309+
public void testParsingJdbcStyleSingleAttribute() {
310+
uri = "db2://localhost/mydb:user=other;";
311+
actualParsedResult = parse(uri);
312+
313+
expectedParsedResult = new JsonObject()
314+
.put("host", "localhost")
315+
.put("database", "mydb")
316+
.put("user", "other");
317+
318+
assertEquals(expectedParsedResult, actualParsedResult);
319+
}
320+
321+
@Test
322+
public void testParsingJdbcStyleCustomProperties() {
323+
uri = "db2://localhost/mydb:user=hreact;securityMechanism=9;";
324+
actualParsedResult = parse(uri);
325+
326+
expectedParsedResult = new JsonObject()
327+
.put("host", "localhost")
328+
.put("database", "mydb")
329+
.put("user", "hreact")
330+
.put("properties", new JsonObject().put("securitymechanism", "9"));
331+
332+
assertEquals(expectedParsedResult, actualParsedResult);
333+
}
334+
335+
@Test(expected = IllegalArgumentException.class)
336+
public void testParsingJdbcStyleAttributesWithAmpersandSeparator() {
337+
uri = "db2://localhost:4444/hreact:user=hreact&password=hreact";
338+
actualParsedResult = parse(uri);
339+
}
340+
341+
@Test(expected = IllegalArgumentException.class)
342+
public void testParsingJdbcStyleAttributesWithoutDatabase() {
343+
uri = "db2://localhost:user=hreact;password=hreact;";
344+
actualParsedResult = parse(uri);
345+
}
346+
347+
@Test(expected = IllegalArgumentException.class)
348+
public void testParsingJdbcStyleAttributeWithoutValueDelimiter() {
349+
uri = "db2://localhost/mydb:user;";
350+
actualParsedResult = parse(uri);
351+
}
278352
}

0 commit comments

Comments
 (0)