From 50e288791bf94903cc76e0c5a703a936cc9a5d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 19 Mar 2024 11:42:17 +0100 Subject: [PATCH] perf: keep comments when searching for params (#2951) Keep all comments in the SQL string in place when converting positional parameters to named parameters. This reduces the amount of string operations that are needed for each query that is executed, and also enables actually sending comments from the client to Spanner when using positional parameters (e.g. in JDBC). This is step 3 in the refactoring to share more code between the SpannerStatementParser and PostgreSQLStatementParser. --- .../connection/AbstractStatementParser.java | 49 +-- .../connection/PostgreSQLStatementParser.java | 26 +- .../connection/SpannerStatementParser.java | 67 +--- .../SpannerStatementParserTest.java | 156 ++++++++ .../connection/StatementParserTest.java | 362 ++++++++---------- 5 files changed, 361 insertions(+), 299 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractStatementParser.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractStatementParser.java index 13301181452..9793a50c636 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractStatementParser.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractStatementParser.java @@ -634,36 +634,33 @@ 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, except for PostgreSQL-dialect - * SQL strings. + * parameters are named @p1, @p2, etc. for GoogleSQL, and $1, $2, etc. for PostgreSQL. This method + * is used when converting a JDBC statement that uses positional parameters to a Cloud Spanner + * {@link Statement} instance that requires named parameters. * - * @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. - */ - @InternalApi - abstract ParametersInfo convertPositionalParametersToNamedParametersInternal( - char paramChar, String sql); - - /** - * 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. - * - * @param sql The sql string without comments that should be converted + * @param sql The sql string that should be converted to use named parameters * @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. */ @InternalApi public ParametersInfo convertPositionalParametersToNamedParameters(char paramChar, String sql) { - return convertPositionalParametersToNamedParametersInternal(paramChar, sql); + Preconditions.checkNotNull(sql); + final String namedParamPrefix = getQueryParameterPrefix(); + StringBuilder named = new StringBuilder(sql.length() + countOccurrencesOf(paramChar, sql)); + int index = 0; + int paramIndex = 1; + while (index < sql.length()) { + char c = sql.charAt(index); + if (c == paramChar) { + named.append(namedParamPrefix).append(paramIndex); + paramIndex++; + index++; + } else { + index = skip(sql, index, named); + } + } + return new ParametersInfo(paramIndex - 1, named.toString()); } /** Convenience method that is used to estimate the number of parameters in a SQL statement. */ @@ -700,7 +697,8 @@ public boolean checkReturningClause(String sql) { } /** - * <<<<<<< HEAD Returns true if this dialect supports nested comments. + * <<<<<<< HEAD Returns true if this dialect supports nested comments. ======= <<<<<<< HEAD + * Returns true if this dialect supports nested comments. >>>>>>> main * *