Skip to content

Commit f87653d

Browse files
author
Axyoan Marcelo
committed
Fix for Bug#21294134, DBMD.GETPROCEDURECOLUMNS() IS UNABLE TO DEAL WITH PROCEDURE COLUMNS WITH SPACES.
Change-Id: I8705a6e364deb699bfd64fd19e7038ee390fb6f1
1 parent 7e9b0ac commit f87653d

File tree

3 files changed

+86
-30
lines changed

3 files changed

+86
-30
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#21294134, DBMD.GETPROCEDURECOLUMNS() IS UNABLE TO DEAL WITH PROCEDURE COLUMNS WITH SPACES.
7+
68
- Fix for Bug#77658 (Bug#21946136), Incorrect java.sql.Statement.cancel() behavior.
79

810
- Fix for Bug#118100 (Bug#37900711), `You have an error in your SQL syntax` exception thrown after `mysql-connector-j` `9.2.0` -> `9.3.0` upgrade.

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

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.mysql.cj.result.Field;
5353
import com.mysql.cj.result.Row;
5454
import com.mysql.cj.util.SearchMode;
55+
import com.mysql.cj.util.StringInspector;
5556
import com.mysql.cj.util.StringUtils;
5657

5758
/**
@@ -921,52 +922,52 @@ private List<Row> extractStoredRoutineColumnsTypeInfo(String dbName, String rout
921922
boolean isOutParam = false;
922923
boolean isInParam = false;
923924

924-
// Bug#52167, tokenizer will break if declaration contains special characters like '\n'.
925-
declaration = declaration.replaceAll("[\\t\\n\\x0B\\f\\r]", " ");
926-
StringTokenizer declarationTok = new StringTokenizer(declaration, " ");
927-
if (declarationTok.hasMoreTokens()) {
928-
String possibleParamName = declarationTok.nextToken();
925+
boolean noBackslashEscapes = getSession().getServerSession().isNoBackslashEscapesSet();
926+
StringInspector strInspector = new StringInspector(declaration, openingDelimiters, closingDelimiters, "",
927+
noBackslashEscapes ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
928+
929+
int endPos = strInspector.indexOfNextWsChar();
930+
int startPos = 0;
931+
if (endPos != -1) {
932+
String possibleParamName = declaration.substring(startPos, endPos);
933+
boolean firstStringWasParamType = false;
929934
if (possibleParamName.equalsIgnoreCase("OUT")) {
930935
isOutParam = true;
931936
isInParam = false;
932-
if (declarationTok.hasMoreTokens()) {
933-
paramName = declarationTok.nextToken();
934-
} else {
935-
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.6"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
936-
getExceptionInterceptor());
937-
}
937+
firstStringWasParamType = true;
938938
} else if (possibleParamName.equalsIgnoreCase("INOUT")) {
939939
isOutParam = true;
940940
isInParam = true;
941-
if (declarationTok.hasMoreTokens()) {
942-
paramName = declarationTok.nextToken();
943-
} else {
944-
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.6"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
945-
getExceptionInterceptor());
946-
}
941+
firstStringWasParamType = true;
947942
} else if (possibleParamName.equalsIgnoreCase("IN")) {
948943
isOutParam = false;
949944
isInParam = true;
950-
if (declarationTok.hasMoreTokens()) {
951-
paramName = declarationTok.nextToken();
952-
} else {
953-
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.6"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
954-
getExceptionInterceptor());
955-
}
945+
firstStringWasParamType = true;
956946
} else {
957947
isOutParam = false;
958948
isInParam = true;
959949
paramName = possibleParamName;
960950
}
961951

962-
TypeDescriptor typeDesc = null;
963-
if (declarationTok.hasMoreTokens()) {
964-
StringBuilder typeInfo = new StringBuilder(declarationTok.nextToken());
965-
while (declarationTok.hasMoreTokens()) {
966-
typeInfo.append(" ");
967-
typeInfo.append(declarationTok.nextToken());
952+
if (firstStringWasParamType) {
953+
while (Character.isWhitespace(strInspector.getChar())) {
954+
strInspector.incrementPosition();
955+
}
956+
startPos = strInspector.getPosition();
957+
endPos = strInspector.indexOfNextWsChar();
958+
if (endPos != -1) {
959+
paramName = declaration.substring(startPos, endPos);
960+
} else {
961+
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.6"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
962+
getExceptionInterceptor());
968963
}
969-
typeDesc = new TypeDescriptor(typeInfo.toString(), "YES");
964+
}
965+
966+
TypeDescriptor typeDesc = null;
967+
if (strInspector.getPosition() != declaration.length()) {
968+
startPos = strInspector.indexOfNextNonWsChar();
969+
endPos = declaration.length();
970+
typeDesc = new TypeDescriptor(declaration.substring(startPos, endPos), "YES");
970971
} else {
971972
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.7"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
972973
getExceptionInterceptor());

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5964,4 +5964,57 @@ void testBug118100() throws Exception {
59645964
} while (useIS = !useIS);
59655965
}
59665966

5967+
/**
5968+
* Tests fix for Bug#21294134, DBMD.GETPROCEDURECOLUMNS() IS UNABLE TO DEAL WITH PROCEDURE COLUMNS WITH SPACES.
5969+
*
5970+
* @throws Exception
5971+
*/
5972+
@Test
5973+
void testBug21294134() throws Exception {
5974+
boolean useIS = false;
5975+
boolean useAnsiQuotes = false;
5976+
do {
5977+
String sqlMode = getMysqlVariable("sql_mode");
5978+
sqlMode = removeSqlMode("ANSI_QUOTES", sqlMode);
5979+
if (sqlMode.length() > 0) {
5980+
sqlMode += ",";
5981+
}
5982+
if (useAnsiQuotes) {
5983+
sqlMode += "ANSI_QUOTES";
5984+
}
5985+
Properties props = new Properties();
5986+
props.setProperty(PropertyKey.useInformationSchema.getKeyName(), Boolean.toString(useIS));
5987+
props.setProperty(PropertyKey.sessionVariables.getKeyName(), "sql_mode='" + sqlMode + "'");
5988+
this.conn = getConnectionWithProps(props);
5989+
5990+
String procDef = "(IN `a 1` ENUM ('a', 'b'), INOUT `a\n2` SET ('c', 'd')) BEGIN SELECT CONCAT(`a 1`, `a\n2`) INTO `a\n2`; END";
5991+
String funcDef = "(`b 1` ENUM ('a', 'b'), `b\n2` SET ('c', 'd')) RETURNS INT DETERMINISTIC RETURN CONCAT(`b 1`, `b\n2`)";
5992+
if (useAnsiQuotes) {
5993+
procDef.replaceAll("`", "\"");
5994+
funcDef.replaceAll("`", "\"");
5995+
}
5996+
5997+
Statement testStmt = this.conn.createStatement();
5998+
createProcedure(testStmt, "testBug21294134p", procDef);
5999+
createFunction(testStmt, "testBug21294134f", funcDef);
6000+
6001+
final String testCase = String.format("Case: [useIS: %s, useAnsiQuotes: %s]", useIS ? "Y" : "N", useAnsiQuotes ? "Y" : "N");
6002+
6003+
DatabaseMetaData dbmd = this.conn.getMetaData();
6004+
6005+
this.rs = dbmd.getProcedureColumns(null, null, "testBug21294134p", null);
6006+
assertTrue(this.rs.next());
6007+
assertEquals("a 1", this.rs.getString("COLUMN_NAME"), testCase);
6008+
assertTrue(this.rs.next());
6009+
assertEquals("a\n2", this.rs.getString("COLUMN_NAME"), testCase);
6010+
6011+
this.rs = dbmd.getFunctionColumns(null, null, "testBug21294134f", null);
6012+
assertTrue(this.rs.next());
6013+
assertTrue(this.rs.next());
6014+
assertEquals("b 1", this.rs.getString("COLUMN_NAME"), testCase);
6015+
assertTrue(this.rs.next());
6016+
assertEquals("b\n2", this.rs.getString("COLUMN_NAME"), testCase);
6017+
} while (useIS = !useIS);
6018+
}
6019+
59676020
}

0 commit comments

Comments
 (0)