Description:
CallableStatement.extractProcedureName() don't work correct when procedure name with dash "-"
How to repeat:
import com.mysql.jdbc.StringUtils;
import com.mysql.jdbc.util.BaseBugReport;
public class MyBugReport extends BaseBugReport{
@Override
public void setUp() throws Exception {}
@Override
public void tearDown() throws Exception {}
@Override
public void runTest() throws Exception {
String originalSql= "CALL a-bug.proc_stock(?,?)";
//mysql-connector-java 5.1.40
//com.mysql.jdbc.CallableStatement.extractProcedureName()
String sanitizedSql = StringUtils.stripComments(originalSql, "`\"'", "`\"'", true, false, true, true);
assertTrue("\""+sanitizedSql+"\" should be equal to \""+originalSql+"\"", originalSql.equals(sanitizedSql));
}
public static void main(String[] args) throws Exception {
new MyBugReport().run();
}
}
Suggested fix:
package com.mysql.jdbc;
public class StringUtils {
public static String stripComments(String src, String stringOpens, String stringCloses, boolean slashStarComments, boolean slashSlashComments,
boolean hashComments, boolean dashDashComments) {
if (src == null) {
return null;
}
StringBuilder strBuilder = new StringBuilder(src.length());
// It's just more natural to deal with this as a stream when parsing..This code is currently only called when parsing the kind of metadata that
// developers are strongly recommended to cache anyways, so we're not worried about the _1_ extra object allocation if it cleans up the code
StringReader sourceReader = new StringReader(src);
int contextMarker = Character.MIN_VALUE;
boolean escaped = false;
int markerTypeFound = -1;
int ind = 0;
int currentChar = 0;
try {
while ((currentChar = sourceReader.read()) != -1) {
if (markerTypeFound != -1 && currentChar == stringCloses.charAt(markerTypeFound) && !escaped) {
contextMarker = Character.MIN_VALUE;
markerTypeFound = -1;
} else if ((ind = stringOpens.indexOf(currentChar)) != -1 && !escaped && contextMarker == Character.MIN_VALUE) {
markerTypeFound = ind;
contextMarker = currentChar;
}
if (contextMarker == Character.MIN_VALUE && currentChar == '/' && (slashSlashComments || slashStarComments)) {
currentChar = sourceReader.read();
if (currentChar == '*' && slashStarComments) {
int prevChar = 0;
while ((currentChar = sourceReader.read()) != '/' || prevChar != '*') {
if (currentChar == '\r') {
currentChar = sourceReader.read();
if (currentChar == '\n') {
currentChar = sourceReader.read();
}
} else {
if (currentChar == '\n') {
currentChar = sourceReader.read();
}
}
if (currentChar < 0) {
break;
}
prevChar = currentChar;
}
continue;
} else if (currentChar == '/' && slashSlashComments) {
while ((currentChar = sourceReader.read()) != '\n' && currentChar != '\r' && currentChar >= 0) {
}
}
} else if (contextMarker == Character.MIN_VALUE && currentChar == '#' && hashComments) {
// Slurp up everything until the newline
while ((currentChar = sourceReader.read()) != '\n' && currentChar != '\r' && currentChar >= 0) {
}
} else if (contextMarker == Character.MIN_VALUE && currentChar == '-' && dashDashComments) {
currentChar = sourceReader.read();
if (currentChar == -1 || currentChar != '-') {
strBuilder.append('-');
if (currentChar != -1) {
strBuilder.append((char) currentChar);
}
continue;
}
// Slurp up everything until the newline
while ((currentChar = sourceReader.read()) != '\n' && currentChar != '\r' && currentChar >= 0) {
}
}
if (currentChar != -1) {
strBuilder.append((char) currentChar);
}
}
} catch (IOException ioEx) {
// we'll never see this from a StringReader
}
return strBuilder.toString();
}
}
Description: CallableStatement.extractProcedureName() don't work correct when procedure name with dash "-" How to repeat: import com.mysql.jdbc.StringUtils; import com.mysql.jdbc.util.BaseBugReport; public class MyBugReport extends BaseBugReport{ @Override public void setUp() throws Exception {} @Override public void tearDown() throws Exception {} @Override public void runTest() throws Exception { String originalSql= "CALL a-bug.proc_stock(?,?)"; //mysql-connector-java 5.1.40 //com.mysql.jdbc.CallableStatement.extractProcedureName() String sanitizedSql = StringUtils.stripComments(originalSql, "`\"'", "`\"'", true, false, true, true); assertTrue("\""+sanitizedSql+"\" should be equal to \""+originalSql+"\"", originalSql.equals(sanitizedSql)); } public static void main(String[] args) throws Exception { new MyBugReport().run(); } } Suggested fix: package com.mysql.jdbc; public class StringUtils { public static String stripComments(String src, String stringOpens, String stringCloses, boolean slashStarComments, boolean slashSlashComments, boolean hashComments, boolean dashDashComments) { if (src == null) { return null; } StringBuilder strBuilder = new StringBuilder(src.length()); // It's just more natural to deal with this as a stream when parsing..This code is currently only called when parsing the kind of metadata that // developers are strongly recommended to cache anyways, so we're not worried about the _1_ extra object allocation if it cleans up the code StringReader sourceReader = new StringReader(src); int contextMarker = Character.MIN_VALUE; boolean escaped = false; int markerTypeFound = -1; int ind = 0; int currentChar = 0; try { while ((currentChar = sourceReader.read()) != -1) { if (markerTypeFound != -1 && currentChar == stringCloses.charAt(markerTypeFound) && !escaped) { contextMarker = Character.MIN_VALUE; markerTypeFound = -1; } else if ((ind = stringOpens.indexOf(currentChar)) != -1 && !escaped && contextMarker == Character.MIN_VALUE) { markerTypeFound = ind; contextMarker = currentChar; } if (contextMarker == Character.MIN_VALUE && currentChar == '/' && (slashSlashComments || slashStarComments)) { currentChar = sourceReader.read(); if (currentChar == '*' && slashStarComments) { int prevChar = 0; while ((currentChar = sourceReader.read()) != '/' || prevChar != '*') { if (currentChar == '\r') { currentChar = sourceReader.read(); if (currentChar == '\n') { currentChar = sourceReader.read(); } } else { if (currentChar == '\n') { currentChar = sourceReader.read(); } } if (currentChar < 0) { break; } prevChar = currentChar; } continue; } else if (currentChar == '/' && slashSlashComments) { while ((currentChar = sourceReader.read()) != '\n' && currentChar != '\r' && currentChar >= 0) { } } } else if (contextMarker == Character.MIN_VALUE && currentChar == '#' && hashComments) { // Slurp up everything until the newline while ((currentChar = sourceReader.read()) != '\n' && currentChar != '\r' && currentChar >= 0) { } } else if (contextMarker == Character.MIN_VALUE && currentChar == '-' && dashDashComments) { currentChar = sourceReader.read(); if (currentChar == -1 || currentChar != '-') { strBuilder.append('-'); if (currentChar != -1) { strBuilder.append((char) currentChar); } continue; } // Slurp up everything until the newline while ((currentChar = sourceReader.read()) != '\n' && currentChar != '\r' && currentChar >= 0) { } } if (currentChar != -1) { strBuilder.append((char) currentChar); } } } catch (IOException ioEx) { // we'll never see this from a StringReader } return strBuilder.toString(); } }