Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: improve parsing performance of JDBC-style { call ...} calls #1233

Merged
merged 1 commit into from Jul 1, 2018
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.
+36 −15
Diff settings

Always

Just for now

add some tests on Parser#modifyJdbcCall

small optimization on Parser#modifyJdbcCall
remove support for version < 8.1 in Parser#modifyJdbcCall
  • Loading branch information...
benbenw committed Jun 30, 2018
commit 7978cc75209be8b23d90aaec477db5094649aff3
@@ -862,7 +862,7 @@ public static JdbcCallParseInfo modifyJdbcCall(String jdbcSql, boolean stdString
// RE: frequently used statements are cached (see {@link org.postgresql.jdbc.PgConnection#borrowQuery}), so this "merge" is not that important.
String sql = jdbcSql;
boolean isFunction = false;
boolean outParmBeforeFunc = false;
boolean outParamBeforeFunc = false;

int len = jdbcSql.length();
int state = 1;
@@ -891,7 +891,7 @@ public static JdbcCallParseInfo modifyJdbcCall(String jdbcSql, boolean stdString

case 2: // After {, looking for ? or =, skipping whitespace
if (ch == '?') {
outParmBeforeFunc =
outParamBeforeFunc =
isFunction = true; // { ? = call ... } -- function with one out parameter
++i;
++state;
@@ -1007,35 +1007,47 @@ public static JdbcCallParseInfo modifyJdbcCall(String jdbcSql, boolean stdString
PSQLState.STATEMENT_NOT_ALLOWED_IN_FUNCTION_CALL);
}

if (serverVersion < 80100 /* 8.1 */ || protocolVersion != 3) {
sql = "select " + jdbcSql.substring(startIndex, endIndex) + " as result";
return new JdbcCallParseInfo(sql, isFunction);
}
String prefix = "select * from ";
String suffix = " as result";

String s = jdbcSql.substring(startIndex, endIndex);
StringBuilder sb = new StringBuilder(s);
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(outParmBeforeFunc ? "(?)" : "()");
} else if (outParmBeforeFunc) {
// here the function call has no parameters declaration eg : "{ ? = call pack_getValue}"
sb.append(outParamBeforeFunc ? "(?)" : "()");
} else if (outParamBeforeFunc) {
// move the single out parameter into the function call
// so that it can be treated like all other parameters
boolean needComma = false;

int closing = s.indexOf(')', opening);
for (int j = opening; j < closing; j++) {
if (!Character.isWhitespace(sb.charAt(j))) {
// the following loop will check if the function call has parameters
// eg "{ ? = call pack_getValue(?) }" vs "{ ? = call pack_getValue() }
for (int j = opening + prefixLength; j < sb.length(); j++) {
char c = sb.charAt(j);
if (c == ')') {
break;
}

if (!Character.isWhitespace(c)) {
needComma = true;
break;
}
}

// insert the return parameter as the first parameter of the function call
if (needComma) {
sb.insert(opening, "?,");
sb.insert(opening + prefixLength, "?,");
} else {
sb.insert(opening, "?");
sb.insert(opening + prefixLength, "?");
}
}
sql = "select * from " + sb.toString() + " as result";

sql = sb.append(suffix).toString();
return new JdbcCallParseInfo(sql, isFunction);
}

@@ -134,6 +134,15 @@ public void testEscapeProcessing() throws Exception {
assertEquals("{obj : 1}", Parser.replaceProcessing("{obj : 1}", true, false));
}

@Test
public void testModifyJdbcCall() throws SQLException {
assertEquals("select * from pack_getValue(?) as result", Parser.modifyJdbcCall("{ ? = call pack_getValue}", true, ServerVersion.v9_6.getVersionNum(), 3).getSql());
assertEquals("select * from pack_getValue(?,?) as result", Parser.modifyJdbcCall("{ ? = call pack_getValue(?) }", true, ServerVersion.v9_6.getVersionNum(), 3).getSql());
assertEquals("select * from pack_getValue(?) as result", Parser.modifyJdbcCall("{ ? = call pack_getValue()}", true, ServerVersion.v9_6.getVersionNum(), 3).getSql());
assertEquals("select * from pack_getValue(?,?,?,?) as result", Parser.modifyJdbcCall("{ ? = call pack_getValue(?,?,?) }", true, ServerVersion.v9_6.getVersionNum(), 3).getSql());
assertEquals("select * from lower(?,?) as result", Parser.modifyJdbcCall("{ ? = call lower(?)}", true, ServerVersion.v9_6.getVersionNum(), 3).getSql());
}

@Test
public void testUnterminatedEscape() throws Exception {
assertEquals("{oj ", Parser.replaceProcessing("{oj ", true, false));
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.