docs: public static List<NativeQuery> parseJdbcSql(String query, boolean standardConformingStrings,
        boolean withParameters, boolean splitStatements,
        boolean isBatchedReWriteConfigured,
        String... returningColumnNames) throws SQLException {
      if (!withParameters && !splitStatements
          && returningColumnNames != null && returningColumnNames.length == 0) {
        return Collections.singletonList(new NativeQuery(query,
          SqlCommand.createStatementTypeInfo(SqlCommandType.BLANK)));
      }
  
      int fragmentStart = 0;
      int inParen = 0;
  
      char[] aChars = query.toCharArray();
  
      StringBuilder nativeSql = new StringBuilder(query.length() + 10);
      List<Integer> bindPositions = null; // initialized on demand
      List<NativeQuery> nativeQueries = null;
      boolean isCurrentReWriteCompatible = false;
      boolean isValuesFound = false;
      int valuesBraceOpenPosition = -1;
      int valuesBraceClosePosition = -1;
      boolean valuesBraceCloseFound = false;
      boolean isInsertPresent = false;
      boolean isReturningPresent = false;
      boolean isReturningPresentPrev = false;
      SqlCommandType currentCommandType = SqlCommandType.BLANK;
      SqlCommandType prevCommandType = SqlCommandType.BLANK;
      int numberOfStatements = 0;
  
      boolean whitespaceOnly = true;
      int keyWordCount = 0;
      int keywordStart = -1;
      int keywordEnd = -1;
      for (int i = 0; i < aChars.length; ++i) {
        char aChar = aChars[i];
        boolean isKeyWordChar = false;
        // ';' is ignored as it splits the queries
        whitespaceOnly &= aChar == ';' || Character.isWhitespace(aChar);
        keywordEnd = i; // parseSingleQuotes, parseDoubleQuotes, etc move index so we keep old value
        switch (aChar) {
          case '\'': // single-quotes
            i = Parser.parseSingleQuotes(aChars, i, standardConformingStrings);
            break;
  
          case '"': // double-quotes
            i = Parser.parseDoubleQuotes(aChars, i);
            break;
  
          case '-': // possibly -- style comment
            i = Parser.parseLineComment(aChars, i);
            break;
  
          case '/': // possibly /* */ style comment
            i = Parser.parseBlockComment(aChars, i);
            break;
  
          case '$': // possibly dollar quote start
            i = Parser.parseDollarQuotes(aChars, i);
            break;
  
          // case '(' moved below to parse "values(" properly
  
          case ')':
            inParen--;
            if (inParen == 0 && isValuesFound && !valuesBraceCloseFound) {
              // If original statement is multi-values like VALUES (...), (...), ... then
              // search for the latest closing paren
              valuesBraceClosePosition = nativeSql.length() + i - fragmentStart;
            }
            break;
  
          case '?':
            nativeSql.append(aChars, fragmentStart, i - fragmentStart);
            if (i + 1 < aChars.length && aChars[i + 1] == '?') /* replace ?? with ? */ {
              nativeSql.append('?');
              i++; // make sure the coming ? is not treated as a bind
            } else {
              if (!withParameters) {
                nativeSql.append('?');
              } else {
                if (bindPositions == null) {
                  bindPositions = new ArrayList<Integer>();
                }
                bindPositions.add(nativeSql.length());
                int bindIndex = bindPositions.size();
                nativeSql.append(NativeQuery.bindName(bindIndex));
              }
            }
            fragmentStart = i + 1;
            break;
  
          case ';':
            if (inParen == 0) {
              if (!whitespaceOnly) {
                numberOfStatements++;
                nativeSql.append(aChars, fragmentStart, i - fragmentStart);
                whitespaceOnly = true;
              }
              fragmentStart = i + 1;
              if (nativeSql.length() > 0) {
                if (addReturning(nativeSql, currentCommandType, returningColumnNames, isReturningPresent)) {
                  isReturningPresent = true;
                }
  
                if (splitStatements) {
                  if (nativeQueries == null) {
                    nativeQueries = new ArrayList<NativeQuery>();
                  }
  
                  if (!isValuesFound || !isCurrentReWriteCompatible || valuesBraceClosePosition == -1
                      || (bindPositions != null
                      && valuesBraceClosePosition < bindPositions.get(bindPositions.size() - 1))) {
                    valuesBraceOpenPosition = -1;
                    valuesBraceClosePosition = -1;
                  }
  
                  nativeQueries.add(new NativeQuery(nativeSql.toString(),
                      toIntArray(bindPositions), false,
                      SqlCommand.createStatementTypeInfo(
                          currentCommandType, isBatchedReWriteConfigured, valuesBraceOpenPosition,
                          valuesBraceClosePosition,
                          isReturningPresent, nativeQueries.size())));
                }
              }
              prevCommandType = currentCommandType;
              isReturningPresentPrev = isReturningPresent;
              currentCommandType = SqlCommandType.BLANK;
              isReturningPresent = false;
              if (splitStatements) {
                // Prepare for next query
                if (bindPositions != null) {
                  bindPositions.clear();
                }
                nativeSql.setLength(0);
                isValuesFound = false;
                isCurrentReWriteCompatible = false;
                valuesBraceOpenPosition = -1;
                valuesBraceClosePosition = -1;
                valuesBraceCloseFound = false;
              }
            }
            break;
  
          default:
            if (keywordStart >= 0) {
              // When we are inside a keyword, we need to detect keyword end boundary
              // Note that isKeyWordChar is initialized to false before the switch, so
              // all other characters would result in isKeyWordChar=false
              isKeyWordChar = isIdentifierContChar(aChar);
              break;
            }
            // Not in keyword, so just detect next keyword start
            isKeyWordChar = isIdentifierStartChar(aChar);
            if (isKeyWordChar) {
              keywordStart = i;
              if (valuesBraceOpenPosition != -1 && inParen == 0) {
                // When the statement already has multi-values, stop looking for more of them
                // Since values(?,?),(?,?),... should not contain keywords in the middle
                valuesBraceCloseFound = true;
              }
            }
            break;
        }
        if (keywordStart >= 0 && (i == aChars.length - 1 || !isKeyWordChar)) {
          int wordLength = (isKeyWordChar ? i + 1 : keywordEnd) - keywordStart;
          if (currentCommandType == SqlCommandType.BLANK) {
            if (wordLength == 6 && parseUpdateKeyword(aChars, keywordStart)) {
              currentCommandType = SqlCommandType.UPDATE;
            } else if (wordLength == 6 && parseDeleteKeyword(aChars, keywordStart)) {
              currentCommandType = SqlCommandType.DELETE;
            } else if (wordLength == 4 && parseMoveKeyword(aChars, keywordStart)) {
              currentCommandType = SqlCommandType.MOVE;
            } else if (wordLength == 6 && parseSelectKeyword(aChars, keywordStart)) {
              currentCommandType = SqlCommandType.SELECT;
            } else if (wordLength == 4 && parseWithKeyword(aChars, keywordStart)) {
              currentCommandType = SqlCommandType.WITH;
            } else if (wordLength == 6 && parseInsertKeyword(aChars, keywordStart)) {
              if (!isInsertPresent && (nativeQueries == null || nativeQueries.isEmpty())) {
                // Only allow rewrite for insert command starting with the insert keyword.
                // Else, too many risks of wrong interpretation.
                isCurrentReWriteCompatible = keyWordCount == 0;
                isInsertPresent = true;
                currentCommandType = SqlCommandType.INSERT;
              } else {
                isCurrentReWriteCompatible = false;
              }
            }
          } else if (currentCommandType == SqlCommandType.WITH
              && inParen == 0) {
            SqlCommandType command = parseWithCommandType(aChars, i, keywordStart, wordLength);
            if (command != null) {
              currentCommandType = command;
            }
          }
          if (inParen != 0 || aChar == ')') {
            // RETURNING and VALUES cannot be present in braces
          } else if (wordLength == 9 && parseReturningKeyword(aChars, keywordStart)) {
            isReturningPresent = true;
          } else if (wordLength == 6 && parseValuesKeyword(aChars, keywordStart)) {
            isValuesFound = true;
          }
          keywordStart = -1;
          keyWordCount++;
        }
        if (aChar == '(') {
          inParen++;
          if (inParen == 1 && isValuesFound && valuesBraceOpenPosition == -1) {
            valuesBraceOpenPosition = nativeSql.length() + i - fragmentStart;
          }
        }
      }
  
      if (!isValuesFound || !isCurrentReWriteCompatible || valuesBraceClosePosition == -1
          || (bindPositions != null
          && valuesBraceClosePosition < bindPositions.get(bindPositions.size() - 1))) {
        valuesBraceOpenPosition = -1;
        valuesBraceClosePosition = -1;
      }
  
      if (fragmentStart < aChars.length && !whitespaceOnly) {
        nativeSql.append(aChars, fragmentStart, aChars.length - fragmentStart);
      } else {
        if (numberOfStatements > 1) {
          isReturningPresent = false;
          currentCommandType = SqlCommandType.BLANK;
        } else if (numberOfStatements == 1) {
          isReturningPresent = isReturningPresentPrev;
          currentCommandType = prevCommandType;
        }
      }
  
      if (nativeSql.length() == 0) {
        return nativeQueries != null ? nativeQueries : Collections.<NativeQuery>emptyList();
      }
  
      if (addReturning(nativeSql, currentCommandType, returningColumnNames, isReturningPresent)) {
        isReturningPresent = true;
      }
  
      NativeQuery lastQuery = new NativeQuery(nativeSql.toString(),
          toIntArray(bindPositions), !splitStatements,
          SqlCommand.createStatementTypeInfo(currentCommandType,
              isBatchedReWriteConfigured, valuesBraceOpenPosition, valuesBraceClosePosition,
              isReturningPresent, (nativeQueries == null ? 0 : nativeQueries.size())));
  
      if (nativeQueries == null) {
        return Collections.singletonList(lastQuery);
      }
  
      if (!whitespaceOnly) {
        nativeQueries.add(lastQuery);
      }
      return nativeQueries;
    }