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 performance of replacing JDBC {...} escapes #1230

Merged
merged 11 commits into from Jun 29, 2018
@@ -5,7 +5,7 @@

package org.postgresql.core;

import org.postgresql.jdbc.EscapedFunctions;
import org.postgresql.jdbc.EscapedFunctions2;
import org.postgresql.util.GT;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
@@ -1179,25 +1179,7 @@ private static int parseSql(char[] p_sql, int i, StringBuilder newsql, boolean s

case ESC_FUNCTION:
// extract function name
String functionName;
int posArgs;
for (posArgs = i; posArgs < len && p_sql[posArgs] != '('; posArgs++) {
;
}
if (posArgs < len) {
functionName = new String(p_sql, i, posArgs - i).trim();
// extract arguments
i = posArgs + 1;// we start the scan after the first (
StringBuilder args = new StringBuilder();
i = parseSql(p_sql, i, args, false, stdStrings);
// translate the function and parse arguments
newsql.append(escapeFunction(functionName, args.toString(), stdStrings));
}
// go to the end of the function copying anything found
i++;
while (i < len && p_sql[i] != '}') {
newsql.append(p_sql[i++]);
}
i = escapeFunction(p_sql, i, newsql, stdStrings);
state = SqlParseState.IN_SQLCODE; // end of escaped function (or query)
break;
case ESC_DATE:
@@ -1216,6 +1198,14 @@ private static int parseSql(char[] p_sql, int i, StringBuilder newsql, boolean s
return i;
}

private static int findOpenBrace(char[] p_sql, int i) {
int posArgs;
for (posArgs = i; posArgs < p_sql.length && p_sql[posArgs] != '('; posArgs++) {
;
}
return posArgs;
}

private static void checkParsePosition(int i, int len, int i0, char[] p_sql,
String message)
throws PSQLException {
@@ -1227,54 +1217,72 @@ private static void checkParsePosition(int i, int len, int i0, char[] p_sql,
PSQLState.SYNTAX_ERROR);
}

private static int escapeFunction(char[] p_sql, int i, StringBuilder newsql, boolean stdStrings) throws SQLException {
String functionName;
int posArgs;
posArgs = findOpenBrace(p_sql, i);
if (posArgs < p_sql.length) {
functionName = new String(p_sql, i, posArgs - i).trim();
// extract arguments
i = posArgs + 1;// we start the scan after the first (
i = escapeFunctionArguments(newsql, functionName, p_sql, i, stdStrings);
}
// go to the end of the function copying anything found
i++;
while (i < p_sql.length && p_sql[i] != '}') {
newsql.append(p_sql[i++]);
}
return i;
}

/**
* generate sql for escaped functions
*
* @param newsql destination StringBuilder
* @param functionName the escaped function name
* @param args the arguments for this function
* @param p_sql input SQL text (containing arguments of a function call with possible JDBC escapes)
* @param i position in the input SQL
* @param stdStrings whether standard_conforming_strings is on
* @return the right postgreSql sql
* @return the right PostgreSQL sql
* @throws SQLException if something goes wrong
*/
private static String escapeFunction(String functionName, String args, boolean stdStrings)
private static int escapeFunctionArguments(StringBuilder newsql, String functionName, char[] p_sql, int i,
boolean stdStrings)
throws SQLException {
// parse function arguments
int len = args.length();
char[] argChars = args.toCharArray();
int i = 0;
ArrayList<StringBuilder> parsedArgs = new ArrayList<StringBuilder>();
while (i < len) {
// Maximum arity of functions in EscapedFunctions is 3
List<CharSequence> parsedArgs = new ArrayList<CharSequence>(3);
while (true) {
StringBuilder arg = new StringBuilder();
int lastPos = i;
i = parseSql(argChars, i, arg, true, stdStrings);
if (lastPos != i) {
i = parseSql(p_sql, i, arg, true, stdStrings);
if (i != lastPos) {
parsedArgs.add(arg);
}
if (i >= p_sql.length // should not happen
|| p_sql[i] != ',') {
break;
}
i++;
}
// we can now translate escape functions
Method method = EscapedFunctions2.getFunction(functionName);
if (method == null) {
newsql.append(functionName);
EscapedFunctions2.appendCall(newsql, "(", ",", ")", parsedArgs);
return i;
}
try {
Method escapeMethod = EscapedFunctions.getFunction(functionName);
return (String) escapeMethod.invoke(null, parsedArgs);
method.invoke(null, newsql, parsedArgs);
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof SQLException) {
throw (SQLException) e.getTargetException();
Throwable targetException = e.getTargetException();
if (targetException instanceof SQLException) {
throw (SQLException) targetException;
} else {
throw new PSQLException(e.getTargetException().getMessage(), PSQLState.SYSTEM_ERROR);
}
} catch (Exception e) {
// by default the function name is kept unchanged
StringBuilder buf = new StringBuilder();
buf.append(functionName).append('(');
for (int iArg = 0; iArg < parsedArgs.size(); iArg++) {
buf.append(parsedArgs.get(iArg));
if (iArg != (parsedArgs.size() - 1)) {
buf.append(',');
}
throw new PSQLException(targetException.getMessage(), PSQLState.SYSTEM_ERROR);
}
buf.append(')');
return buf.toString();
} catch (IllegalAccessException e) {
throw new PSQLException(e.getMessage(), PSQLState.SYSTEM_ERROR);
}
return i;
}

private static final char[] QUOTE_OR_ALPHABETIC_MARKER = {'\"', '0'};
@@ -1308,23 +1316,28 @@ private static String escapeFunction(String functionName, String args, boolean s
this.replacementKeyword = replacementKeyword;
}

private int getMatchedPosition(char[] p_sql, int pos) {
int newPos = pos;

private boolean startMatches(char[] p_sql, int pos) {

This comment has been minimized.

Copy link
@bokken

bokken Jun 29, 2018

Member

static?

// check for the keyword
for (char c : escapeKeyword) {
if (newPos >= p_sql.length) {
return 0;
if (pos >= p_sql.length) {
return false;
}
char curr = p_sql[newPos++];
char curr = p_sql[pos++];
if (curr != c && curr != Character.toUpperCase(c)) {
return 0;
return false;
}
}
if (newPos >= p_sql.length) {
return pos < p_sql.length;
}

private int getMatchedPosition(char[] p_sql, int pos) {

This comment has been minimized.

Copy link
@bokken

bokken Jun 29, 2018

Member

static?

This comment has been minimized.

Copy link
@vlsi

vlsi Jun 29, 2018

Author Member

Hm. I should have probably configured my IDE to have those warnings

This comment has been minimized.

Copy link
@vlsi

vlsi Jun 29, 2018

Author Member

Neither of the methods can be made static as they access escapeKeyword field of SqlParseState enum

This comment has been minimized.

Copy link
@bokken

bokken Jul 3, 2018

Member

Aren't enum's static by definition/default?
The previous code directly referenced the escapeKeyword from a static method.

This comment has been minimized.

Copy link
@vlsi

vlsi Jul 3, 2018

Author Member

I do not follow you.

There's a constructor and enum's instance fields:

private final char[] escapeKeyword;
private final char[] allowedValues;
private final String replacementKeyword;
SqlParseState() {
this("", new char[0], null);
}
SqlParseState(String escapeKeyword, char[] allowedValues, String replacementKeyword) {
this.escapeKeyword = escapeKeyword.toCharArray();
this.allowedValues = allowedValues;
this.replacementKeyword = replacementKeyword;
}

This comment has been minimized.

Copy link
@bokken

bokken Jul 3, 2018

Member

Sorry - I think I got lost to the context of where this method was. The method itself is in the SqlParseState, rather than in Parser.

// check for the keyword
if (!startMatches(p_sql, pos)) {
return 0;
}

int newPos = pos + escapeKeyword.length;

// check for the beginning of the value
char curr = p_sql[newPos];
// ignore any in-between whitespace
@@ -20,7 +20,9 @@
* This class stores supported escaped function
*
* @author Xavier Poinsard
* @deprecated see {@link EscapedFunctions2}
*/
@Deprecated
public class EscapedFunctions {
// numeric functions names
public static final String ABS = "abs";
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.