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 4bf6609110..fea032e2f5 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 @@ -1033,8 +1033,9 @@ int skipQuoted( } else if (supportsBackslashEscape() && currentChar == BACKSLASH && length > currentIndex + 1 - && sql.charAt(currentIndex + 1) == startQuote) { - // This is an escaped quote (e.g. 'foo\'bar'). + && (sql.charAt(currentIndex + 1) == startQuote + || sql.charAt(currentIndex + 1) == BACKSLASH)) { + // This is an escaped quote (e.g. 'foo\'bar') or an escaped backslash (e.g. 'test\\'). // Note that in raw strings, the \ officially does not start an escape sequence, but the // result is still the same, as in a raw string 'both characters are preserved'. appendIfNotNull(result, currentChar); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerStatementParserTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerStatementParserTest.java index 035ab72959..10f01df937 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerStatementParserTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerStatementParserTest.java @@ -54,6 +54,7 @@ public void testSkip() { assertEquals("'foo\"bar\"'", skip("'foo\"bar\"' ", 0)); assertEquals("\"foo'bar'\"", skip("\"foo'bar'\" ", 0)); assertEquals("`foo'bar'`", skip("`foo'bar'` ", 0)); + assertEquals("'test\\\\'", skip("'test\\\\'", 0)); assertEquals("'''foo'bar'''", skip("'''foo'bar''' ", 0)); assertEquals("'''foo\\'bar'''", skip("'''foo\\'bar''' ", 0)); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementParserTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementParserTest.java index c37b769419..300517faaf 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementParserTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementParserTest.java @@ -1268,6 +1268,10 @@ public void testGoogleStandardSQLDialectConvertPositionalParametersToNamedParame "@p1'''?it\\'?s \n ?it\\'?s'''@p2", parser.convertPositionalParametersToNamedParameters('?', "?'''?it\\'?s \n ?it\\'?s'''?") .sqlWithNamedParameters); + assertEquals( + "@p1'?test?\\\\'@p2", + parser.convertPositionalParametersToNamedParameters('?', "?'?test?\\\\'?") + .sqlWithNamedParameters); assertUnclosedLiteral(parser, "?'?it\\'?s \n ?it\\'?s'?"); assertUnclosedLiteral(parser, "?'?it\\'?s \n ?it\\'?s?");