Skip to content

Commit a7dfb94

Browse files
style: Cosmetic improvements
1 parent 3ff9774 commit a7dfb94

File tree

2 files changed

+107
-103
lines changed

2 files changed

+107
-103
lines changed

src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.List;
1717
import java.util.concurrent.ExecutorService;
1818
import java.util.concurrent.Executors;
19+
import java.util.concurrent.TimeUnit;
1920
import java.util.concurrent.TimeoutException;
2021
import java.util.logging.Level;
2122

@@ -33,6 +34,7 @@
3334
import static org.junit.jupiter.api.Assertions.assertThrows;
3435
import static org.junit.jupiter.api.Assertions.assertTrue;
3536

37+
import net.sf.jsqlparser.test.MemoryLeakVerifier;
3638
import org.junit.jupiter.api.Assertions;
3739
import org.junit.jupiter.api.Disabled;
3840
import org.junit.jupiter.api.Test;
@@ -296,6 +298,96 @@ public void testCondExpressionIssue1482_2() throws JSQLParserException {
296298
assertEquals("test_table_enum.f1_enum IN ('TEST2'::test.\"test_enum\")", expr.toString());
297299
}
298300

301+
302+
/**
303+
* The purpose of the test is to run into a timeout and to stop the parser when this happens. We
304+
* provide an INVALID statement for this purpose, which will fail the SIMPLE parse and then hang
305+
* with COMPLEX parsing until the timeout occurs.
306+
* <p>
307+
* We repeat that test multiple times and want to see no stale references to the Parser after
308+
* timeout.
309+
*
310+
* @throws JSQLParserException
311+
*/
312+
@Test
313+
public void testParserInterruptedByTimeout() throws InterruptedException {
314+
String sqlStr = "SELECT * FROM TABLE_1 t1\n"
315+
+ "WHERE\n"
316+
+ "(((t1.COL1 = 'VALUE2' )\n"
317+
+ "AND (t1.CAL2 = 'VALUE2' ))\n"
318+
+ "AND (((1 = 1 )\n"
319+
+ "AND ((((((t1.id IN (940550 ,940600 ,940650 ,940700 ,940750 ,940800 ,940850 ,940900 ,940950 ,941000 ,941050 ,941100 ,941150 ,941200 ,941250 ,941300 ,941350 ,941400 ,941450 ,941500 ,941550 ,941600 ,941650 ,941700 ,941750 ,941800 ,941850 ,941900 ,941950 ,942000 ,942050 ,942100 ,942150 ,942200 ,942250 ,942300 ,942350 ,942400 ,942450 ,942500 ,942550 ,942600 ,942650 ,942700 ,942750 ,942800 ,942850 ,942900 ,942950 ,943000 ,943050 ,943100 ,943150 ,943200 ,943250 ,943300 ,943350 ,943400 ,943450 ,943500 ,943550 ,943600 ,943650 ,943700 ,943750 ,943800 ,943850 ,943900 ,943950 ,944000 ,944050 ,944100 ,944150 ,944200 ,944250 ,944300 ,944350 ,944400 ,944450 ,944500 ,944550 ,944600 ,944650 ,944700 ,944750 ,944800 ,944850 ,944900 ,944950 ,945000 ,945050 ,945100 ,945150 ,945200 ,945250 ,945300 ))\n"
320+
+ "OR (t1.id IN (945350 ,945400 ,945450 ,945500 ,945550 ,945600 ,945650 ,945700 ,945750 ,945800 ,945850 ,945900 ,945950 ,946000 ,946050 ,946100 ,946150 ,946200 ,946250 ,946300 ,946350 ,946400 ,946450 ,946500 ,946550 ,946600 ,946650 ,946700 ,946750 ,946800 ,946850 ,946900 ,946950 ,947000 ,947050 ,947100 ,947150 ,947200 ,947250 ,947300 ,947350 ,947400 ,947450 ,947500 ,947550 ,947600 ,947650 ,947700 ,947750 ,947800 ,947850 ,947900 ,947950 ,948000 ,948050 ,948100 ,948150 ,948200 ,948250 ,948300 ,948350 ,948400 ,948450 ,948500 ,948550 ,948600 ,948650 ,948700 ,948750 ,948800 ,948850 ,948900 ,948950 ,949000 ,949050 ,949100 ,949150 ,949200 ,949250 ,949300 ,949350 ,949400 ,949450 ,949500 ,949550 ,949600 ,949650 ,949700 ,949750 ,949800 ,949850 ,949900 ,949950 ,950000 ,950050 ,950100 )))\n"
321+
+ "OR (t1.id IN (950150 ,950200 ,950250 ,950300 ,950350 ,950400 ,950450 ,950500 ,950550 ,950600 ,950650 ,950700 ,950750 ,950800 ,950850 ,950900 ,950950 ,951000 ,951050 ,951100 ,951150 ,951200 ,951250 ,951300 ,951350 ,951400 ,951450 ,951500 ,951550 ,951600 ,951650 ,951700 ,951750 ,951800 ,951850 ,951900 ,951950 ,952000 ,952050 ,952100 ,952150 ,952200 ,952250 ,952300 ,952350 ,952400 ,952450 ,952500 ,952550 ,952600 ,952650 ,952700 ,952750 ,952800 ,952850 ,952900 ,952950 ,953000 ,953050 ,953100 ,953150 ,953200 ,953250 ,953300 ,953350 ,953400 ,953450 ,953500 ,953550 ,953600 ,953650 ,953700 )))\n"
322+
+ "OR (t1.id IN (953750 ,953800 ,953850 ,953900 ,953950 ,954000 ,954050 ,954100 ,954150 ,954200 ,954250 ,954300 ,954350 ,954400 ,954450 ,954500 ,954550 ,954600 ,954650 ,954700 ,954750 ,954800 ,954850 ,954900 ,954950 ,955000 ,955050 ,955100 ,955150 ,955200 ,955250 ,955300 ,955350 ,955400 ,955450 ,955500 ,955550 ,955600 ,955650 ,955700 ,955750 ,955800 ,955850 ,955900 ,955950 ,956000 ,956050 ,956100 ,956150 ,956200 ,956250 ,956300 ,956350 ,956400 ,956450 ,956500 ,956550 ,956600 ,956650 ,956700 ,956750 ,956800 ,956850 ,956900 ,956950 ,957000 ,957050 ,957100 ,957150 ,957200 ,957250 ,957300 )))\n"
323+
+ "OR (t1.id IN (944100, 944150, 944200, 944250, 944300, 944350, 944400, 944450, 944500, 944550, 944600, 944650, 944700, 944750, 944800, 944850, 944900, 944950, 945000 )))\n"
324+
+ "OR (t1.id IN (957350 ,957400 ,957450 ,957500 ,957550 ,957600 ,957650 ,957700 ,957750 ,957800 ,957850 ,957900 ,957950 ,958000 ,958050 ,958100 ,958150 ,958200 ,958250 ,958300 ,958350 ,958400 ,958450 ,958500 ,958550 ,958600 ,958650 ,958700 ,958750 ,958800 ,958850 ,958900 ,958950 ,959000 ,959050 ,959100 ,959150 ,959200 ,959250 ,959300 ,959350 ,959400 ,959450 ,959500 ,959550 ,959600 ,959650 ,959700 ,959750 ,959800 ,959850 ,959900 ,959950 ,960000 ,960050 ,960100 ,960150 ,960200 ,960250 ,960300 ,960350 ,960400 ,960450 ,960500 ,960550 ,960600 ,960650 ,960700 ,960750 ,960800 ,960850 ,960900 ,960950 ,961000 ,961050 ,961100 ,961150 ,961200 ,961250 ,961300 ,961350 ,961400 ,961450 ,961500 ,961550 ,961600 ,961650 ,961700 ,961750 ,961800 ,961850 ,961900 ,961950 ,962000 ,962050 ,962100 ))))\n"
325+
+ "OR (t1.id IN (962150 ,962200 ,962250 ,962300 ,962350 ,962400 ,962450 ,962500 ,962550 ,962600 ,962650 ,962700 ,962750 ,962800 ,962850 ,962900 ,962950 ,963000 ,963050 ,963100 ,963150 ,963200 ,963250 ,963300 ,963350 ,963400 ,963450 ,963500 ,963550 ,963600 ,963650 ,963700 ,963750 ,963800 ,963850 ,963900 ,963950 ,964000 ,964050 ,964100 ,964150 ,964200 ,964250 ,964300 ,964350 ,964400 ,964450 ,964500 ,964550 ,964600 ,964650 ,964700 ,964750 ,964800 ,964850 ,964900 ,964950 ,965000 ,965050 ,965100 ,965150 ,965200 ,965250 ,965300 ,965350 ,965400 ,965450 ,965500 ))))\n"
326+
+ "AND t1.COL3 IN (\n"
327+
+ " SELECT\n"
328+
+ " t2.COL3\n"
329+
+ " FROM\n"
330+
+ " TABLE_6 t6,\n"
331+
+ " TABLE_1 t5,\n"
332+
+ " TABLE_4 t4,\n"
333+
+ " TABLE_3 t3,\n"
334+
+ " TABLE_1 t2\n"
335+
+ " WHERE\n"
336+
+ " (((((((t5.CAL3 = T6.id)\n"
337+
+ " AND (t5.CAL5 = t6.CAL5))\n"
338+
+ " AND (t5.CAL1 = t6.CAL1))\n"
339+
+ " AND (t3.CAL1 IN (108500)))\n"
340+
+ " AND (t5.id = t2.id))\n"
341+
+ " AND NOT ((t6.CAL6 IN ('VALUE'))))\n"
342+
+ " AND ((t2.id = t3.CAL2)\n"
343+
+ " AND (t4.id = t3.CAL3))))\n" +
344+
// add two redundant unmatched brackets in order to make the Simple Parser fail
345+
// and get the complex parser stuck
346+
" )) \n"
347+
+ "ORDER BY\n"
348+
+ "t1.id ASC";
349+
350+
MemoryLeakVerifier verifier = new MemoryLeakVerifier();
351+
352+
int parallelThreads = Runtime.getRuntime().availableProcessors() + 1;
353+
ExecutorService executorService = Executors.newFixedThreadPool(parallelThreads);
354+
ExecutorService timeOutService = Executors.newSingleThreadExecutor();
355+
for (int i = 0; i < parallelThreads; i++) {
356+
executorService.submit(new Runnable() {
357+
@Override
358+
public void run() {
359+
360+
try {
361+
CCJSqlParser parser =
362+
CCJSqlParserUtil.newParser(sqlStr).withAllowComplexParsing(true);
363+
verifier.addObject(parser);
364+
365+
Statement statement =
366+
CCJSqlParserUtil.parseStatement(parser, timeOutService);
367+
} catch (JSQLParserException ignore) {
368+
// We expected that to happen.
369+
}
370+
}
371+
});
372+
}
373+
374+
executorService.shutdown();
375+
timeOutService.shutdown();
376+
377+
// we should not run in any timeout here (because we expect that the Parser has timed out by
378+
// itself)
379+
Assertions.assertDoesNotThrow(new Executable() {
380+
@Override
381+
public void execute() throws Throwable {
382+
executorService.awaitTermination(10, TimeUnit.SECONDS);
383+
timeOutService.awaitTermination(10, TimeUnit.SECONDS);
384+
}
385+
});
386+
387+
// we should not have any Objects left in the weak reference map
388+
verifier.assertGarbageCollected();
389+
}
390+
299391
@Test
300392
public void testTimeOutIssue1582() throws InterruptedException {
301393
// This statement is INVALID on purpose
@@ -304,15 +396,15 @@ public void testTimeOutIssue1582() throws InterruptedException {
304396

305397
String sqlStr = ""
306398
+ "select\n"
307-
+ " t0.operatienr\n"
308-
+ " , case\n"
309-
+ " when\n"
310-
+ " case when (t0.vc_begintijd_operatie is null or lpad((extract('hours' into t0.vc_begintijd_operatie::timestamp))::text,2,'0') ||':'|| lpad(extract('minutes' from t0.vc_begintijd_operatie::timestamp)::text,2,'0') = '00:00') then null\n"
311-
+ " else (greatest(((extract('hours' into (t0.vc_eindtijd_operatie::timestamp-t0.vc_begintijd_operatie::timestamp))*60 + extract('minutes' from (t0.vc_eindtijd_operatie::timestamp-t0.vc_begintijd_operatie::timestamp)))/60)::numeric(12,2),0))*60\n"
312-
+ " end = 0 then null\n"
313-
+ " else '25. Meer dan 4 uur'\n"
314-
+ " end \n"
315-
+ " as snijtijd_interval";
399+
+ " t0.operatienr\n"
400+
+ " , case\n"
401+
+ " when\n"
402+
+ " case when (t0.vc_begintijd_operatie is null or lpad((extract('hours' into t0.vc_begintijd_operatie::timestamp))::text,2,'0') ||':'|| lpad(extract('minutes' from t0.vc_begintijd_operatie::timestamp)::text,2,'0') = '00:00') then null\n"
403+
+ " else (greatest(((extract('hours' into (t0.vc_eindtijd_operatie::timestamp-t0.vc_begintijd_operatie::timestamp))*60 + extract('minutes' from (t0.vc_eindtijd_operatie::timestamp-t0.vc_begintijd_operatie::timestamp)))/60)::numeric(12,2),0))*60\n"
404+
+ " end = 0 then null\n"
405+
+ " else '25. Meer dan 4 uur'\n"
406+
+ " end \n"
407+
+ " as snijtijd_interval";
316408

317409
// With DEFAULT TIMEOUT 6 Seconds, we expect the statement to timeout normally
318410
// A TimeoutException wrapped into a Parser Exception should be thrown
@@ -359,7 +451,7 @@ public void execute() throws Throwable {
359451

360452
@Test
361453
@Timeout(2000)
362-
void testIssue1792() throws JSQLParserException {
454+
void testIssue1792() throws JSQLParserException, InterruptedException {
363455
String sqlStr =
364456
"SELECT ('{\"obj\":{\"field\": \"value\"}}'::JSON -> 'obj'::TEXT ->> 'field'::TEXT)";
365457

@@ -378,11 +470,13 @@ public void execute() throws Throwable {
378470
}
379471
});
380472
executorService.shutdown();
473+
executorService.awaitTermination(1, TimeUnit.MINUTES);
474+
CCJSqlParserUtil.LOGGER.setLevel(Level.OFF);
381475
}
382476

383477
// Supposed to time out
384478
@Test
385-
void testComplexIssue1792() throws JSQLParserException {
479+
void testComplexIssue1792() throws JSQLParserException, InterruptedException {
386480
ExecutorService executorService = Executors.newCachedThreadPool();
387481

388482
String sqlStr =
@@ -422,5 +516,7 @@ void testComplexIssue1792() throws JSQLParserException {
422516
assertTrue(ex.getCause() instanceof TimeoutException);
423517
}
424518
executorService.shutdown();
519+
executorService.awaitTermination(1, TimeUnit.MINUTES);
520+
CCJSqlParserUtil.LOGGER.setLevel(Level.OFF);
425521
}
426522
}

0 commit comments

Comments
 (0)