Skip to content

Commit d910913

Browse files
authored
Fix parseStatements failure propagation and executor cleanup (#2568)
1 parent 7252121 commit d910913

2 files changed

Lines changed: 89 additions & 8 deletions

File tree

‎src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -429,10 +429,11 @@ public static Statements parseStatements(String sqls, Consumer<CCJSqlParser> con
429429
}
430430

431431
ExecutorService executorService = Executors.newSingleThreadExecutor();
432-
final Statements statements = parseStatements(sqls, executorService, consumer);
433-
executorService.shutdown();
434-
435-
return statements;
432+
try {
433+
return parseStatements(sqls, executorService, consumer);
434+
} finally {
435+
executorService.shutdown();
436+
}
436437
}
437438

438439
/**
@@ -447,7 +448,6 @@ public static Statements parseStatements(String sqls, ExecutorService executorSe
447448
return null;
448449
}
449450

450-
Statements statements = null;
451451
CCJSqlParser parser = newParser(sqls);
452452
if (consumer != null) {
453453
consumer.accept(parser);
@@ -457,7 +457,7 @@ public static Statements parseStatements(String sqls, ExecutorService executorSe
457457

458458
// first, try to parse fast and simple
459459
try {
460-
statements = parseStatements(parser.withAllowComplexParsing(false), executorService);
460+
return parseStatements(parser.withAllowComplexParsing(false), executorService);
461461
} catch (JSQLParserException ex) {
462462
// when fast simple parsing fails, try complex parsing but only if it has a chance to
463463
// succeed
@@ -468,10 +468,10 @@ public static Statements parseStatements(String sqls, ExecutorService executorSe
468468
if (consumer != null) {
469469
consumer.accept(parser);
470470
}
471-
statements = parseStatements(parser.withAllowComplexParsing(true), executorService);
471+
return parseStatements(parser.withAllowComplexParsing(true), executorService);
472472
}
473+
throw ex;
473474
}
474-
return statements;
475475
}
476476

477477
/**
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.parser;
11+
12+
import net.sf.jsqlparser.JSQLParserException;
13+
import net.sf.jsqlparser.statement.UnsupportedStatement;
14+
import org.junit.jupiter.api.Test;
15+
16+
import java.util.concurrent.CountDownLatch;
17+
import java.util.concurrent.ExecutorService;
18+
import java.util.concurrent.Executors;
19+
import java.util.concurrent.TimeUnit;
20+
import java.util.concurrent.TimeoutException;
21+
22+
import static org.junit.jupiter.api.Assertions.*;
23+
24+
class ParseStatementsFailureTest {
25+
@Test
26+
void reportsFailureWhenComplexParsingIsDisabled() {
27+
JSQLParserException exception = assertThrows(JSQLParserException.class,
28+
() -> CCJSqlParserUtil.parseStatements("SELECT FROM",
29+
parser -> parser.withAllowComplexParsing(false)));
30+
assertNotNull(exception.getCause());
31+
}
32+
33+
@Test
34+
void reportsFailureWhenNestingPreventsRetry() {
35+
assertThrows(JSQLParserException.class,
36+
() -> CCJSqlParserUtil.parseStatements("SELECT (( FROM",
37+
parser -> parser.withAllowComplexParsing(true).withAllowedNestingDepth(0)));
38+
}
39+
40+
@Test
41+
void leavesCallerExecutorUsableAfterFailure() throws Exception {
42+
ExecutorService executor = Executors.newSingleThreadExecutor();
43+
try {
44+
assertThrows(JSQLParserException.class,
45+
() -> CCJSqlParserUtil.parseStatements("SELECT FROM", executor,
46+
parser -> parser.withAllowComplexParsing(false)));
47+
assertFalse(executor.isShutdown());
48+
assertEquals(2, CCJSqlParserUtil.parseStatements("SELECT 1; SELECT 2", executor,
49+
parser -> parser.withAllowComplexParsing(false)).size());
50+
} finally {
51+
executor.shutdownNow();
52+
}
53+
}
54+
55+
@Test
56+
void reportsTimeoutWhenComplexParsingIsDisabled() {
57+
ExecutorService executor = Executors.newSingleThreadExecutor();
58+
CountDownLatch release = new CountDownLatch(1);
59+
executor.submit(() -> release.await(30, TimeUnit.SECONDS));
60+
try {
61+
JSQLParserException exception = assertThrows(JSQLParserException.class,
62+
() -> CCJSqlParserUtil.parseStatements("SELECT 1", executor,
63+
parser -> parser.withAllowComplexParsing(false).withTimeOut(50)));
64+
assertInstanceOf(TimeoutException.class, exception.getCause());
65+
} finally {
66+
release.countDown();
67+
executor.shutdownNow();
68+
}
69+
}
70+
71+
@Test
72+
void preservesEmptyInputAndUnsupportedStatementContracts() throws Exception {
73+
assertNull(CCJSqlParserUtil.parseStatements((String) null));
74+
assertNull(CCJSqlParserUtil.parseStatements(""));
75+
assertInstanceOf(UnsupportedStatement.class,
76+
CCJSqlParserUtil.parseStatements("SELECT 1; WHATEVER !",
77+
parser -> parser.withAllowComplexParsing(false)
78+
.withUnsupportedStatements(true))
79+
.get(1));
80+
}
81+
}

0 commit comments

Comments
 (0)