1616
1717package com .google .cloud .spanner .connection ;
1818
19+ import static com .google .cloud .spanner .ErrorCode .INVALID_ARGUMENT ;
1920import static com .google .cloud .spanner .connection .StatementParserTest .assertUnclosedLiteral ;
2021import static org .junit .Assert .assertEquals ;
22+ import static org .junit .Assert .assertFalse ;
23+ import static org .junit .Assert .assertTrue ;
24+ import static org .junit .Assert .fail ;
2125
2226import com .google .cloud .spanner .Dialect ;
27+ import com .google .cloud .spanner .SpannerException ;
28+ import com .google .cloud .spanner .Statement ;
2329import com .google .cloud .spanner .connection .StatementParserTest .CommentInjector ;
2430import org .junit .Test ;
2531import org .junit .runner .RunWith ;
@@ -39,6 +45,55 @@ static String skip(String sql, int currentIndex) {
3945 return sql .substring (currentIndex , position );
4046 }
4147
48+ @ Test
49+ public void testRemoveCommentsAndTrim () {
50+ AbstractStatementParser parser =
51+ AbstractStatementParser .getInstance (Dialect .GOOGLE_STANDARD_SQL );
52+
53+ // Statements that should parse correctly
54+ String [] validStatements =
55+ new String [] {
56+ "SELECT '\\ \\ '" , // SELECT '\\' (escaped backslash, followed by quote)
57+ "SELECT '\\ ''" , // SELECT '\'' (escaped quote, followed by an actual closing quote)
58+ "SELECT '\\ \\ \\ \\ '" // SELECT '\\\\' (two escaped backslashes)
59+ };
60+ for (String sql : validStatements ) {
61+ assertEquals (sql , parser .removeCommentsAndTrim (sql ));
62+ }
63+
64+ // Statements that contain an unclosed literal because the final quote is
65+ // escaped
66+ String [] invalidStatements =
67+ new String [] {
68+ "SELECT '\\ '" // SELECT '\' (escaped closing quote)
69+ };
70+
71+ for (String sql : invalidStatements ) {
72+ try {
73+ parser .removeCommentsAndTrim (sql );
74+ fail ("Expected SpannerException for unclosed literal: " + sql );
75+ } catch (SpannerException e ) {
76+ assertEquals (INVALID_ARGUMENT , e .getErrorCode ());
77+ }
78+ }
79+ }
80+
81+ @ Test
82+ public void testReturningClauseWithBackslashes () {
83+ AbstractStatementParser parser =
84+ AbstractStatementParser .getInstance (Dialect .GOOGLE_STANDARD_SQL );
85+
86+ // Valid returning clause, double backslash in string literal should be handled
87+ // correctly.
88+ String sqlWithReturning = "INSERT INTO my_table (value) VALUES ('foo \\ \\ bar') THEN RETURN id" ;
89+ assertTrue (parser .parse (Statement .of (sqlWithReturning )).hasReturningClause ());
90+
91+ // No returning clause, `then return` is inside a string literal with a double
92+ // backslash.
93+ String sqlWithoutReturning = "INSERT INTO my_table (value) VALUES ('then \\ \\ return')" ;
94+ assertFalse (parser .parse (Statement .of (sqlWithoutReturning )).hasReturningClause ());
95+ }
96+
4297 @ Test
4398 public void testSkip () {
4499 assertEquals ("" , skip ("" ));
0 commit comments