in src/main/java/org/mariadb/jdbc/internal/util/dao/ClientPrepareResult.java [373:652]
public static ClientPrepareResult rewritableParts(
String queryString, boolean noBackslashEscapes) {
boolean reWritablePrepare = true;
boolean multipleQueriesPrepare = true;
List<byte[]> partList = new ArrayList<>();
LexState state = LexState.Normal;
char lastChar = '\0';
StringBuilder sb = new StringBuilder();
String preValuePart1 = null;
String preValuePart2 = null;
String postValuePart = null;
boolean singleQuotes = false;
int isInParenthesis = 0;
boolean skipChar = false;
boolean isFirstChar = true;
boolean isInsert = false;
boolean semicolon = false;
boolean hasParam = false;
char[] query = queryString.toCharArray();
int queryLength = query.length;
for (int i = 0; i < queryLength; i++) {
char car = query[i];
if (state == LexState.Escape
&& !((car == '\'' && singleQuotes) || (car == '"' && !singleQuotes))) {
sb.append(car);
lastChar = car;
state = LexState.String;
continue;
}
switch (car) {
case '*':
if (state == LexState.Normal && lastChar == '/') {
state = LexState.SlashStarComment;
}
break;
case '/':
if (state == LexState.SlashStarComment && lastChar == '*') {
state = LexState.Normal;
}
break;
case '#':
if (state == LexState.Normal) {
state = LexState.EOLComment;
}
break;
case '-':
if (state == LexState.Normal && lastChar == '-') {
state = LexState.EOLComment;
multipleQueriesPrepare = false;
}
break;
case '\n':
if (state == LexState.EOLComment) {
state = LexState.Normal;
}
break;
case '"':
if (state == LexState.Normal) {
state = LexState.String;
singleQuotes = false;
} else if (state == LexState.String && !singleQuotes) {
state = LexState.Normal;
} else if (state == LexState.Escape && !singleQuotes) {
state = LexState.String;
}
break;
case ';':
if (state == LexState.Normal) {
semicolon = true;
multipleQueriesPrepare = false;
}
break;
case '\'':
if (state == LexState.Normal) {
state = LexState.String;
singleQuotes = true;
} else if (state == LexState.String && singleQuotes) {
state = LexState.Normal;
} else if (state == LexState.Escape && singleQuotes) {
state = LexState.String;
}
break;
case '\\':
if (noBackslashEscapes) {
break;
}
if (state == LexState.String) {
state = LexState.Escape;
}
break;
case '?':
if (state == LexState.Normal) {
hasParam = true;
if (preValuePart1 == null) {
preValuePart1 = sb.toString();
sb.setLength(0);
}
if (preValuePart2 == null) {
preValuePart2 = sb.toString();
sb.setLength(0);
} else {
if (postValuePart != null) {
// having parameters after the last ")" of value is not rewritable
reWritablePrepare = false;
// add part
sb.insert(0, postValuePart);
postValuePart = null;
}
partList.add(sb.toString().getBytes(StandardCharsets.UTF_8));
sb.setLength(0);
}
skipChar = true;
}
break;
case '`':
if (state == LexState.Backtick) {
state = LexState.Normal;
} else if (state == LexState.Normal) {
state = LexState.Backtick;
}
break;
case 's':
case 'S':
if (state == LexState.Normal
&& postValuePart == null
&& queryLength > i + 7
&& (query[i + 1] == 'e' || query[i + 1] == 'E')
&& (query[i + 2] == 'l' || query[i + 2] == 'L')
&& (query[i + 3] == 'e' || query[i + 3] == 'E')
&& (query[i + 4] == 'c' || query[i + 4] == 'C')
&& (query[i + 5] == 't' || query[i + 5] == 'T')) {
// field/table name might contain 'select'
if (i > 0 && (query[i - 1] > ' ' && "();><=-+,".indexOf(query[i - 1]) == -1)) {
break;
}
if (query[i + 6] > ' ' && "();><=-+,".indexOf(query[i + 6]) == -1) {
break;
}
// SELECT queries, INSERT FROM SELECT not rewritable
reWritablePrepare = false;
}
break;
case 'v':
case 'V':
if (state == LexState.Normal
&& preValuePart1 == null
&& (lastChar == ')' || ((byte) lastChar <= 40))
&& queryLength > i + 7
&& (query[i + 1] == 'a' || query[i + 1] == 'A')
&& (query[i + 2] == 'l' || query[i + 2] == 'L')
&& (query[i + 3] == 'u' || query[i + 3] == 'U')
&& (query[i + 4] == 'e' || query[i + 4] == 'E')
&& (query[i + 5] == 's' || query[i + 5] == 'S')
&& (query[i + 6] == '(' || ((byte) query[i + 6] <= 40))) {
sb.append(car);
sb.append(query[i + 1]);
sb.append(query[i + 2]);
sb.append(query[i + 3]);
sb.append(query[i + 4]);
sb.append(query[i + 5]);
i = i + 5;
preValuePart1 = sb.toString();
sb.setLength(0);
skipChar = true;
}
break;
case 'l':
case 'L':
if (state == LexState.Normal
&& queryLength > i + 14
&& (query[i + 1] == 'a' || query[i + 1] == 'A')
&& (query[i + 2] == 's' || query[i + 2] == 'S')
&& (query[i + 3] == 't' || query[i + 3] == 'T')
&& query[i + 4] == '_'
&& (query[i + 5] == 'i' || query[i + 5] == 'I')
&& (query[i + 6] == 'n' || query[i + 6] == 'N')
&& (query[i + 7] == 's' || query[i + 7] == 'S')
&& (query[i + 8] == 'e' || query[i + 8] == 'E')
&& (query[i + 9] == 'r' || query[i + 9] == 'R')
&& (query[i + 10] == 't' || query[i + 10] == 'T')
&& query[i + 11] == '_'
&& (query[i + 12] == 'i' || query[i + 12] == 'I')
&& (query[i + 13] == 'd' || query[i + 13] == 'D')
&& query[i + 14] == '(') {
sb.append(car);
reWritablePrepare = false;
skipChar = true;
}
break;
case '(':
if (state == LexState.Normal) {
isInParenthesis++;
}
break;
case ')':
if (state == LexState.Normal) {
isInParenthesis--;
if (isInParenthesis == 0 && preValuePart2 != null && postValuePart == null) {
sb.append(car);
postValuePart = sb.toString();
sb.setLength(0);
skipChar = true;
}
}
break;
default:
if (state == LexState.Normal && isFirstChar && ((byte) car >= 40)) {
if (car == 'I' || car == 'i') {
isInsert = true;
}
isFirstChar = false;
}
// multiple queries
if (state == LexState.Normal && semicolon && ((byte) car >= 40)) {
reWritablePrepare = false;
multipleQueriesPrepare = true;
}
break;
}
lastChar = car;
if (skipChar) {
skipChar = false;
} else {
sb.append(car);
}
}
if (!hasParam) {
// permit to have rewrite without parameter
if (preValuePart1 == null) {
partList.add(0, sb.toString().getBytes(StandardCharsets.UTF_8));
partList.add(1, new byte[0]);
} else {
partList.add(0, preValuePart1.getBytes(StandardCharsets.UTF_8));
partList.add(1, sb.toString().getBytes(StandardCharsets.UTF_8));
}
sb.setLength(0);
} else {
partList.add(
0,
(preValuePart1 == null) ? new byte[0] : preValuePart1.getBytes(StandardCharsets.UTF_8));
partList.add(
1,
(preValuePart2 == null) ? new byte[0] : preValuePart2.getBytes(StandardCharsets.UTF_8));
}
if (!isInsert) {
reWritablePrepare = false;
}
// postValuePart is the value after the last parameter and parenthesis
// if no param, don't add to the list.
if (hasParam) {
partList.add(
(postValuePart == null) ? new byte[0] : postValuePart.getBytes(StandardCharsets.UTF_8));
}
partList.add(sb.toString().getBytes(StandardCharsets.UTF_8));
return new ClientPrepareResult(
queryString, partList, reWritablePrepare, multipleQueriesPrepare, true);
}