in src/main/user-impl/java/com/mysql/cj/jdbc/EscapeProcessor.java [93:297]
public static final Object escapeSQL(String sql, TimeZone connectionTimeZone, boolean serverSupportsFractionalSecond,
boolean serverTruncatesFractionalSecond, ExceptionInterceptor exceptionInterceptor) throws java.sql.SQLException {
boolean replaceEscapeSequence = false;
String escapeSequence = null;
if (sql == null) {
return null;
}
/*
* Short circuit this code if we don't have a matching pair of "{}". - Suggested by Ryan Gustafason
*/
int beginBrace = sql.indexOf('{');
int nextEndBrace = beginBrace == -1 ? -1 : sql.indexOf('}', beginBrace);
if (nextEndBrace == -1) {
return sql;
}
StringBuilder newSql = new StringBuilder();
EscapeTokenizer escapeTokenizer = new EscapeTokenizer(sql);
byte usesVariables = StatementImpl.USES_VARIABLES_FALSE;
boolean callingStoredFunction = false;
while (escapeTokenizer.hasMoreTokens()) {
String token = escapeTokenizer.nextToken();
if (token.length() != 0) {
if (token.charAt(0) == '{') { // It's an escape code
if (!token.endsWith("}")) {
throw SQLError.createSQLException(Messages.getString("EscapeProcessor.0", new Object[] { token }), exceptionInterceptor);
}
if (token.length() > 2) {
int nestedBrace = token.indexOf('{', 2);
if (nestedBrace != -1) {
StringBuilder buf = new StringBuilder(token.substring(0, 1));
Object remainingResults = escapeSQL(token.substring(1, token.length() - 1), connectionTimeZone, serverSupportsFractionalSecond,
serverTruncatesFractionalSecond, exceptionInterceptor);
String remaining = null;
if (remainingResults instanceof String) {
remaining = (String) remainingResults;
} else {
remaining = ((EscapeProcessorResult) remainingResults).escapedSql;
if (usesVariables != StatementImpl.USES_VARIABLES_TRUE) {
usesVariables = ((EscapeProcessorResult) remainingResults).usesVariables;
}
}
buf.append(remaining);
buf.append('}');
token = buf.toString();
}
}
// nested escape code
// Compare to tokens with _no_ whitespace
String collapsedToken = removeWhitespace(token);
/*
* Process the escape code
*/
if (StringUtils.startsWithIgnoreCase(collapsedToken, "{escape")) {
try {
StringTokenizer st = new StringTokenizer(token, " '");
st.nextToken(); // eat the "escape" token
escapeSequence = st.nextToken();
if (escapeSequence.length() < 3) {
newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders
} else {
escapeSequence = escapeSequence.substring(1, escapeSequence.length() - 1);
replaceEscapeSequence = true;
}
} catch (java.util.NoSuchElementException e) {
newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders
}
} else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{fn")) {
int startPos = token.toLowerCase().indexOf("fn") + 2;
if (token.charAt(startPos) == ' ') {
startPos++;
}
int endPos = token.length() - 1; // no }
String fnToken = token.substring(startPos, endPos);
// We need to handle 'convert' by ourselves
if (StringUtils.startsWithIgnoreCaseAndWs(fnToken, "convert")) {
newSql.append(processConvertToken(fnToken, exceptionInterceptor));
} else {
// just pass functions right to the DB
newSql.append(fnToken);
}
} else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{d")) {
int startPos = token.indexOf('\'') + 1;
int endPos = token.lastIndexOf('\''); // no }
if (startPos == -1 || endPos == -1) {
newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders
} else {
String argument = token.substring(startPos, endPos);
try {
StringTokenizer st = new StringTokenizer(argument, " -");
String year4 = st.nextToken();
String month2 = st.nextToken();
String day2 = st.nextToken();
String dateString = "'" + year4 + "-" + month2 + "-" + day2 + "'";
newSql.append(dateString);
} catch (java.util.NoSuchElementException e) {
throw SQLError.createSQLException(Messages.getString("EscapeProcessor.1", new Object[] { argument }),
MysqlErrorNumbers.SQLSTATE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION_NO_SUBCLASS, exceptionInterceptor);
}
}
} else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{ts")) {
processTimestampToken(connectionTimeZone, newSql, token, serverSupportsFractionalSecond, serverTruncatesFractionalSecond,
exceptionInterceptor);
} else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{t")) {
processTimeToken(newSql, token, serverSupportsFractionalSecond, exceptionInterceptor);
} else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{call") || StringUtils.startsWithIgnoreCase(collapsedToken, "{?=call")) {
int startPos = StringUtils.indexOfIgnoreCase(token, "CALL") + 5;
int endPos = token.length() - 1;
if (StringUtils.startsWithIgnoreCase(collapsedToken, "{?=call")) {
callingStoredFunction = true;
newSql.append("SELECT ");
newSql.append(token.substring(startPos, endPos));
} else {
callingStoredFunction = false;
newSql.append("CALL ");
newSql.append(token.substring(startPos, endPos));
}
for (int i = endPos - 1; i >= startPos; i--) {
char c = token.charAt(i);
if (Character.isWhitespace(c)) {
continue;
}
if (c != ')') {
newSql.append("()"); // handle no-parenthesis no-arg call not supported by MySQL parser
}
break;
}
} else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{oj")) {
// MySQL already handles this escape sequence because of ODBC. Cool.
newSql.append(token);
} else {
// not an escape code, just part of the query
newSql.append(token);
}
} else {
newSql.append(token); // it's just part of the query
}
}
}
String escapedSql = newSql.toString();
//
// FIXME: Let MySQL do this, however requires lightweight parsing of statement
//
if (replaceEscapeSequence) {
String currentSql = escapedSql;
while (currentSql.indexOf(escapeSequence) != -1) {
int escapePos = currentSql.indexOf(escapeSequence);
String lhs = currentSql.substring(0, escapePos);
String rhs = currentSql.substring(escapePos + 1, currentSql.length());
currentSql = lhs + "\\" + rhs;
}
escapedSql = currentSql;
}
EscapeProcessorResult epr = new EscapeProcessorResult();
epr.escapedSql = escapedSql;
epr.callingStoredFunction = callingStoredFunction;
if (usesVariables != StatementImpl.USES_VARIABLES_TRUE) {
if (escapeTokenizer.sawVariableUse()) {
epr.usesVariables = StatementImpl.USES_VARIABLES_TRUE;
} else {
epr.usesVariables = StatementImpl.USES_VARIABLES_FALSE;
}
}
return epr;
}