in src/main/core-api/java/com/mysql/cj/ParseInfo.java [96:289]
public ParseInfo(String sql, Session session, String encoding, boolean buildRewriteInfo) {
try {
if (sql == null) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("PreparedStatement.61"),
session.getExceptionInterceptor());
}
this.charEncoding = encoding;
this.lastUsed = System.currentTimeMillis();
String quotedIdentifierString = session.getIdentifierQuoteString();
char quotedIdentifierChar = 0;
if ((quotedIdentifierString != null) && !quotedIdentifierString.equals(" ") && (quotedIdentifierString.length() > 0)) {
quotedIdentifierChar = quotedIdentifierString.charAt(0);
}
this.statementLength = sql.length();
ArrayList<int[]> endpointList = new ArrayList<>();
boolean inQuotes = false;
char quoteChar = 0;
boolean inQuotedId = false;
int lastParmEnd = 0;
int i;
boolean noBackslashEscapes = session.getServerSession().isNoBackslashEscapesSet();
// we're not trying to be real pedantic here, but we'd like to skip comments at the beginning of statements, as frameworks such as Hibernate
// use them to aid in debugging
this.statementStartPos = findStartOfStatement(sql);
for (i = this.statementStartPos; i < this.statementLength; ++i) {
char c = sql.charAt(i);
if ((this.firstStmtChar == 0) && Character.isLetter(c)) {
// Determine what kind of statement we're doing (_S_elect, _I_nsert, etc.)
this.firstStmtChar = Character.toUpperCase(c);
// no need to search for "ON DUPLICATE KEY UPDATE" if not an INSERT statement
if (this.firstStmtChar == 'I') {
this.locationOfOnDuplicateKeyUpdate = getOnDuplicateKeyLocation(sql,
session.getPropertySet().getBooleanProperty(PropertyKey.dontCheckOnDuplicateKeyUpdateInSQL).getValue(),
session.getPropertySet().getBooleanProperty(PropertyKey.rewriteBatchedStatements).getValue(),
session.getServerSession().isNoBackslashEscapesSet());
this.isOnDuplicateKeyUpdate = this.locationOfOnDuplicateKeyUpdate != -1;
}
}
if (!noBackslashEscapes && c == '\\' && i < (this.statementLength - 1)) {
i++;
continue; // next character is escaped
}
// are we in a quoted identifier? (only valid when the id is not inside a 'string')
if (!inQuotes && (quotedIdentifierChar != 0) && (c == quotedIdentifierChar)) {
inQuotedId = !inQuotedId;
} else if (!inQuotedId) {
// only respect quotes when not in a quoted identifier
if (inQuotes) {
if (((c == '\'') || (c == '"')) && c == quoteChar) {
if (i < (this.statementLength - 1) && sql.charAt(i + 1) == quoteChar) {
i++;
continue; // inline quote escape
}
inQuotes = !inQuotes;
quoteChar = 0;
} else if (((c == '\'') || (c == '"')) && c == quoteChar) {
inQuotes = !inQuotes;
quoteChar = 0;
}
} else {
if (c == '#' || (c == '-' && (i + 1) < this.statementLength && sql.charAt(i + 1) == '-')) {
// run out to end of statement, or newline, whichever comes first
int endOfStmt = this.statementLength - 1;
for (; i < endOfStmt; i++) {
c = sql.charAt(i);
if (c == '\r' || c == '\n') {
break;
}
}
continue;
} else if (c == '/' && (i + 1) < this.statementLength) {
// Comment?
char cNext = sql.charAt(i + 1);
if (cNext == '*') {
i += 2;
for (int j = i; j < this.statementLength; j++) {
i++;
cNext = sql.charAt(j);
if (cNext == '*' && (j + 1) < this.statementLength) {
if (sql.charAt(j + 1) == '/') {
i++;
if (i < this.statementLength) {
c = sql.charAt(i);
}
break; // comment done
}
}
}
}
} else if ((c == '\'') || (c == '"')) {
inQuotes = true;
quoteChar = c;
}
}
}
if (!inQuotes && !inQuotedId) {
if ((c == '?')) {
endpointList.add(new int[] { lastParmEnd, i });
lastParmEnd = i + 1;
if (this.isOnDuplicateKeyUpdate && i > this.locationOfOnDuplicateKeyUpdate) {
this.parametersInDuplicateKeyClause = true;
}
} else if (c == ';') {
int j = i + 1;
if (j < this.statementLength) {
for (; j < this.statementLength; j++) {
if (!Character.isWhitespace(sql.charAt(j))) {
break;
}
}
if (j < this.statementLength) {
this.numberOfQueries++;
}
i = j - 1;
}
}
}
}
if (this.firstStmtChar == 'L') {
if (StringUtils.startsWithIgnoreCaseAndWs(sql, "LOAD DATA")) {
this.foundLoadData = true;
} else {
this.foundLoadData = false;
}
} else {
this.foundLoadData = false;
}
endpointList.add(new int[] { lastParmEnd, this.statementLength });
this.staticSql = new byte[endpointList.size()][];
this.hasPlaceholders = this.staticSql.length > 1;
for (i = 0; i < this.staticSql.length; i++) {
int[] ep = endpointList.get(i);
int end = ep[1];
int begin = ep[0];
int len = end - begin;
if (this.foundLoadData) {
this.staticSql[i] = StringUtils.getBytes(sql, begin, len);
} else if (encoding == null) {
byte[] buf = new byte[len];
for (int j = 0; j < len; j++) {
buf[j] = (byte) sql.charAt(begin + j);
}
this.staticSql[i] = buf;
} else {
this.staticSql[i] = StringUtils.getBytes(sql, begin, len, encoding);
}
}
} catch (StringIndexOutOfBoundsException oobEx) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("PreparedStatement.62", new Object[] { sql }), oobEx,
session.getExceptionInterceptor());
}
if (buildRewriteInfo) {
this.canRewriteAsMultiValueInsert = this.numberOfQueries == 1 && !this.parametersInDuplicateKeyClause
&& canRewrite(sql, this.isOnDuplicateKeyUpdate, this.locationOfOnDuplicateKeyUpdate, this.statementStartPos);
if (this.canRewriteAsMultiValueInsert && session.getPropertySet().getBooleanProperty(PropertyKey.rewriteBatchedStatements).getValue()) {
buildRewriteBatchedParams(sql, session, encoding);
}
}
}