1919import java .util .concurrent .TimeUnit ;
2020import java .util .concurrent .TimeoutException ;
2121import java .util .function .Consumer ;
22+ import java .util .logging .Level ;
23+ import java .util .logging .Logger ;
24+
2225import net .sf .jsqlparser .JSQLParserException ;
2326import net .sf .jsqlparser .expression .Expression ;
2427import net .sf .jsqlparser .parser .feature .Feature ;
3336
3437@ SuppressWarnings ("PMD.CyclomaticComplexity" )
3538public final class CCJSqlParserUtil {
39+ public final static Logger LOGGER = Logger .getLogger (CCJSqlParserUtil .class .getName ());
40+ static {
41+ LOGGER .setLevel (Level .WARNING );
42+ }
43+
3644 public final static int ALLOWED_NESTING_DEPTH = 10 ;
3745
3846 private CCJSqlParserUtil () {}
3947
4048 public static Statement parse (Reader statementReader ) throws JSQLParserException {
49+ ExecutorService executorService = Executors .newSingleThreadExecutor ();
50+ Statement statement = null ;
4151 CCJSqlParser parser = new CCJSqlParser (new StreamProvider (statementReader ));
42- return parseStatement (parser );
52+ try {
53+ statement = parseStatement (parser , executorService );
54+ } finally {
55+ executorService .shutdown ();
56+ }
57+ return statement ;
4358 }
4459
4560 public static Statement parse (String sql ) throws JSQLParserException {
@@ -62,22 +77,41 @@ public static Statement parse(String sql) throws JSQLParserException {
6277 */
6378 public static Statement parse (String sql , Consumer <CCJSqlParser > consumer )
6479 throws JSQLParserException {
80+
81+ ExecutorService executorService = Executors .newSingleThreadExecutor ();
82+ Statement statement = null ;
83+ try {
84+ statement = parse (sql , executorService , consumer );
85+ } finally {
86+ executorService .shutdown ();
87+ }
88+ return statement ;
89+ }
90+
91+ public static Statement parse (String sql , ExecutorService executorService ,
92+ Consumer <CCJSqlParser > consumer )
93+ throws JSQLParserException {
6594 Statement statement = null ;
6695
6796 // first, try to parse fast and simple
97+ CCJSqlParser parser = newParser (sql );
98+ if (consumer != null ) {
99+ consumer .accept (parser );
100+ }
101+ boolean allowComplex = parser .getConfiguration ().getAsBoolean (Feature .allowComplexParsing );
102+ LOGGER .info ("Allowed Complex Parsing: " + allowComplex );
68103 try {
69- CCJSqlParser parser = newParser (sql ).withAllowComplexParsing (false );
70- if (consumer != null ) {
71- consumer .accept (parser );
72- }
73- statement = parseStatement (parser );
104+ LOGGER .info ("Trying SIMPLE parsing " + (allowComplex ? "first" : "only" ));
105+ statement = parseStatement (parser .withAllowComplexParsing (false ), executorService );
74106 } catch (JSQLParserException ex ) {
75- if (getNestingDepth (sql ) <= ALLOWED_NESTING_DEPTH ) {
76- CCJSqlParser parser = newParser (sql ).withAllowComplexParsing (true );
107+ if (allowComplex && getNestingDepth (sql ) <= ALLOWED_NESTING_DEPTH ) {
108+ LOGGER .info ("Trying COMPLEX parsing when SIMPLE parsing failed" );
109+ // beware: the parser must not be reused, but needs to be re-initiated
110+ parser = newParser (sql );
77111 if (consumer != null ) {
78112 consumer .accept (parser );
79113 }
80- statement = parseStatement (parser );
114+ statement = parseStatement (parser . withAllowComplexParsing ( true ), executorService );
81115 } else {
82116 throw ex ;
83117 }
@@ -252,24 +286,25 @@ public static Expression parseCondExpression(String conditionalExpressionStr,
252286 }
253287
254288 /**
255- * @param parser
256- * @return the statement parsed
257- * @throws JSQLParserException
289+ * @param parser the Parser armed with a Statement text
290+ * @param executorService the Executor Service for parsing within a Thread
291+ * @return the parsed Statement
292+ * @throws JSQLParserException when either the Statement can't be parsed or the configured
293+ * timeout is reached
258294 */
259- public static Statement parseStatement (CCJSqlParser parser ) throws JSQLParserException {
295+
296+ public static Statement parseStatement (CCJSqlParser parser , ExecutorService executorService )
297+ throws JSQLParserException {
260298 Statement statement = null ;
261299 try {
262- ExecutorService executorService = Executors .newSingleThreadExecutor ();
263300 Future <Statement > future = executorService .submit (new Callable <Statement >() {
264301 @ Override
265302 public Statement call () throws Exception {
266303 return parser .Statement ();
267304 }
268305 });
269- executorService .shutdown ();
270-
271- statement = future .get ( parser .getConfiguration ().getAsLong (Feature .timeOut ), TimeUnit .MILLISECONDS );
272-
306+ statement = future .get (parser .getConfiguration ().getAsLong (Feature .timeOut ),
307+ TimeUnit .MILLISECONDS );
273308 } catch (TimeoutException ex ) {
274309 parser .interrupted = true ;
275310 throw new JSQLParserException ("Time out occurred." , ex );
@@ -288,55 +323,68 @@ public static Statements parseStatements(String sqls) throws JSQLParserException
288323 return parseStatements (sqls , null );
289324 }
290325
326+ public static Statements parseStatements (String sqls , Consumer <CCJSqlParser > consumer )
327+ throws JSQLParserException {
328+ ExecutorService executorService = Executors .newSingleThreadExecutor ();
329+ final Statements statements = parseStatements (sqls , executorService , consumer );
330+ executorService .shutdown ();
331+
332+ return statements ;
333+ }
334+
291335 /**
292336 * Parse a statement list.
293337 *
294338 * @return the statements parsed
295339 */
296- public static Statements parseStatements (String sqls , Consumer <CCJSqlParser > consumer )
340+ public static Statements parseStatements (String sqls , ExecutorService executorService ,
341+ Consumer <CCJSqlParser > consumer )
297342 throws JSQLParserException {
298343 Statements statements = null ;
299344
345+ CCJSqlParser parser = newParser (sqls );
346+ if (consumer != null ) {
347+ consumer .accept (parser );
348+ }
349+ boolean allowComplex = parser .getConfiguration ().getAsBoolean (Feature .allowComplexParsing );
350+
300351 // first, try to parse fast and simple
301352 try {
302- CCJSqlParser parser = newParser (sqls ).withAllowComplexParsing (false );
303- if (consumer != null ) {
304- consumer .accept (parser );
305- }
306- statements = parseStatements (parser );
353+ statements = parseStatements (parser .withAllowComplexParsing (false ), executorService );
307354 } catch (JSQLParserException ex ) {
308355 // when fast simple parsing fails, try complex parsing but only if it has a chance to
309356 // succeed
310- if (getNestingDepth (sqls ) <= ALLOWED_NESTING_DEPTH ) {
311- CCJSqlParser parser = newParser (sqls ).withAllowComplexParsing (true );
357+ if (allowComplex && getNestingDepth (sqls ) <= ALLOWED_NESTING_DEPTH ) {
358+ // beware: parser must not be re-used but needs to be re-initiated
359+ parser = newParser (sqls );
312360 if (consumer != null ) {
313361 consumer .accept (parser );
314362 }
315- statements = parseStatements (parser );
363+ statements = parseStatements (parser . withAllowComplexParsing ( true ), executorService );
316364 }
317365 }
318366 return statements ;
319367 }
320368
321369 /**
322- * @param parser
323- * @return the statements parsed
324- * @throws JSQLParserException
370+ * @param parser the Parser armed with a Statement text
371+ * @param executorService the Executor Service for parsing within a Thread
372+ * @return the Statements (representing a List of single statements)
373+ * @throws JSQLParserException when either the Statement can't be parsed or the configured
374+ * timeout is reached
325375 */
326- public static Statements parseStatements (CCJSqlParser parser ) throws JSQLParserException {
376+ public static Statements parseStatements (CCJSqlParser parser , ExecutorService executorService )
377+ throws JSQLParserException {
327378 Statements statements = null ;
328379 try {
329- ExecutorService executorService = Executors .newSingleThreadExecutor ();
330380 Future <Statements > future = executorService .submit (new Callable <Statements >() {
331381 @ Override
332382 public Statements call () throws Exception {
333383 return parser .Statements ();
334384 }
335385 });
336- executorService .shutdown ();
337-
338- statements = future .get ( parser .getConfiguration ().getAsLong (Feature .timeOut ) , TimeUnit .MILLISECONDS );
339-
386+ statements = future .get (parser .getConfiguration ().getAsLong (Feature .timeOut ),
387+ TimeUnit .MILLISECONDS );
340388 } catch (TimeoutException ex ) {
341389 parser .interrupted = true ;
342390 throw new JSQLParserException ("Time out occurred." , ex );
0 commit comments