@@ -56,95 +56,44 @@ protected boolean supportsExplain() {
5656 @ Override
5757 String removeCommentsAndTrimInternal (String sql ) {
5858 Preconditions .checkNotNull (sql );
59- String currentTag = null ;
60- boolean isInQuoted = false ;
6159 boolean isInSingleLineComment = false ;
6260 int multiLineCommentLevel = 0 ;
63- char startQuote = 0 ;
64- boolean lastCharWasEscapeChar = false ;
6561 StringBuilder res = new StringBuilder (sql .length ());
6662 int index = 0 ;
6763 while (index < sql .length ()) {
6864 char c = sql .charAt (index );
69- if (isInQuoted ) {
70- if ((c == '\n' || c == '\r' ) && startQuote != DOLLAR ) {
71- throw SpannerExceptionFactory .newSpannerException (
72- ErrorCode .INVALID_ARGUMENT , "SQL statement contains an unclosed literal: " + sql );
73- } else if (c == startQuote ) {
74- if (c == DOLLAR ) {
75- // Check if this is the end of the current dollar quoted string.
76- String tag = parseDollarQuotedString (sql , index + 1 );
77- if (tag != null && tag .equals (currentTag )) {
78- index += tag .length () + 1 ;
79- res .append (c );
80- res .append (tag );
81- isInQuoted = false ;
82- startQuote = 0 ;
83- }
84- } else if (lastCharWasEscapeChar ) {
85- lastCharWasEscapeChar = false ;
86- } else if (sql .length () > index + 1 && sql .charAt (index + 1 ) == startQuote ) {
87- // This is an escaped quote (e.g. 'foo''bar')
88- res .append (c );
89- index ++;
90- } else {
91- isInQuoted = false ;
92- startQuote = 0 ;
93- }
94- } else if (c == '\\' ) {
95- lastCharWasEscapeChar = true ;
96- } else {
97- lastCharWasEscapeChar = false ;
65+ if (isInSingleLineComment ) {
66+ if (c == '\n' ) {
67+ isInSingleLineComment = false ;
68+ // Include the line feed in the result.
69+ res .append (c );
70+ }
71+ } else if (multiLineCommentLevel > 0 ) {
72+ if (sql .length () > index + 1 && c == ASTERISK && sql .charAt (index + 1 ) == SLASH ) {
73+ multiLineCommentLevel --;
74+ index ++;
75+ } else if (sql .length () > index + 1 && c == SLASH && sql .charAt (index + 1 ) == ASTERISK ) {
76+ multiLineCommentLevel ++;
77+ index ++;
9878 }
99- res .append (c );
10079 } else {
101- // We are not in a quoted string.
102- if (isInSingleLineComment ) {
103- if (c == '\n' ) {
104- isInSingleLineComment = false ;
105- // Include the line feed in the result.
106- res .append (c );
107- }
108- } else if (multiLineCommentLevel > 0 ) {
109- if (sql .length () > index + 1 && c == ASTERIKS && sql .charAt (index + 1 ) == SLASH ) {
110- multiLineCommentLevel --;
111- index ++;
112- } else if (sql .length () > index + 1 && c == SLASH && sql .charAt (index + 1 ) == ASTERIKS ) {
113- multiLineCommentLevel ++;
114- index ++;
115- }
80+ // Check for -- which indicates the start of a single-line comment.
81+ if (sql .length () > index + 1 && c == HYPHEN && sql .charAt (index + 1 ) == HYPHEN ) {
82+ // This is a single line comment.
83+ isInSingleLineComment = true ;
84+ index += 2 ;
85+ continue ;
86+ } else if (sql .length () > index + 1 && c == SLASH && sql .charAt (index + 1 ) == ASTERISK ) {
87+ multiLineCommentLevel ++;
88+ index += 2 ;
89+ continue ;
11690 } else {
117- // Check for -- which indicates the start of a single-line comment.
118- if (sql .length () > index + 1 && c == HYPHEN && sql .charAt (index + 1 ) == HYPHEN ) {
119- // This is a single line comment.
120- isInSingleLineComment = true ;
121- } else if (sql .length () > index + 1 && c == SLASH && sql .charAt (index + 1 ) == ASTERIKS ) {
122- multiLineCommentLevel ++;
123- index ++;
124- } else {
125- if (c == SINGLE_QUOTE || c == DOUBLE_QUOTE ) {
126- isInQuoted = true ;
127- startQuote = c ;
128- } else if (c == DOLLAR ) {
129- currentTag = parseDollarQuotedString (sql , index + 1 );
130- if (currentTag != null ) {
131- isInQuoted = true ;
132- startQuote = DOLLAR ;
133- index += currentTag .length () + 1 ;
134- res .append (c );
135- res .append (currentTag );
136- }
137- }
138- res .append (c );
139- }
91+ index = skip (sql , index , res );
92+ continue ;
14093 }
14194 }
14295 index ++;
14396 }
144- if (isInQuoted ) {
145- throw SpannerExceptionFactory .newSpannerException (
146- ErrorCode .INVALID_ARGUMENT , "SQL statement contains an unclosed literal: " + sql );
147- }
14897 if (multiLineCommentLevel > 0 ) {
14998 throw SpannerExceptionFactory .newSpannerException (
15099 ErrorCode .INVALID_ARGUMENT ,
@@ -184,73 +133,78 @@ String removeStatementHint(String sql) {
184133 ParametersInfo convertPositionalParametersToNamedParametersInternal (char paramChar , String sql ) {
185134 Preconditions .checkNotNull (sql );
186135 final String namedParamPrefix = "$" ;
187- String currentTag = null ;
188- boolean isInQuoted = false ;
189- char startQuote = 0 ;
190- boolean lastCharWasEscapeChar = false ;
191136 StringBuilder named = new StringBuilder (sql .length () + countOccurrencesOf (paramChar , sql ));
192137 int index = 0 ;
193138 int paramIndex = 1 ;
194139 while (index < sql .length ()) {
195140 char c = sql .charAt (index );
196- if (isInQuoted ) {
197- if ((c == '\n' || c == '\r' ) && startQuote != DOLLAR ) {
198- throw SpannerExceptionFactory .newSpannerException (
199- ErrorCode .INVALID_ARGUMENT , "SQL statement contains an unclosed literal: " + sql );
200- } else if (c == startQuote ) {
201- if (c == DOLLAR ) {
202- // Check if this is the end of the current dollar quoted string.
203- String tag = parseDollarQuotedString (sql , index + 1 );
204- if (tag != null && tag .equals (currentTag )) {
205- index += tag .length () + 1 ;
206- named .append (c );
207- named .append (tag );
208- isInQuoted = false ;
209- startQuote = 0 ;
210- }
211- } else if (lastCharWasEscapeChar ) {
212- lastCharWasEscapeChar = false ;
213- } else if (sql .length () > index + 1 && sql .charAt (index + 1 ) == startQuote ) {
214- // This is an escaped quote (e.g. 'foo''bar')
215- named .append (c );
216- index ++;
217- } else {
218- isInQuoted = false ;
219- startQuote = 0 ;
141+ if (c == paramChar ) {
142+ named .append (namedParamPrefix ).append (paramIndex );
143+ paramIndex ++;
144+ index ++;
145+ } else {
146+ index = skip (sql , index , named );
147+ }
148+ }
149+ return new ParametersInfo (paramIndex - 1 , named .toString ());
150+ }
151+
152+ private int skip (String sql , int currentIndex , StringBuilder result ) {
153+ char currentChar = sql .charAt (currentIndex );
154+ if (currentChar == SINGLE_QUOTE || currentChar == DOUBLE_QUOTE ) {
155+ result .append (currentChar );
156+ return skipQuoted (sql , currentIndex , currentChar , result );
157+ } else if (currentChar == DOLLAR ) {
158+ String dollarTag = parseDollarQuotedString (sql , currentIndex + 1 );
159+ if (dollarTag != null ) {
160+ result .append (currentChar ).append (dollarTag ).append (currentChar );
161+ return skipQuoted (
162+ sql , currentIndex + dollarTag .length () + 1 , currentChar , dollarTag , result );
163+ }
164+ }
165+
166+ result .append (currentChar );
167+ return currentIndex + 1 ;
168+ }
169+
170+ private int skipQuoted (String sql , int startIndex , char startQuote , StringBuilder result ) {
171+ return skipQuoted (sql , startIndex , startQuote , null , result );
172+ }
173+
174+ private int skipQuoted (
175+ String sql , int startIndex , char startQuote , String dollarTag , StringBuilder result ) {
176+ boolean lastCharWasEscapeChar = false ;
177+ int currentIndex = startIndex + 1 ;
178+ while (currentIndex < sql .length ()) {
179+ char currentChar = sql .charAt (currentIndex );
180+ if (currentChar == startQuote ) {
181+ if (currentChar == DOLLAR ) {
182+ // Check if this is the end of the current dollar quoted string.
183+ String tag = parseDollarQuotedString (sql , currentIndex + 1 );
184+ if (tag != null && tag .equals (dollarTag )) {
185+ result .append (currentChar ).append (tag ).append (currentChar );
186+ return currentIndex + tag .length () + 2 ;
220187 }
221- } else if (c == '\\' ) {
222- lastCharWasEscapeChar = true ;
223- } else {
188+ } else if (lastCharWasEscapeChar ) {
224189 lastCharWasEscapeChar = false ;
225- }
226- named .append (c );
227- } else {
228- if (c == paramChar ) {
229- named .append (namedParamPrefix + paramIndex );
230- paramIndex ++;
190+ } else if (sql .length () > currentIndex + 1 && sql .charAt (currentIndex + 1 ) == startQuote ) {
191+ // This is an escaped quote (e.g. 'foo''bar')
192+ result .append (currentChar ).append (currentChar );
193+ currentIndex += 2 ;
194+ continue ;
231195 } else {
232- if (c == SINGLE_QUOTE || c == DOUBLE_QUOTE ) {
233- isInQuoted = true ;
234- startQuote = c ;
235- } else if (c == DOLLAR ) {
236- currentTag = parseDollarQuotedString (sql , index + 1 );
237- if (currentTag != null ) {
238- isInQuoted = true ;
239- startQuote = DOLLAR ;
240- index += currentTag .length () + 1 ;
241- named .append (c );
242- named .append (currentTag );
243- }
244- }
245- named .append (c );
196+ result .append (currentChar );
197+ return currentIndex + 1 ;
246198 }
199+ } else if (currentChar == '\\' ) {
200+ lastCharWasEscapeChar = true ;
201+ } else {
202+ lastCharWasEscapeChar = false ;
247203 }
248- index ++;
249- }
250- if (isInQuoted ) {
251- throw SpannerExceptionFactory .newSpannerException (
252- ErrorCode .INVALID_ARGUMENT , "SQL statement contains an unclosed literal: " + sql );
204+ currentIndex ++;
205+ result .append (currentChar );
253206 }
254- return new ParametersInfo (paramIndex - 1 , named .toString ());
207+ throw SpannerExceptionFactory .newSpannerException (
208+ ErrorCode .INVALID_ARGUMENT , "SQL statement contains an unclosed literal: " + sql );
255209 }
256210}
0 commit comments