Parser { public static JdbcCallParseInfo modifyJdbcCall(String jdbcSql, boolean stdStrings, int serverVersion, int protocolVersion, EscapeSyntaxCallMode escapeSyntaxCallMode) throws SQLException { String sql = jdbcSql; boolean isFunction = false; boolean outParamBeforeFunc = false; int len = jdbcSql.length(); int state = 1; boolean inQuotes = false; boolean inEscape = false; int startIndex = -1; int endIndex = -1; boolean syntaxError = false; int i = 0; while (i < len && !syntaxError) { char ch = jdbcSql.charAt(i); switch (state) { case 1: if (ch == '{') { ++i; ++state; } else if (Character.isWhitespace(ch)) { ++i; } else { i = len; } break; case 2: if (ch == '?') { outParamBeforeFunc = isFunction = true; ++i; ++state; } else if (ch == 'c' || ch == 'C') { state += 3; } else if (Character.isWhitespace(ch)) { ++i; } else { syntaxError = true; } break; case 3: if (ch == '=') { ++i; ++state; } else if (Character.isWhitespace(ch)) { ++i; } else { syntaxError = true; } break; case 4: if (ch == 'c' || ch == 'C') { ++state; } else if (Character.isWhitespace(ch)) { ++i; } else { syntaxError = true; } break; case 5: if ((ch == 'c' || ch == 'C') && i + 4 <= len && jdbcSql.substring(i, i + 4) .equalsIgnoreCase("call")) { isFunction = true; i += 4; ++state; } else if (Character.isWhitespace(ch)) { ++i; } else { syntaxError = true; } break; case 6: if (Character.isWhitespace(ch)) { ++i; ++state; startIndex = i; } else { syntaxError = true; } break; case 7: if (ch == '\'') { inQuotes = !inQuotes; ++i; } else if (inQuotes && ch == '\\' && !stdStrings) { i += 2; } else if (!inQuotes && ch == '{') { inEscape = !inEscape; ++i; } else if (!inQuotes && ch == '}') { if (!inEscape) { endIndex = i; ++i; ++state; } else { inEscape = false; } } else if (!inQuotes && ch == ';') { syntaxError = true; } else { ++i; } break; case 8: if (Character.isWhitespace(ch)) { ++i; } else { syntaxError = true; } break; default: throw new IllegalStateException("somehow got into bad state " + state); } } if (i == len && !syntaxError) { if (state == 1) { i = 0; while (i < len && Character.isWhitespace(jdbcSql.charAt(i))) { i++; } if (i < len - 5) { char ch = jdbcSql.charAt(i); if ((ch == 'c' || ch == 'C') && jdbcSql.substring(i, i + 4).equalsIgnoreCase("call") && Character.isWhitespace(jdbcSql.charAt(i + 4))) { isFunction = true; } } return new JdbcCallParseInfo(sql, isFunction); } if (state != 8) { syntaxError = true; } } if (syntaxError) { throw new PSQLException( GT.tr("Malformed function or procedure escape syntax at offset {0}.", i), PSQLState.STATEMENT_NOT_ALLOWED_IN_FUNCTION_CALL); } String prefix; String suffix; if (escapeSyntaxCallMode == EscapeSyntaxCallMode.SELECT || serverVersion < 110000 || (outParamBeforeFunc && escapeSyntaxCallMode == EscapeSyntaxCallMode.CALL_IF_NO_RETURN)) { prefix = "select * from "; suffix = " as result"; } else { prefix = "call "; suffix = ""; } String s = jdbcSql.substring(startIndex, endIndex); int prefixLength = prefix.length(); StringBuilder sb = new StringBuilder(prefixLength + jdbcSql.length() + suffix.length() + 10); sb.append(prefix); sb.append(s); int opening = s.indexOf('(') + 1; if (opening == 0) { sb.append(outParamBeforeFunc ? "(?)" : "()"); } else if (outParamBeforeFunc) { boolean needComma = false; for (int j = opening + prefixLength; j < sb.length(); j++) { char c = sb.charAt(j); if (c == ')') { break; } if (!Character.isWhitespace(c)) { needComma = true; break; } } if (needComma) { sb.insert(opening + prefixLength, "?,"); } else { sb.insert(opening + prefixLength, "?"); } } if (!suffix.isEmpty()) { sql = sb.append(suffix).toString(); } else { sql = sb.toString(); } return new JdbcCallParseInfo(sql, isFunction); }  static List<NativeQuery> parseJdbcSql(String query, boolean standardConformingStrings,
      boolean withParameters, boolean splitStatements,
      boolean isBatchedReWriteConfigured,
      String... returningColumnNames); static int parseSingleQuotes(final char[] query, int offset,
      boolean standardConformingStrings); static int parseDoubleQuotes(final char[] query, int offset); static int parseDollarQuotes(final char[] query, int offset); static int parseLineComment(final char[] query, int offset); static int parseBlockComment(final char[] query, int offset); static boolean parseDeleteKeyword(final char[] query, int offset); static boolean parseInsertKeyword(final char[] query, int offset); static boolean parseMoveKeyword(final char[] query, int offset); static boolean parseReturningKeyword(final char[] query, int offset); static boolean parseSelectKeyword(final char[] query, int offset); static boolean parseUpdateKeyword(final char[] query, int offset); static boolean parseValuesKeyword(final char[] query, int offset); static long parseLong(String s, int beginIndex, int endIndex); static boolean parseWithKeyword(final char[] query, int offset); static boolean parseAsKeyword(final char[] query, int offset); static boolean isDigitAt(String s, int pos); static int digitAt(String s, int pos); static boolean isSpace(char c); static boolean isArrayWhiteSpace(char c); static boolean isOperatorChar(char c); static boolean isIdentifierStartChar(char c); static boolean isIdentifierContChar(char c); static boolean charTerminatesIdentifier(char c); static boolean isDollarQuoteStartChar(char c); static boolean isDollarQuoteContChar(char c); static JdbcCallParseInfo modifyJdbcCall(String jdbcSql, boolean stdStrings,
      int serverVersion, int protocolVersion, EscapeSyntaxCallMode escapeSyntaxCallMode); static String replaceProcessing(String sql, boolean replaceProcessingEnabled,
      boolean standardConformingStrings);  }
@Test public void testModifyJdbcCall() throws SQLException { assertEquals("select * from pack_getValue(?) as result", Parser.modifyJdbcCall("{ ? = call pack_getValue}", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.SELECT).getSql()); assertEquals("select * from pack_getValue(?,?) as result", Parser.modifyJdbcCall("{ ? = call pack_getValue(?) }", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.SELECT).getSql()); assertEquals("select * from pack_getValue(?) as result", Parser.modifyJdbcCall("{ ? = call pack_getValue()}", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.SELECT).getSql()); assertEquals("select * from pack_getValue(?,?,?,?) as result", Parser.modifyJdbcCall("{ ? = call pack_getValue(?,?,?) }", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.SELECT).getSql()); assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{ ? = call lower(?)}", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.SELECT).getSql()); assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{ ? = call lower(?)}", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.CALL_IF_NO_RETURN).getSql()); assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{ ? = call lower(?)}", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.CALL).getSql()); assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{call lower(?,?)}", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.SELECT).getSql()); assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{call lower(?,?)}", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.CALL_IF_NO_RETURN).getSql()); assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{call lower(?,?)}", true, ServerVersion.v9_6.getVersionNum(), 3, EscapeSyntaxCallMode.CALL).getSql()); assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{ ? = call lower(?)}", true, ServerVersion.v11.getVersionNum(), 3, EscapeSyntaxCallMode.SELECT).getSql()); assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{ ? = call lower(?)}", true, ServerVersion.v11.getVersionNum(), 3, EscapeSyntaxCallMode.CALL_IF_NO_RETURN).getSql()); assertEquals("call lower(?,?)", Parser.modifyJdbcCall("{ ? = call lower(?)}", true, ServerVersion.v11.getVersionNum(), 3, EscapeSyntaxCallMode.CALL).getSql()); assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{call lower(?,?)}", true, ServerVersion.v11.getVersionNum(), 3, EscapeSyntaxCallMode.SELECT).getSql()); assertEquals("call lower(?,?)", Parser.modifyJdbcCall("{call lower(?,?)}", true, ServerVersion.v11.getVersionNum(), 3, EscapeSyntaxCallMode.CALL_IF_NO_RETURN).getSql()); assertEquals("call lower(?,?)", Parser.modifyJdbcCall("{call lower(?,?)}", true, ServerVersion.v11.getVersionNum(), 3, EscapeSyntaxCallMode.CALL).getSql()); }