Skip to content

Commit 8383db0

Browse files
committed
address corner case
1 parent 22d8304 commit 8383db0

2 files changed

Lines changed: 122 additions & 2 deletions

File tree

framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.Properties;
3232
import java.util.Objects;
3333
import java.util.concurrent.atomic.AtomicLong;
34+
import java.util.regex.Pattern;
3435

3536
import javax.sql.DataSource;
3637

@@ -87,6 +88,13 @@ public class TransactionLegacy implements Closeable {
8788
public static final short CONNECTED_DB = -1;
8889
public static final String CONNECTION_PARAMS = "scrollTolerantForwardOnly=true";
8990

91+
/**
92+
* Format of the pattern that matches a parameter of a connection URI: the name must be at the start of the URI
93+
* parameters or right after a parameter separator, and must be followed by "=". Searching for the bare name would
94+
* consider the parameter as configured when it is just part of a host, of a database name or of the value of
95+
* another parameter.
96+
*/
97+
private static final String URI_PARAM_PATTERN_FORMAT = "(?:^|[?&])%s=";
9098
private static final String CONNECTION_COLLATION_PARAM = "connectionCollation";
9199
private static final String CHARACTER_ENCODING_PARAM = "characterEncoding";
92100
private static final String DEFAULT_CONNECTION_COLLATION = "utf8mb4_general_ci";
@@ -1275,8 +1283,20 @@ protected static String buildConnectionUri(String loadBalanceStrategy, String dr
12751283
* @param connectionUri the connection URI configured by the operator.
12761284
*/
12771285
protected static boolean shouldPinConnectionCollation(String connectionUri) {
1278-
return !StringUtils.containsIgnoreCase(connectionUri, CONNECTION_COLLATION_PARAM)
1279-
&& !StringUtils.containsIgnoreCase(connectionUri, CHARACTER_ENCODING_PARAM);
1286+
return !containsUriParam(connectionUri, CONNECTION_COLLATION_PARAM)
1287+
&& !containsUriParam(connectionUri, CHARACTER_ENCODING_PARAM);
1288+
}
1289+
1290+
/**
1291+
* Informs whether the given parameter is defined in the connection URI.
1292+
*
1293+
* @param connectionUri the connection URI configured by the operator; it also accepts only the parameters of a URI,
1294+
* as in {@code db.<schema>.url.params};
1295+
* @param param the name of the parameter to look for.
1296+
*/
1297+
protected static boolean containsUriParam(String connectionUri, String param) {
1298+
Pattern pattern = Pattern.compile(String.format(URI_PARAM_PATTERN_FORMAT, Pattern.quote(param)), Pattern.CASE_INSENSITIVE);
1299+
return pattern.matcher(StringUtils.defaultString(connectionUri)).find();
12801300
}
12811301

12821302
/**

framework/db/src/test/java/com/cloud/utils/db/TransactionLegacyTest.java

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,104 @@ public void addDefaultConnectionCollationTestUriDefiningCharacterEncodingKeepsIt
252252

253253
Assert.assertEquals(uri, TransactionLegacy.addDefaultConnectionCollation(uri));
254254
}
255+
256+
@Test
257+
public void shouldPinConnectionCollationTestUriWithHostContainingTheParameterNamesReturnsTrue() {
258+
Assert.assertTrue(TransactionLegacy.shouldPinConnectionCollation("jdbc:mysql://characterEncoding:5555/name"));
259+
Assert.assertTrue(TransactionLegacy.shouldPinConnectionCollation("jdbc:mysql://connectionCollation.example.com:5555/name?someParams"));
260+
}
261+
262+
@Test
263+
public void shouldPinConnectionCollationTestUriWithDatabaseNameContainingTheParameterNamesReturnsTrue() {
264+
Assert.assertTrue(TransactionLegacy.shouldPinConnectionCollation("jdbc:mysql://host:5555/connectionCollation"));
265+
Assert.assertTrue(TransactionLegacy.shouldPinConnectionCollation("jdbc:mysql://host:5555/characterEncoding?someParams"));
266+
}
267+
268+
@Test
269+
public void shouldPinConnectionCollationTestParameterValueContainingTheParameterNamesReturnsTrue() {
270+
Assert.assertTrue(TransactionLegacy.shouldPinConnectionCollation("jdbc:mysql://host:5555/name?user=connectionCollation"));
271+
Assert.assertTrue(TransactionLegacy.shouldPinConnectionCollation("jdbc:mysql://host:5555/name?user=characterEncoding&someParams"));
272+
}
273+
274+
@Test
275+
public void shouldPinConnectionCollationTestUriDefiningTheParametersAsTheFirstOneReturnsFalse() {
276+
Assert.assertFalse(TransactionLegacy.shouldPinConnectionCollation("jdbc:mysql://host:5555/name?connectionCollation=utf8mb4_unicode_ci"));
277+
Assert.assertFalse(TransactionLegacy.shouldPinConnectionCollation("jdbc:mysql://host:5555/name?characterEncoding=UTF-8&someParams"));
278+
}
279+
280+
@Test
281+
public void addDefaultConnectionCollationTestUriWithHostContainingTheParameterNamesAddsTheDefaultCollation() {
282+
String result = TransactionLegacy.addDefaultConnectionCollation("jdbc:mysql://characterEncoding.example.com:5555/name");
283+
284+
Assert.assertEquals("jdbc:mysql://characterEncoding.example.com:5555/name?connectionCollation=utf8mb4_general_ci", result);
285+
}
286+
287+
@Test
288+
public void addDefaultConnectionCollationTestUriWithDatabaseNameContainingTheParameterNamesAddsTheDefaultCollation() {
289+
String result = TransactionLegacy.addDefaultConnectionCollation("jdbc:mysql://host:5555/connectionCollation?someParams");
290+
291+
Assert.assertEquals("jdbc:mysql://host:5555/connectionCollation?someParams&connectionCollation=utf8mb4_general_ci", result);
292+
}
293+
294+
@Test
295+
public void getConnectionUriAndDriverTestWithUriWhoseDatabaseNameContainsTheParameterNamePinsTheDefaultCollation() {
296+
properties.setProperty("db.cloud.uri", "jdbc:mysql://host:5555/characterEncoding");
297+
298+
Pair<String, String> result = TransactionLegacy.getConnectionUriAndDriver(properties, null, false, "cloud");
299+
300+
Assert.assertEquals("jdbc:mysql://host:5555/characterEncoding?connectionCollation=utf8mb4_general_ci", result.first());
301+
}
302+
303+
@Test
304+
public void getConnectionUriAndDriverTestWithoutUriAndDatabaseNameContainingTheParameterNamePinsTheDefaultCollation() {
305+
properties.setProperty("db.cloud.uri", "");
306+
properties.setProperty("db.cloud.driver", "driver");
307+
properties.setProperty("db.cloud.name", "connectionCollation");
308+
309+
Pair<String, String> result = TransactionLegacy.getConnectionUriAndDriver(properties, null, false, "cloud");
310+
311+
Assert.assertEquals("driver://host:5555/connectionCollation?autoReconnect=false&someParams&scrollTolerantForwardOnly=true"
312+
+ "&connectionCollation=utf8mb4_general_ci", result.first());
313+
}
314+
315+
@Test
316+
public void containsUriParamTestParamDefinedAsTheFirstOneReturnsTrue() {
317+
Assert.assertTrue(TransactionLegacy.containsUriParam("jdbc:mysql://host:5555/name?serverTimezone=UTC", "serverTimezone"));
318+
}
319+
320+
@Test
321+
public void containsUriParamTestParamDefinedAfterOtherParamsReturnsTrue() {
322+
Assert.assertTrue(TransactionLegacy.containsUriParam("jdbc:mysql://host:5555/name?someParams&serverTimezone=UTC", "serverTimezone"));
323+
}
324+
325+
@Test
326+
public void containsUriParamTestOnlyTheUriParamsReturnsTrue() {
327+
Assert.assertTrue(TransactionLegacy.containsUriParam("serverTimezone=UTC&someParams", "serverTimezone"));
328+
}
329+
330+
@Test
331+
public void containsUriParamTestParamIsPartOfTheHostOrOfTheDatabaseNameReturnsFalse() {
332+
Assert.assertFalse(TransactionLegacy.containsUriParam("jdbc:mysql://serverTimezone:5555/name", "serverTimezone"));
333+
Assert.assertFalse(TransactionLegacy.containsUriParam("jdbc:mysql://host:5555/serverTimezone?someParams", "serverTimezone"));
334+
}
335+
336+
@Test
337+
public void containsUriParamTestParamIsTheValueOfAnotherParamReturnsFalse() {
338+
Assert.assertFalse(TransactionLegacy.containsUriParam("jdbc:mysql://host:5555/name?user=serverTimezone", "serverTimezone"));
339+
}
340+
341+
@Test
342+
public void containsUriParamTestParamIsNotDefinedReturnsFalse() {
343+
Assert.assertFalse(TransactionLegacy.containsUriParam("jdbc:mysql://host:5555/name?someParams", "serverTimezone"));
344+
}
345+
346+
@Test
347+
public void containsUriParamTestNullConnectionUriReturnsFalse() {
348+
Assert.assertFalse(TransactionLegacy.containsUriParam(null, "serverTimezone"));
349+
}
350+
351+
@Test
352+
public void containsUriParamTestIsCaseInsensitive() {
353+
Assert.assertTrue(TransactionLegacy.containsUriParam("jdbc:mysql://host:5555/name?SERVERTIMEZONE=UTC", "serverTimezone"));
354+
}
255355
}

0 commit comments

Comments
 (0)