Skip to content

Commit eb84d9a

Browse files
author
Axyoan Marcelo
committed
Fix for Bug#98620 (Bug#31503893), Using DatabaseMetaData.getColumns() gives collation mix error.
Change-Id: I96ce6b8605152105c8166297814c6fad811aedfc
1 parent 7743064 commit eb84d9a

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
Version 9.4.0
55

6+
- Fix for Bug#98620 (Bug#31503893), Using DatabaseMetaData.getColumns() gives collation mix error.
7+
68
- Fix for Bug#118389 (Bug#38044940), OCI ephemeral keys not working after change in OCI CLI.
79

810
- Fix for Bug#22473405, GETOBJECT(STRING , CLASS<T>) METHOD RETURNS ERROR FOR POOLED CONNECTION.

src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataInformationSchema.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,32 @@
2626
import java.sql.Statement;
2727
import java.sql.Types;
2828
import java.util.ArrayList;
29+
import java.util.Collections;
2930
import java.util.List;
31+
import java.util.Map;
32+
import java.util.concurrent.locks.Lock;
33+
import java.util.concurrent.locks.ReentrantLock;
3034
import java.util.stream.Collectors;
3135

36+
import com.mysql.cj.CharsetSettings;
3237
import com.mysql.cj.Messages;
3338
import com.mysql.cj.MysqlType;
3439
import com.mysql.cj.ServerVersion;
3540
import com.mysql.cj.conf.PropertyDefinitions.DatabaseTerm;
3641
import com.mysql.cj.exceptions.MysqlErrorNumbers;
3742
import com.mysql.cj.jdbc.exceptions.SQLError;
3843
import com.mysql.cj.jdbc.result.ResultSetFactory;
44+
import com.mysql.cj.util.LRUCache;
3945
import com.mysql.cj.util.StringUtils;
4046

4147
/**
4248
* DatabaseMetaData implementation that uses INFORMATION_SCHEMA
4349
*/
4450
public class DatabaseMetaDataInformationSchema extends DatabaseMetaData {
4551

52+
static final Lock INFORMATION_SCHEMA_COLLATION_CACHE_LOCK = new ReentrantLock();
53+
static Map<ServerVersion, String> informationSchemaCollationCache = Collections.synchronizedMap(new LRUCache<>(10));
54+
4655
protected DatabaseMetaDataInformationSchema(JdbcConnection connToSet, String databaseToSet, ResultSetFactory resultSetFactory) {
4756
super(connToSet, databaseToSet, resultSetFactory);
4857
}
@@ -351,6 +360,7 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
351360
final String dbFilter = normalizeIdentifierQuoting(chooseDatabaseTerm(catalog, schemaPattern));
352361
final String tableNameFilter = normalizeIdentifierQuoting(tableNamePattern);
353362
final String columnNameFilter = normalizeIdentifierQuoting(columnNamePattern);
363+
final String infScCollation = getInformationSchemaCollation();
354364

355365
StringBuilder query = new StringBuilder("SELECT");
356366
query.append(chooseBasedOnDatabaseTerm(() -> " TABLE_SCHEMA, NULL,", () -> " TABLE_CATALOG, TABLE_SCHEMA,")); // TABLE_CAT, TABLE_SCHEM
@@ -362,8 +372,8 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
362372
query.append(" ").append(MAX_BUFFER_SIZE).append(" AS BUFFER_LENGTH,"); // BUFFER_LENGTH
363373
appendDecimalDigitsClause(query).append(" AS DECIMAL_DIGITS,"); // DECIMAL_DIGITS
364374
query.append(" 10 AS NUM_PREC_RADIX,"); // NUM_PREC_RADIX
365-
query.append(" CASE WHEN IS_NULLABLE = 'NO' THEN ").append(columnNoNulls);
366-
query.append(" ELSE CASE WHEN IS_NULLABLE = 'YES' THEN ").append(columnNullable);
375+
query.append(" CASE WHEN IS_NULLABLE COLLATE " + infScCollation + "= 'NO' THEN ").append(columnNoNulls);
376+
query.append(" ELSE CASE WHEN IS_NULLABLE COLLATE " + infScCollation + "= 'YES' THEN ").append(columnNullable);
367377
query.append(" ELSE ").append(columnNullableUnknown).append(" END END AS NULLABLE,"); // NULLABLE
368378
query.append(" COLUMN_COMMENT AS REMARKS,"); // REMARKS
369379
query.append(" COLUMN_DEFAULT AS COLUMN_DEF,"); // COLUMN_DEF
@@ -377,8 +387,8 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
377387
query.append(" NULL AS SCOPE_SCHEMA,"); // SCOPE_SCHEMA
378388
query.append(" NULL AS SCOPE_TABLE,"); // SCOPE_TABLE
379389
query.append(" NULL AS SOURCE_DATA_TYPE,"); // SOURCE_DATA_TYPE
380-
query.append(" IF (EXTRA LIKE '%auto_increment%','YES','NO') AS IS_AUTOINCREMENT,"); // IS_AUTOINCREMENT
381-
query.append(" IF (EXTRA LIKE '%GENERATED%','YES','NO') AS IS_GENERATEDCOLUMN"); // IS_GENERATEDCOLUMN
390+
query.append(" IF (EXTRA COLLATE " + infScCollation + " LIKE '%auto_increment%','YES','NO') AS IS_AUTOINCREMENT,"); // IS_AUTOINCREMENT
391+
query.append(" IF (EXTRA COLLATE " + infScCollation + " LIKE '%GENERATED%','YES','NO') AS IS_GENERATEDCOLUMN"); // IS_GENERATEDCOLUMN
382392
query.append(" FROM INFORMATION_SCHEMA.COLUMNS");
383393

384394
StringBuilder condition = new StringBuilder();
@@ -1141,4 +1151,34 @@ public ResultSet getVersionColumns(String catalog, String schema, String table)
11411151
}
11421152
}
11431153

1154+
private String getInformationSchemaCollation() throws SQLException {
1155+
String informationSchemaCollation = informationSchemaCollationCache.get(getJdbcConnection().getServerVersion());
1156+
if (informationSchemaCollation != null) {
1157+
return informationSchemaCollation;
1158+
}
1159+
1160+
INFORMATION_SCHEMA_COLLATION_CACHE_LOCK.lock();
1161+
try {
1162+
// Double check, maybe another thread already added it.
1163+
informationSchemaCollation = informationSchemaCollationCache.get(getJdbcConnection().getServerVersion());
1164+
if (informationSchemaCollation != null) {
1165+
return informationSchemaCollation;
1166+
}
1167+
1168+
Statement stmt = getJdbcConnection().getMetaDataSafeStatement();
1169+
ResultSet rs = stmt.executeQuery("SELECT DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'information_schema'");
1170+
if (rs.next()) {
1171+
informationSchemaCollation = rs.getString(1);
1172+
} else {
1173+
informationSchemaCollation = getSession().getServerSession().getServerVariable(CharsetSettings.COLLATION_CONNECTION);
1174+
}
1175+
stmt.close();
1176+
1177+
informationSchemaCollationCache.put(getJdbcConnection().getServerVersion(), informationSchemaCollation);
1178+
return informationSchemaCollation;
1179+
} finally {
1180+
INFORMATION_SCHEMA_COLLATION_CACHE_LOCK.unlock();
1181+
}
1182+
}
1183+
11441184
}

src/test/java/testsuite/regression/MetaDataRegressionTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6017,4 +6017,24 @@ void testBug21294134() throws Exception {
60176017
} while (useIS = !useIS);
60186018
}
60196019

6020+
/**
6021+
* Tests fix for Bug#98620, Bug#31503893, Using DatabaseMetaData.getColumns() gives collation mix error
6022+
*
6023+
* @throws Exception
6024+
*/
6025+
@Test
6026+
public void testBug98620() throws Exception {
6027+
createTable("testBug98620", "(id INT)");
6028+
boolean useIS = false;
6029+
do {
6030+
Properties props = new Properties();
6031+
props.setProperty(PropertyKey.connectionCollation.getKeyName(), "utf8mb3_unicode_ci");
6032+
props.setProperty(PropertyKey.useInformationSchema.getKeyName(), Boolean.toString(useIS));
6033+
Connection testConn = getConnectionWithProps(props);
6034+
this.rs = testConn.getMetaData().getColumns(null, null, "testBug98620", null);
6035+
assertTrue(this.rs.next());
6036+
assertEquals(isServerRunningOnWindows() ? "testbug98620" : "testBug98620", this.rs.getString("TABLE_NAME"));
6037+
} while (useIS = !useIS);
6038+
}
6039+
60206040
}

0 commit comments

Comments
 (0)