Skip to content

Commit

Permalink
chore: allow comments in PG strings (#2604)
Browse files Browse the repository at this point in the history
Allow comments in PostgreSQL query strings for extracting parameter
definitions. The comments need to be preserved, as they could contain
query hints.
  • Loading branch information
olavloite authored Aug 29, 2023
1 parent 59cec9b commit bfa777b
Show file tree
Hide file tree
Showing 3 changed files with 286 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -539,11 +539,10 @@ public static class ParametersInfo {
* Converts all positional parameters (?) in the given sql string into named parameters. The
* parameters are named @p1, @p2, etc. This method is used when converting a JDBC statement that
* uses positional parameters to a Cloud Spanner {@link Statement} instance that requires named
* parameters. The input SQL string may not contain any comments. There is an exception case if
* the statement starts with a GSQL comment which forces it to be interpreted as a GoogleSql
* statement.
* parameters. The input SQL string may not contain any comments, except for PostgreSQL-dialect
* SQL strings.
*
* @param sql The sql string without comments that should be converted
* @param sql The sql string that should be converted
* @return A {@link ParametersInfo} object containing a string with named parameters instead of
* positional parameters and the number of parameters.
* @throws SpannerException If the input sql string contains an unclosed string/byte literal.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,8 @@ ParametersInfo convertPositionalParametersToNamedParametersInternal(char paramCh
* Note: This is an internal API and breaking changes can be made without prior notice.
*
* <p>Returns the PostgreSQL-style query parameters ($1, $2, ...) in the given SQL string. The
* SQL-string is assumed to not contain any comments. Use {@link #removeCommentsAndTrim(String)}
* to remove all comments before calling this method. Occurrences of query-parameter like strings
* inside quoted identifiers or string literals are ignored.
* SQL-string is allowed to contain comments. Occurrences of query-parameter like strings inside
* quoted identifiers or string literals are ignored.
*
* <p>The following example will return a set containing ("$1", "$2"). <code>
* select col1, col2, "col$4"
Expand All @@ -195,7 +194,7 @@ ParametersInfo convertPositionalParametersToNamedParametersInternal(char paramCh
* and not col3=$1 and col4='$3'
* </code>
*
* @param sql the SQL-string to check for parameters. Must not contain comments.
* @param sql the SQL-string to check for parameters.
* @return A set containing all the parameters in the SQL-string.
*/
@InternalApi
Expand Down Expand Up @@ -233,12 +232,56 @@ private int skip(String sql, int currentIndex, @Nullable StringBuilder result) {
return skipQuoted(
sql, currentIndex + dollarTag.length() + 1, currentChar, dollarTag, result);
}
} else if (currentChar == HYPHEN
&& sql.length() > (currentIndex + 1)
&& sql.charAt(currentIndex + 1) == HYPHEN) {
return skipSingleLineComment(sql, currentIndex, result);
} else if (currentChar == SLASH
&& sql.length() > (currentIndex + 1)
&& sql.charAt(currentIndex + 1) == ASTERISK) {
return skipMultiLineComment(sql, currentIndex, result);
}

appendIfNotNull(result, currentChar);
return currentIndex + 1;
}

static int skipSingleLineComment(String sql, int currentIndex, @Nullable StringBuilder result) {
int endIndex = sql.indexOf('\n', currentIndex + 2);
if (endIndex == -1) {
endIndex = sql.length();
} else {
// Include the newline character.
endIndex++;
}
appendIfNotNull(result, sql.substring(currentIndex, endIndex));
return endIndex;
}

static int skipMultiLineComment(String sql, int startIndex, @Nullable StringBuilder result) {
// Current position is start + '/*'.length().
int pos = startIndex + 2;
// PostgreSQL allows comments to be nested. That is, the following is allowed:
// '/* test /* inner comment */ still a comment */'
int level = 1;
while (pos < sql.length()) {
if (sql.charAt(pos) == SLASH && sql.length() > (pos + 1) && sql.charAt(pos + 1) == ASTERISK) {
level++;
}
if (sql.charAt(pos) == ASTERISK && sql.length() > (pos + 1) && sql.charAt(pos + 1) == SLASH) {
level--;
if (level == 0) {
pos += 2;
appendIfNotNull(result, sql.substring(startIndex, pos));
return pos;
}
}
pos++;
}
appendIfNotNull(result, sql.substring(startIndex));
return sql.length();
}

private int skipQuoted(
String sql, int startIndex, char startQuote, @Nullable StringBuilder result) {
return skipQuoted(sql, startIndex, startQuote, null, result);
Expand Down Expand Up @@ -285,6 +328,12 @@ private void appendIfNotNull(@Nullable StringBuilder result, char currentChar) {
}
}

private static void appendIfNotNull(@Nullable StringBuilder result, String suffix) {
if (result != null) {
result.append(suffix);
}
}

private void appendIfNotNull(
@Nullable StringBuilder result, char prefix, String tag, char suffix) {
if (result != null) {
Expand Down
Loading

0 comments on commit bfa777b

Please sign in to comment.