Skip to content

Commit

Permalink
[CONJ-574] forcing using toLowerCase/toUpperCase with Locale.ROOT whe…
Browse files Browse the repository at this point in the history
…n retrieving column by name to avoid issues if current local special casing rules.
  • Loading branch information
rusher committed Jan 31, 2018
1 parent 08eef2b commit f88098f
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 18 deletions.
5 changes: 3 additions & 2 deletions src/main/java/org/mariadb/jdbc/CallableParameterMetaData.java
Expand Up @@ -56,6 +56,7 @@
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -107,7 +108,7 @@ public void readMetadataFromDbIfRequired() throws SQLException {
}

private int mapMariaDbTypeToJdbc(String str) {
switch (str.toUpperCase()) {
switch (str.toUpperCase(Locale.ROOT)) {
case "BIT":
return Types.BIT;
case "TINYINT":
Expand Down Expand Up @@ -246,7 +247,7 @@ private void parseParamList(boolean isFunction, String paramList) throws SQLExce

callParameter.setName(matcher2.group(2).trim());
callParameter.setSigned(matcher2.group(3) == null);
callParameter.setTypeName(matcher2.group(4).trim().toUpperCase());
callParameter.setTypeName(matcher2.group(4).trim().toUpperCase(Locale.ROOT));

if (direction == null || direction.equalsIgnoreCase("IN")) {
callParameter.setInput(true);
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/org/mariadb/jdbc/UrlParser.java
Expand Up @@ -61,6 +61,7 @@
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -136,7 +137,7 @@ private void setInitialUrl() {
StringBuilder sb = new StringBuilder();
sb.append("jdbc:mariadb:");
if (haMode != HaMode.NONE) {
sb.append(haMode.toString().toLowerCase()).append(":");
sb.append(haMode.toString().toLowerCase(Locale.ROOT)).append(":");
}
sb.append("//");

Expand Down Expand Up @@ -341,7 +342,7 @@ private static HaMode parseHaMode(String url, int separator) {
}

try {
return HaMode.valueOf(url.substring(secondColonPos + 1, thirdColonPos).toUpperCase());
return HaMode.valueOf(url.substring(secondColonPos + 1, thirdColonPos).toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException i) {
throw new IllegalArgumentException("wrong failover parameter format in connection String " + url);
}
Expand Down
Expand Up @@ -56,6 +56,7 @@

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;


Expand All @@ -77,7 +78,7 @@ public ColumnNameMap(ColumnInformation[] columnInformations) {
*/
public int getIndex(String name) throws SQLException {
if (name == null) throw new SQLException("Column name cannot be null");
String lowerName = name.toLowerCase();
String lowerName = name.toLowerCase(Locale.ROOT);
// The specs in JDBC 4.0 specify that ResultSet.findColumn and
// ResultSet.getXXX(String name) should use column alias (AS in the query). If label is not found, we use
// original table name.
Expand All @@ -87,12 +88,12 @@ public int getIndex(String name) throws SQLException {
for (ColumnInformation ci : columnInfo) {
String columnAlias = ci.getName();
if (columnAlias != null && !columnAlias.isEmpty()) {
columnAlias = columnAlias.toLowerCase();
columnAlias = columnAlias.toLowerCase(Locale.ROOT);
aliasMap.putIfAbsent(columnAlias, counter);

String tableName = ci.getTable();
if (tableName != null && !tableName.isEmpty()) {
aliasMap.putIfAbsent(tableName.toLowerCase() + "." + columnAlias, counter);
aliasMap.putIfAbsent(tableName.toLowerCase(Locale.ROOT) + "." + columnAlias, counter);
}
}
counter++;
Expand All @@ -110,12 +111,12 @@ public int getIndex(String name) throws SQLException {
for (ColumnInformation ci : columnInfo) {
String columnRealName = ci.getOriginalName();
if (columnRealName != null && !columnRealName.isEmpty()) {
columnRealName = columnRealName.toLowerCase();
columnRealName = columnRealName.toLowerCase(Locale.ROOT);
originalMap.putIfAbsent(columnRealName, counter);

String tableName = ci.getOriginalTable();
if (tableName != null && !tableName.isEmpty()) {
originalMap.putIfAbsent(tableName.toLowerCase() + "." + columnRealName, counter);
originalMap.putIfAbsent(tableName.toLowerCase(Locale.ROOT) + "." + columnRealName, counter);
}
}
counter++;
Expand Down
Expand Up @@ -66,6 +66,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -300,7 +301,7 @@ public HandleErrorResult relaunchOperation(Method method, Object[] args) throws

case "executeQuery":
if (args[2] instanceof String) {
String query = ((String) args[2]).toUpperCase();
String query = ((String) args[2]).toUpperCase(Locale.ROOT);
if (!"ALTER SYSTEM CRASH".equals(query)
&& !query.startsWith("KILL")) {
logger.debug("relaunch query to new connection {}",
Expand Down Expand Up @@ -349,17 +350,18 @@ public boolean isQueryRelaunchable(Method method, Object[] args) {
case "executeQuery":
if (!((Boolean) args[0])) return true; //launched on slave connection
if (args[2] instanceof String) {
return ((String) args[2]).toUpperCase().startsWith("SELECT");
return ((String) args[2]).toUpperCase(Locale.ROOT).startsWith("SELECT");
} else if (args[2] instanceof ClientPrepareResult) {
@SuppressWarnings("unchecked")
String query = new String(((ClientPrepareResult) args[2]).getQueryParts().get(0)).toUpperCase();
String query = new String(((ClientPrepareResult) args[2]).getQueryParts().get(0))
.toUpperCase(Locale.ROOT);
return query.startsWith("SELECT");
}
break;
case "executePreparedQuery":
if (!((Boolean) args[0])) return true; //launched on slave connection
ServerPrepareResult serverPrepareResult = (ServerPrepareResult) args[1];
return (serverPrepareResult.getSql()).toUpperCase().startsWith("SELECT");
return (serverPrepareResult.getSql()).toUpperCase(Locale.ROOT).startsWith("SELECT");
case "executeBatchStmt":
case "executeBatchClient":
case "executeBatchServer":
Expand Down
Expand Up @@ -94,6 +94,7 @@
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.List;
import java.util.Locale;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
Expand Down Expand Up @@ -393,7 +394,7 @@ private boolean executeBulkBatch(Results results, String sql, ServerPrepareResul
}

//any select query is not applicable to bulk
if (sql.toLowerCase().contains("select")) return false;
if (sql.toLowerCase(Locale.ROOT).contains("select")) return false;

cmdPrologue();

Expand Down
Expand Up @@ -38,8 +38,8 @@ public class HostnameVerifierImpl implements HostnameVerifier {
*/
private static boolean matchDns(String hostname, String tlsDnsPattern) throws SSLException {
boolean hostIsIp = Utils.isIPv4(hostname) || Utils.isIPv6(hostname);
StringTokenizer hostnameSt = new StringTokenizer(hostname.toLowerCase(), ".");
StringTokenizer templateSt = new StringTokenizer(tlsDnsPattern.toLowerCase(), ".");
StringTokenizer hostnameSt = new StringTokenizer(hostname.toLowerCase(Locale.ROOT), ".");
StringTokenizer templateSt = new StringTokenizer(tlsDnsPattern.toLowerCase(Locale.ROOT), ".");
if (hostnameSt.countTokens() != templateSt.countTokens()) return false;

try {
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/org/mariadb/jdbc/internal/util/Utils.java
Expand Up @@ -77,6 +77,7 @@
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -224,7 +225,7 @@ private static String replaceFunctionParameter(String functionString) {
for (; ((input[index] >= 'a' && index <= 'z') || (input[index] >= 'A' && input[index] <= 'Z')) && index < input.length; index++) {
sb.append(input[index]);
}
String func = sb.toString().toLowerCase();
String func = sb.toString().toLowerCase(Locale.ROOT);

if ("convert".equals(func) || "timestampdiff".equals(func) || "timestampadd".equals(func)) {
String paramPrefix;
Expand Down Expand Up @@ -277,7 +278,7 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes)
throw new SQLException("unexpected escaped string");
}
int endIndex = escaped.length() - 1;
String escapedLower = escaped.toLowerCase();
String escapedLower = escaped.toLowerCase(Locale.ROOT);
if (escaped.startsWith("{fn ")) {
String resolvedParams = replaceFunctionParameter(escaped.substring(4, endIndex));
return nativeSql(resolvedParams, noBackslashEscapes);
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/org/mariadb/jdbc/CollationTest.java
Expand Up @@ -59,6 +59,7 @@
import java.io.StringReader;
import java.nio.charset.Charset;
import java.sql.*;
import java.util.Locale;

import static org.junit.Assert.*;

Expand Down Expand Up @@ -232,5 +233,32 @@ public void insertAndSelectShouldBothUseLatin1Encoding() throws SQLException {
assertFalse(rs1.next());
}

@Test
public void languageCasing() throws SQLException {
Locale currentLocal = Locale.getDefault();
createTable("languageCasing", "ID int, id2 int");
try (Statement statement = sharedConnection.createStatement()) {
statement.execute("INSERT INTO languageCasing values (1,2)");

ResultSet rs = statement.executeQuery("SELECT * FROM languageCasing");
assertTrue(rs.next());
assertEquals(1, rs.getInt("ID"));
assertEquals(1, rs.getInt("id"));
assertEquals(2, rs.getInt("ID2"));
assertEquals(2, rs.getInt("id2"));

Locale.setDefault(new Locale("tr"));

rs = statement.executeQuery("SELECT * FROM languageCasing");
assertTrue(rs.next());
assertEquals(1, rs.getInt("ID"));
assertEquals(1, rs.getInt("id"));
assertEquals(2, rs.getInt("ID2"));
assertEquals(2, rs.getInt("id2"));

} finally {
Locale.setDefault(currentLocal);
}
}

}

0 comments on commit f88098f

Please sign in to comment.