12
12
import java .io .IOException ;
13
13
import java .io .InputStream ;
14
14
import java .io .Reader ;
15
+ import java .util .concurrent .Callable ;
16
+ import java .util .concurrent .ExecutorService ;
17
+ import java .util .concurrent .Executors ;
18
+ import java .util .concurrent .Future ;
19
+ import java .util .concurrent .TimeUnit ;
20
+ import java .util .concurrent .TimeoutException ;
15
21
import java .util .function .Consumer ;
16
22
import net .sf .jsqlparser .JSQLParserException ;
17
23
import net .sf .jsqlparser .expression .Expression ;
23
29
*
24
30
* @author toben
25
31
*/
32
+
33
+ @ SuppressWarnings ("PMD.CyclomaticComplexity" )
26
34
public final class CCJSqlParserUtil {
27
35
public final static int ALLOWED_NESTING_DEPTH = 10 ;
36
+ public static final int PARSER_TIMEOUT = 6000 ;
28
37
29
38
private CCJSqlParserUtil () {
30
39
}
@@ -54,13 +63,25 @@ public static Statement parse(String sql) throws JSQLParserException {
54
63
* @throws JSQLParserException
55
64
*/
56
65
public static Statement parse (String sql , Consumer <CCJSqlParser > consumer ) throws JSQLParserException {
57
- boolean allowComplexParsing = getNestingDepth (sql )<=ALLOWED_NESTING_DEPTH ;
58
-
59
- CCJSqlParser parser = newParser (sql ).withAllowComplexParsing (allowComplexParsing );
60
- if (consumer != null ) {
61
- consumer .accept (parser );
66
+ Statement statement = null ;
67
+
68
+ // first, try to parse fast and simple
69
+ try {
70
+ CCJSqlParser parser = newParser (sql ).withAllowComplexParsing (false );
71
+ if (consumer != null ) {
72
+ consumer .accept (parser );
73
+ }
74
+ statement = parseStatement (parser );
75
+ } catch (JSQLParserException ex ) {
76
+ if (getNestingDepth (sql )<=ALLOWED_NESTING_DEPTH ) {
77
+ CCJSqlParser parser = newParser (sql ).withAllowComplexParsing (true );
78
+ if (consumer != null ) {
79
+ consumer .accept (parser );
80
+ }
81
+ statement = parseStatement (parser );
82
+ }
62
83
}
63
- return parseStatement ( parser ) ;
84
+ return statement ;
64
85
}
65
86
66
87
public static CCJSqlParser newParser (String sql ) {
@@ -112,24 +133,44 @@ public static Expression parseExpression(String expression, boolean allowPartial
112
133
});
113
134
}
114
135
115
- public static Expression parseExpression (String expression , boolean allowPartialParse , Consumer <CCJSqlParser > consumer ) throws JSQLParserException {
116
- boolean allowComplexParsing = getNestingDepth (expression )<=ALLOWED_NESTING_DEPTH ;
117
-
118
- CCJSqlParser parser = newParser (expression ).withAllowComplexParsing (allowComplexParsing );
119
- if (consumer != null ) {
120
- consumer .accept (parser );
121
- }
136
+ @ SuppressWarnings ("PMD.CyclomaticComplexity" )
137
+ public static Expression parseExpression (String expressionStr , boolean allowPartialParse , Consumer <CCJSqlParser > consumer ) throws JSQLParserException {
138
+ Expression expression = null ;
139
+
140
+ // first, try to parse fast and simple
122
141
try {
123
- Expression expr = parser .Expression ();
124
- if (!allowPartialParse && parser .getNextToken ().kind != CCJSqlParserTokenManager .EOF ) {
125
- throw new JSQLParserException ("could only parse partial expression " + expr .toString ());
142
+ CCJSqlParser parser = newParser (expressionStr ).withAllowComplexParsing (false );
143
+ if (consumer != null ) {
144
+ consumer .accept (parser );
145
+ }
146
+ try {
147
+ expression = parser .Expression ();
148
+ if (parser .getNextToken ().kind != CCJSqlParserTokenManager .EOF ) {
149
+ throw new JSQLParserException ("could only parse partial expression " + expression .toString ());
150
+ }
151
+ } catch (ParseException ex ) {
152
+ throw new JSQLParserException (ex );
153
+ }
154
+ } catch (JSQLParserException ex1 ) {
155
+ // when fast simple parsing fails, try complex parsing but only if it has a chance to succeed
156
+ if (getNestingDepth (expressionStr )<=ALLOWED_NESTING_DEPTH ) {
157
+ CCJSqlParser parser = newParser (expressionStr ).withAllowComplexParsing (true );
158
+ if (consumer != null ) {
159
+ consumer .accept (parser );
160
+ }
161
+ try {
162
+ expression = parser .Expression ();
163
+ if (!allowPartialParse && parser .getNextToken ().kind != CCJSqlParserTokenManager .EOF ) {
164
+ throw new JSQLParserException ("could only parse partial expression " + expression .toString ());
165
+ }
166
+ } catch (JSQLParserException ex ) {
167
+ throw ex ;
168
+ } catch (ParseException ex ) {
169
+ throw new JSQLParserException (ex );
170
+ }
126
171
}
127
- return expr ;
128
- } catch (JSQLParserException ex ) {
129
- throw ex ;
130
- } catch (ParseException ex ) {
131
- throw new JSQLParserException (ex );
132
172
}
173
+ return expression ;
133
174
}
134
175
135
176
/**
@@ -158,24 +199,43 @@ public static Expression parseCondExpression(String condExpr, boolean allowParti
158
199
});
159
200
}
160
201
161
- public static Expression parseCondExpression (String condExpr , boolean allowPartialParse , Consumer <CCJSqlParser > consumer ) throws JSQLParserException {
162
- boolean allowComplexParsing = getNestingDepth (condExpr )<=ALLOWED_NESTING_DEPTH ;
163
-
164
- CCJSqlParser parser = newParser (condExpr ).withAllowComplexParsing (allowComplexParsing );
165
- if (consumer != null ) {
166
- consumer .accept (parser );
167
- }
202
+ @ SuppressWarnings ("PMD.CyclomaticComplexity" )
203
+ public static Expression parseCondExpression (String conditionalExpressionStr , boolean allowPartialParse , Consumer <CCJSqlParser > consumer ) throws JSQLParserException {
204
+ Expression expression = null ;
205
+
206
+ // first, try to parse fast and simple
168
207
try {
169
- Expression expr = parser .Expression ();
170
- if (!allowPartialParse && parser .getNextToken ().kind != CCJSqlParserTokenManager .EOF ) {
171
- throw new JSQLParserException ("could only parse partial expression " + expr .toString ());
208
+ CCJSqlParser parser = newParser (conditionalExpressionStr ).withAllowComplexParsing (false );
209
+ if (consumer != null ) {
210
+ consumer .accept (parser );
211
+ }
212
+ try {
213
+ expression = parser .Expression ();
214
+ if (parser .getNextToken ().kind != CCJSqlParserTokenManager .EOF ) {
215
+ throw new JSQLParserException ("could only parse partial expression " + expression .toString ());
216
+ }
217
+ } catch (ParseException ex ) {
218
+ throw new JSQLParserException (ex );
219
+ }
220
+ } catch (JSQLParserException ex1 ) {
221
+ if (getNestingDepth (conditionalExpressionStr )<=ALLOWED_NESTING_DEPTH ) {
222
+ CCJSqlParser parser = newParser (conditionalExpressionStr ).withAllowComplexParsing (true );
223
+ if (consumer != null ) {
224
+ consumer .accept (parser );
225
+ }
226
+ try {
227
+ expression = parser .Expression ();
228
+ if (!allowPartialParse && parser .getNextToken ().kind != CCJSqlParserTokenManager .EOF ) {
229
+ throw new JSQLParserException ("could only parse partial expression " + expression .toString ());
230
+ }
231
+ } catch (JSQLParserException ex ) {
232
+ throw ex ;
233
+ } catch (ParseException ex ) {
234
+ throw new JSQLParserException (ex );
235
+ }
172
236
}
173
- return expr ;
174
- } catch (JSQLParserException ex ) {
175
- throw ex ;
176
- } catch (ParseException ex ) {
177
- throw new JSQLParserException (ex );
178
237
}
238
+ return expression ;
179
239
}
180
240
181
241
/**
@@ -184,11 +244,25 @@ public static Expression parseCondExpression(String condExpr, boolean allowParti
184
244
* @throws JSQLParserException
185
245
*/
186
246
public static Statement parseStatement (CCJSqlParser parser ) throws JSQLParserException {
247
+ Statement statement = null ;
187
248
try {
188
- return parser .Statement ();
249
+ ExecutorService executorService = Executors .newSingleThreadExecutor ();
250
+ Future <Statement > future = executorService .submit (new Callable <Statement >() {
251
+ @ Override
252
+ public Statement call () throws Exception {
253
+ return parser .Statement ();
254
+ }
255
+ });
256
+ executorService .shutdown ();
257
+
258
+ statement = future .get (PARSER_TIMEOUT , TimeUnit .MILLISECONDS );
259
+ } catch (TimeoutException ex ) {
260
+ parser .interrupted = true ;
261
+ throw new JSQLParserException ("Time out occurred." , ex );
189
262
} catch (Exception ex ) {
190
263
throw new JSQLParserException (ex );
191
264
}
265
+ return statement ;
192
266
}
193
267
194
268
/**
@@ -197,10 +271,20 @@ public static Statement parseStatement(CCJSqlParser parser) throws JSQLParserExc
197
271
* @return the statements parsed
198
272
*/
199
273
public static Statements parseStatements (String sqls ) throws JSQLParserException {
200
- boolean allowComplexParsing = getNestingDepth (sqls )<=ALLOWED_NESTING_DEPTH ;
201
-
202
- CCJSqlParser parser = newParser (sqls ).withAllowComplexParsing (allowComplexParsing );
203
- return parseStatements (parser );
274
+ Statements statements = null ;
275
+
276
+ // first, try to parse fast and simple
277
+ try {
278
+ CCJSqlParser parser = newParser (sqls ).withAllowComplexParsing (false );
279
+ statements = parseStatements (parser );
280
+ } catch (JSQLParserException ex ) {
281
+ // when fast simple parsing fails, try complex parsing but only if it has a chance to succeed
282
+ if (getNestingDepth (sqls )<=ALLOWED_NESTING_DEPTH ) {
283
+ CCJSqlParser parser = newParser (sqls ).withAllowComplexParsing (true );
284
+ statements = parseStatements (parser );
285
+ }
286
+ }
287
+ return statements ;
204
288
}
205
289
206
290
/**
@@ -209,11 +293,25 @@ public static Statements parseStatements(String sqls) throws JSQLParserException
209
293
* @throws JSQLParserException
210
294
*/
211
295
public static Statements parseStatements (CCJSqlParser parser ) throws JSQLParserException {
296
+ Statements statements = null ;
212
297
try {
213
- return parser .Statements ();
298
+ ExecutorService executorService = Executors .newSingleThreadExecutor ();
299
+ Future <Statements > future = executorService .submit (new Callable <Statements >() {
300
+ @ Override
301
+ public Statements call () throws Exception {
302
+ return parser .Statements ();
303
+ }
304
+ });
305
+ executorService .shutdown ();
306
+
307
+ statements = future .get (PARSER_TIMEOUT , TimeUnit .MILLISECONDS );
308
+ } catch (TimeoutException ex ) {
309
+ parser .interrupted = true ;
310
+ throw new JSQLParserException ("Time out occurred." , ex );
214
311
} catch (Exception ex ) {
215
312
throw new JSQLParserException (ex );
216
313
}
314
+ return statements ;
217
315
}
218
316
219
317
public static void streamStatements (StatementListener listener , InputStream is , String encoding ) throws JSQLParserException {
0 commit comments