tokens = Splitter.onPattern("\\s+").split(sql).iterator();
+ if (!tokens.hasNext()) {
+ return false;
+ }
+ String token = tokens.next();
+ for (String check : checkStatements) {
+ if (token.equalsIgnoreCase(check)) {
+ return true;
}
}
return false;
@@ -929,7 +932,8 @@ int skipQuoted(
appendIfNotNull(result, startQuote);
appendIfNotNull(result, startQuote);
}
- while (currentIndex < sql.length()) {
+ int length = sql.length();
+ while (currentIndex < length) {
char currentChar = sql.charAt(currentIndex);
if (currentChar == startQuote) {
if (supportsDollarQuotedStrings() && currentChar == DOLLAR) {
@@ -940,7 +944,7 @@ int skipQuoted(
return currentIndex + tag.length() + 2;
}
} else if (supportsEscapeQuoteWithQuote()
- && sql.length() > currentIndex + 1
+ && length > currentIndex + 1
&& sql.charAt(currentIndex + 1) == startQuote) {
// This is an escaped quote (e.g. 'foo''bar')
appendIfNotNull(result, currentChar);
@@ -949,7 +953,7 @@ int skipQuoted(
continue;
} else if (isTripleQuoted) {
// Check if this is the end of the triple-quoted string.
- if (sql.length() > currentIndex + 2
+ if (length > currentIndex + 2
&& sql.charAt(currentIndex + 1) == startQuote
&& sql.charAt(currentIndex + 2) == startQuote) {
appendIfNotNull(result, currentChar);
@@ -963,7 +967,7 @@ int skipQuoted(
}
} else if (supportsBackslashEscape()
&& currentChar == BACKSLASH
- && sql.length() > currentIndex + 1
+ && length > currentIndex + 1
&& sql.charAt(currentIndex + 1) == startQuote) {
// This is an escaped quote (e.g. 'foo\'bar').
// Note that in raw strings, the \ officially does not start an escape sequence, but the
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/PostgreSQLStatementParser.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/PostgreSQLStatementParser.java
index 4f39c549de9..60b64b0cd4f 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/PostgreSQLStatementParser.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/PostgreSQLStatementParser.java
@@ -46,15 +46,6 @@ Dialect getDialect() {
return Dialect.POSTGRESQL;
}
- /**
- * Indicates whether the parser supports the {@code EXPLAIN} clause. The PostgreSQL parser does
- * not support it.
- */
- @Override
- protected boolean supportsExplain() {
- return false;
- }
-
@Override
boolean supportsNestedComments() {
return true;
@@ -125,7 +116,8 @@ String removeCommentsAndTrimInternal(String sql) {
int multiLineCommentStartIdx = -1;
StringBuilder res = new StringBuilder(sql.length());
int index = 0;
- while (index < sql.length()) {
+ int length = sql.length();
+ while (index < length) {
char c = sql.charAt(index);
if (isInSingleLineComment) {
if (c == '\n') {
@@ -134,10 +126,10 @@ String removeCommentsAndTrimInternal(String sql) {
res.append(c);
}
} else if (multiLineCommentLevel > 0) {
- if (sql.length() > index + 1 && c == ASTERISK && sql.charAt(index + 1) == SLASH) {
+ if (length > index + 1 && c == ASTERISK && sql.charAt(index + 1) == SLASH) {
multiLineCommentLevel--;
if (multiLineCommentLevel == 0) {
- if (!whitespaceBeforeOrAfterMultiLineComment && (sql.length() > index + 2)) {
+ if (!whitespaceBeforeOrAfterMultiLineComment && (length > index + 2)) {
whitespaceBeforeOrAfterMultiLineComment =
Character.isWhitespace(sql.charAt(index + 2));
}
@@ -145,23 +137,23 @@ String removeCommentsAndTrimInternal(String sql) {
// neither at the start nor at the end of SQL string, append an extra space.
if (!whitespaceBeforeOrAfterMultiLineComment
&& (multiLineCommentStartIdx != 0)
- && (index != sql.length() - 2)) {
+ && (index != length - 2)) {
res.append(' ');
}
}
index++;
- } else if (sql.length() > index + 1 && c == SLASH && sql.charAt(index + 1) == ASTERISK) {
+ } else if (length > index + 1 && c == SLASH && sql.charAt(index + 1) == ASTERISK) {
multiLineCommentLevel++;
index++;
}
} else {
// Check for -- which indicates the start of a single-line comment.
- if (sql.length() > index + 1 && c == HYPHEN && sql.charAt(index + 1) == HYPHEN) {
+ if (length > index + 1 && c == HYPHEN && sql.charAt(index + 1) == HYPHEN) {
// This is a single line comment.
isInSingleLineComment = true;
index += 2;
continue;
- } else if (sql.length() > index + 1 && c == SLASH && sql.charAt(index + 1) == ASTERISK) {
+ } else if (length > index + 1 && c == SLASH && sql.charAt(index + 1) == ASTERISK) {
multiLineCommentLevel++;
if (index >= 1) {
whitespaceBeforeOrAfterMultiLineComment = Character.isWhitespace(sql.charAt(index - 1));
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerStatementParser.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerStatementParser.java
index fdd10bbf5ae..2689145b7ac 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerStatementParser.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerStatementParser.java
@@ -46,15 +46,6 @@ Dialect getDialect() {
return Dialect.GOOGLE_STANDARD_SQL;
}
- /**
- * Indicates whether the parser supports the {@code EXPLAIN} clause. The Spanner parser does
- * support it.
- */
- @Override
- protected boolean supportsExplain() {
- return true;
- }
-
@Override
boolean supportsNestedComments() {
return false;
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementParserBenchmark.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementParserBenchmark.java
new file mode 100644
index 00000000000..e028f8027cf
--- /dev/null
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementParserBenchmark.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner.connection;
+
+import com.google.cloud.spanner.Dialect;
+import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.connection.AbstractStatementParser.ParsedStatement;
+import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Warmup;
+
+@Fork(value = 1, warmups = 0)
+@Warmup(iterations = 1, time = 5)
+@Measurement(iterations = 5, time = 5)
+public class StatementParserBenchmark {
+ private static final Dialect dialect = Dialect.POSTGRESQL;
+ private static final AbstractStatementParser PARSER =
+ AbstractStatementParser.getInstance(dialect);
+
+ private static final String LONG_QUERY_TEXT =
+ generateLongStatement("SELECT * FROM foo WHERE 1", 100 * 1024); // 100kb
+
+ private static final String LONG_DML_TEXT =
+ generateLongStatement("update foo set bar=1 WHERE 1", 100 * 1024); // 100kb
+
+ /** Generates a long SQL-looking string. */
+ private static String generateLongStatement(String prefix, int length) {
+ StringBuilder sb = new StringBuilder(length + 50);
+ sb.append(prefix);
+ while (sb.length() < length) {
+ sb.append(" OR abcdefghijklmnopqrstuvwxyz='abcdefghijklmnopqrstuvwxyz'");
+ }
+ return sb.toString();
+ }
+
+ @Benchmark
+ public ParsedStatement isQueryTest() {
+ return PARSER.internalParse(
+ Statement.of("CREATE TABLE FOO (ID INT64, NAME STRING(100)) PRIMARY KEY (ID)"),
+ QueryOptions.getDefaultInstance());
+ }
+
+ @Benchmark
+ public ParsedStatement longQueryTest() {
+ return PARSER.internalParse(Statement.of(LONG_QUERY_TEXT), QueryOptions.getDefaultInstance());
+ }
+
+ @Benchmark
+ public ParsedStatement longDmlTest() {
+ return PARSER.internalParse(Statement.of(LONG_DML_TEXT), QueryOptions.getDefaultInstance());
+ }
+
+ public static void main(String[] args) throws Exception {
+ for (int i = 0; i < 100000; i++) {
+ if (PARSER.internalParse(Statement.of(LONG_QUERY_TEXT), QueryOptions.getDefaultInstance())
+ == null) {
+ throw new AssertionError();
+ }
+ if (PARSER.internalParse(Statement.of(LONG_DML_TEXT), QueryOptions.getDefaultInstance())
+ == null) {
+ throw new AssertionError();
+ }
+ }
+ }
+}
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy