Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
de805ab
Adjust Gradle to JUnit 5
manticore-projects Nov 22, 2021
d5a6dca
Do not mark SpeedTest for concurrent execution
manticore-projects Nov 24, 2021
a9d0503
Remove unused imports
manticore-projects Nov 28, 2021
6dfa05f
Adjust Gradle to JUnit 5
manticore-projects Nov 22, 2021
8f0bfe6
Do not mark SpeedTest for concurrent execution
manticore-projects Nov 24, 2021
5cd0974
Remove unused imports
manticore-projects Nov 28, 2021
5f11d3f
Merge remote-tracking branch 'origin/master'
manticore-projects Nov 28, 2021
b393e00
Performance Improvements
manticore-projects Dec 10, 2021
cb3c91a
Appease PMD
manticore-projects Dec 10, 2021
cdc56c7
Resolve conflicts
manticore-projects Dec 10, 2021
f14cf33
Update Gradle Plugins to its latest versions
manticore-projects Dec 11, 2021
82ce02b
Revert unintended changes to the Test Resources
manticore-projects Dec 11, 2021
c984ff6
Appease PMD/Codacy
manticore-projects Dec 11, 2021
3ab04b0
Merge https://github.com/JSQLParser/JSqlParser
manticore-projects Dec 21, 2021
c075544
Merge branch 'master' into Issue1438
manticore-projects Dec 21, 2021
79bcbc9
Correct the Gradle "+" dependencies
manticore-projects Dec 21, 2021
4c38284
Bump version to 4.4.-SNAPSHOT
manticore-projects Dec 21, 2021
e25ee10
update build file
manticore-projects Dec 30, 2021
de94651
Merge branch 'JSQLParser:master' into master
manticore-projects Jan 24, 2022
84709a9
Merge branch 'master' of github.com:JSQLParser/JSqlParser
manticore-projects Mar 22, 2022
cba3125
revert unwarranted changes in test files
manticore-projects Mar 29, 2022
3b08fde
Merge remote-tracking branch 'origin/master' into Issue1438
manticore-projects Mar 29, 2022
960aaf2
strip the Exception Class Name from the Message
manticore-projects Mar 29, 2022
592de64
maxDepth = 10 collides with the Parser Timeout = 6 seconds
manticore-projects Mar 29, 2022
31caad9
License Headers
manticore-projects Mar 29, 2022
3c8da30
Merge branch 'master' of github.com:JSQLParser/JSqlParser
manticore-projects Apr 4, 2022
4cef39b
Merge branch 'master' into Issue1438
manticore-projects Apr 4, 2022
55f083f
Merge remote-tracking branch 'origin/master' into Issue1438
manticore-projects Apr 14, 2022
2bd7dee
Bump version to 4.5-SNAPSHOT
manticore-projects Apr 14, 2022
d7d2dbe
Merge remote-tracking branch 'manticore/Issue1438' into Issue1438
manticore-projects Apr 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update Gradle Plugins to its latest versions
Let Parser timeout after 6 seconds and fail gently
Add a special test verifying the clean up after timeout
  • Loading branch information
manticore-projects committed Dec 11, 2021
commit f14cf33f5a2554ef9366b6d7f6ca38fea6b6507a
17 changes: 5 additions & 12 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
plugins {
id 'java'
id 'maven-publish'
id "ca.coglinc2.javacc" version "3.0.0"
id "ca.coglinc2.javacc" version "latest.release"
id 'jacoco'
id "com.github.spotbugs" version "4.7.2"
id "com.github.spotbugs" version "latest.release"
id 'pmd'
id 'checkstyle'

// download the RR tools which have no Maven Repository
id "de.undercouch.download" version "4.1.2"
id "de.undercouch.download" version "latest.release"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious. Does this work the same way maven dependency versioning works like [1.0,2.0)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not know about Maven does (In fact I hate Maven. You can't even clean a project while offline. I went straight from ANT to Gradle, which "just understands and does what I want" instead of forcing me into any dogma). This latest.release automatically retrieves the Latest Release of a Gradle Plugin.

}

group = 'com.github.jsqlparser'
Expand Down Expand Up @@ -46,13 +46,6 @@ dependencies {

// enforce latest version of JavaCC
javacc 'net.java.dev.javacc:javacc:7.0.10'

// https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter
testImplementation 'org.mockito:mockito-junit-jupiter:4.1.0'

// enforce latest version of JavaCC
javacc 'net.java.dev.javacc:javacc:7.0.10'

}

compileJavacc {
Expand Down Expand Up @@ -179,7 +172,7 @@ spotbugs {

pmd {
consoleOutput = false
toolVersion = "6.36.0"
toolVersion = "6.41.0"

sourceSets = [sourceSets.main]

Expand All @@ -198,7 +191,7 @@ pmd {
}

checkstyle {
toolVersion "8.45.1"
toolVersion "9.2"
sourceSets = [sourceSets.main, sourceSets.test]
configFile =rootProject.file('config/checkstyle/checkstyle.xml')
}
Expand Down
2 changes: 1 addition & 1 deletion ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ under the License.
<rule ref="category/java/errorprone.xml/UselessOperationOnImmutable" />

<!-- for Codazy -->
<rule ref="category/java/errorprone.xml/MissingBreakInSwitch" />
<!-- <rule ref="category/java/errorprone.xml/MissingBreakInSwitch" /> -->

<rule ref="category/java/multithreading.xml/AvoidThreadGroup" />
<rule ref="category/java/multithreading.xml/DontCallThreadRun" />
Expand Down
41 changes: 39 additions & 2 deletions src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
Expand All @@ -23,8 +29,11 @@
*
* @author toben
*/

@SuppressWarnings("PMD.CyclomaticComplexity")
public final class CCJSqlParserUtil {
public final static int ALLOWED_NESTING_DEPTH = 10;
public static final int PARSER_TIMEOUT = 6000;

private CCJSqlParserUtil() {
}
Expand Down Expand Up @@ -235,11 +244,25 @@ public static Expression parseCondExpression(String conditionalExpressionStr, bo
* @throws JSQLParserException
*/
public static Statement parseStatement(CCJSqlParser parser) throws JSQLParserException {
Statement statement = null;
try {
return parser.Statement();
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Statement> future = executorService.submit(new Callable<Statement>() {
@Override
public Statement call() throws Exception {
return parser.Statement();
}
});
executorService.shutdown();

statement = future.get(PARSER_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
parser.interrupted = true;
throw new JSQLParserException("Time out occurred.", ex);
} catch (Exception ex) {
throw new JSQLParserException(ex);
}
return statement;
}

/**
Expand Down Expand Up @@ -270,11 +293,25 @@ public static Statements parseStatements(String sqls) throws JSQLParserException
* @throws JSQLParserException
*/
public static Statements parseStatements(CCJSqlParser parser) throws JSQLParserException {
Statements statements = null;
try {
return parser.Statements();
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Statements> future = executorService.submit(new Callable<Statements>() {
@Override
public Statements call() throws Exception {
return parser.Statements();
}
});
executorService.shutdown();

statements = future.get(PARSER_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
parser.interrupted = true;
throw new JSQLParserException("Time out occurred.", ex);
} catch (Exception ex) {
throw new JSQLParserException(ex);
}
return statements;
}

public static void streamStatements(StatementListener listener, InputStream is, String encoding) throws JSQLParserException {
Expand Down
43 changes: 22 additions & 21 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import java.util.*;
public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
public int bracketsCounter = 0;
public int caseCounter = 0;
public boolean interrupted = false;

public CCJSqlParser withConfiguration(FeatureConfiguration configuration) {
token_source.configuration = configuration;
Expand Down Expand Up @@ -3296,7 +3297,7 @@ ExpressionList SimpleExpressionList(boolean outerBrackets) #ExpressionList:
}
{
expr=SimpleExpression() { expressions.add(expr); }
( LOOKAHEAD(2) "," expr=SimpleExpression() { expressions.add(expr); } )*
( LOOKAHEAD(2, {!interrupted} ) "," expr=SimpleExpression() { expressions.add(expr); } )*
{
retval.setExpressions(expressions);
return retval;
Expand All @@ -3316,7 +3317,7 @@ ExpressionList ComplexExpressionList() #ExpressionList:
) { expressions.add(expr); }

(
LOOKAHEAD(2) ","
LOOKAHEAD(2, {!interrupted}) ","
(
LOOKAHEAD(2) expr=OracleNamedFunctionParameter()
| expr=Expression()
Expand Down Expand Up @@ -3657,62 +3658,62 @@ Expression PrimaryExpression() #PrimaryExpression:
(
<K_NULL> { retval = new NullValue(); }

| LOOKAHEAD(3) retval=CaseWhenExpression()
| LOOKAHEAD(3, {!interrupted}) retval=CaseWhenExpression()

| retval = SimpleJdbcParameter()

| LOOKAHEAD(2) retval=JdbcNamedParameter()
| LOOKAHEAD(2, {!interrupted}) retval=JdbcNamedParameter()

| retval=UserVariable()

| LOOKAHEAD(2) retval=NumericBind()
| LOOKAHEAD(2, {!interrupted}) retval=NumericBind()

| LOOKAHEAD(3) retval=ExtractExpression()
| LOOKAHEAD(3, {!interrupted}) retval=ExtractExpression()

| retval=MySQLGroupConcat()

| retval=XMLSerializeExpr()

| LOOKAHEAD(JsonExpression()) retval=JsonExpression()
| LOOKAHEAD(JsonExpression(), {!interrupted}) retval=JsonExpression()

| LOOKAHEAD(JsonFunction()) retval = JsonFunction()
| LOOKAHEAD(JsonFunction(), {!interrupted}) retval = JsonFunction()

| LOOKAHEAD(JsonAggregateFunction()) retval = JsonAggregateFunction()
| LOOKAHEAD(JsonAggregateFunction(), {!interrupted}) retval = JsonAggregateFunction()

/* | LOOKAHEAD(FunctionWithCondParams()) retval = FunctionWithCondParams() */

| LOOKAHEAD(FullTextSearch()) retval = FullTextSearch()
| LOOKAHEAD(FullTextSearch(), {!interrupted}) retval = FullTextSearch()

| LOOKAHEAD(Function()) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ]
| LOOKAHEAD(Function(), {!interrupted}) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ]

| LOOKAHEAD(2) retval = IntervalExpression() { dateExpressionAllowed = false; }
| LOOKAHEAD(2, {!interrupted}) retval = IntervalExpression() { dateExpressionAllowed = false; }

| token=<S_DOUBLE> { retval = new DoubleValue(token.image); }

| token=<S_LONG> { retval = new LongValue(token.image); }

| token=<S_HEX> { retval = new HexValue(token.image); }

| LOOKAHEAD(2) retval=CastExpression()
| LOOKAHEAD(2, {!interrupted}) retval=CastExpression()

| LOOKAHEAD(2) retval=TryCastExpression()
| LOOKAHEAD(2, {!interrupted}) retval=TryCastExpression()

//| LOOKAHEAD(2) retval=RowConstructor()

// support timestamp expressions
| (token=<K_TIME_KEY_EXPR> | token=<K_CURRENT>) { retval = new TimeKeyExpression(token.image); }

| LOOKAHEAD(2) retval=DateTimeLiteralExpression()
| LOOKAHEAD(2, {!interrupted}) retval=DateTimeLiteralExpression()

| LOOKAHEAD(2) <K_ARRAY_LITERAL> retval=ArrayConstructor(true)
| LOOKAHEAD(2, {!interrupted}) <K_ARRAY_LITERAL> retval=ArrayConstructor(true)

| LOOKAHEAD(2) retval = NextValExpression()
| LOOKAHEAD(2, {!interrupted}) retval = NextValExpression()

| retval=ConnectByRootOperator()

| LOOKAHEAD(2) <K_ALL> { retval = new AllValue(); }
| LOOKAHEAD(2, {!interrupted}) <K_ALL> { retval = new AllValue(); }

| LOOKAHEAD(2) retval=Column()
| LOOKAHEAD(2, {!interrupted}) retval=Column()

| token=<S_CHAR_LITERAL> { retval = new StringValue(token.image); linkAST(retval,jjtThis); }

Expand All @@ -3722,10 +3723,10 @@ Expression PrimaryExpression() #PrimaryExpression:

| "{ts" token=<S_CHAR_LITERAL> "}" { retval = new TimestampValue(token.image); }

| LOOKAHEAD("(" retval=SubSelect() ")") "(" retval=SubSelect() ")"
| LOOKAHEAD("(" retval=SubSelect() ")", {!interrupted} ) "(" retval=SubSelect() ")"

| (
"(" ( LOOKAHEAD( { getAsBoolean(Feature.allowComplexParsing) } ) list = ComplexExpressionList() | list = SimpleExpressionList(true) ) ")"
"(" ( LOOKAHEAD( { getAsBoolean(Feature.allowComplexParsing) && !interrupted } ) list = ComplexExpressionList() | list = SimpleExpressionList(true) ) ")"
{
if (list.getExpressions().size() == 1) {
retval = new Parenthesis(list.getExpressions().get(0));
Expand Down
90 changes: 90 additions & 0 deletions src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import net.sf.jsqlparser.parser.CCJSqlParser;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
Expand All @@ -36,6 +40,8 @@
import net.sf.jsqlparser.statement.StatementVisitorAdapter;
import net.sf.jsqlparser.statement.Statements;
import static net.sf.jsqlparser.test.TestUtils.*;

import net.sf.jsqlparser.test.MemoryLeakVerifier;
import org.apache.commons.io.IOUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
Expand All @@ -45,9 +51,11 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;

Expand Down Expand Up @@ -5028,4 +5036,86 @@ public void testPerformanceIssue1397() throws Exception {
String sqlStr = IOUtils.toString( SelectTest.class.getResource( "/net/sf/jsqlparser/statement/select/performanceIssue1397.sql" ), Charset.defaultCharset() );
assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

/**
* The purpose of the test is to run into a timeout and to stop the parser when this happens.
* We provide an INVALID statement for this purpose, which will fail the SIMPLE parse
* and then hang with COMPLEX parsing until the timeout occurs.
*
* We repeat that test multiple times and want to see no stale references to the Parser after timeout.
*
* @throws JSQLParserException
*/
@Test
public void testParserInterruptedByTimeout() {
String sqlStr = "" +
"SELECT \t* FROM TABLE_1 t1\n" +
"WHERE\n" +
"\t(((t1.COL1 = 'VALUE2' )\n" +
"\t\tAND (t1.CAL2 = 'VALUE2' ))\n" +
"\t\tAND (((1 = 1 )\n" +
"\t\t\tAND ((((((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" +
"\t\t\t\tOR (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" +
"\t\t\t\tOR (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" +
"\t\t\t\tOR (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" +
"\t\t\t\tOR (t1.id IN (944100, 944150, 944200, 944250, 944300, 944350, 944400, 944450, 944500, 944550, 944600, 944650, 944700, 944750, 944800, 944850, 944900, 944950, 945000 )))\n" +
"\t\t\t\tOR (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" +
"\t\t\t\tOR (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" +
"\tAND t1.COL3 IN (\n" +
"\t SELECT\n" +
"\t\t t2.COL3\n" +
"\t FROM\n" +
"\t\t TABLE_6 t6,\n" +
"\t\t TABLE_1 t5,\n" +
"\t\t TABLE_4 t4,\n" +
"\t\t TABLE_3 t3,\n" +
"\t\t TABLE_1 t2\n" +
"\t WHERE\n" +
"\t\t (((((((t5.CAL3 = T6.id)\n" +
"\t\t\t AND (t5.CAL5 = t6.CAL5))\n" +
"\t\t\t AND (t5.CAL1 = t6.CAL1))\n" +
"\t\t\t AND (t3.CAL1 IN (108500)))\n" +
"\t\t\t AND (t5.id = t2.id))\n" +
"\t\t\t AND NOT ((t6.CAL6 IN ('VALUE'))))\n" +
"\t\t\t AND ((t2.id = t3.CAL2)\n" +
"\t\t\t\t AND (t4.id = t3.CAL3))))\n" +
// add two redundant unmatched brackets in order to make the Simple Parser fail
// and the complex parser stuck
" )) \n" +
"ORDER BY\n" +
"\tt1.id ASC";

MemoryLeakVerifier verifier = new MemoryLeakVerifier();

int parallelThreads = Runtime.getRuntime().availableProcessors() + 1;
ExecutorService executorService = Executors.newFixedThreadPool(parallelThreads);

for (int i=0; i<parallelThreads; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
try {
CCJSqlParser parser = CCJSqlParserUtil.newParser(sqlStr).withAllowComplexParsing(true);
verifier.addObject(parser);

Statement statement = CCJSqlParserUtil.parseStatement(parser);
} catch (JSQLParserException ignore) {
// We expected that to happen.
}
}
});
}
executorService.shutdown();

// we should not run in any timeout here (because we expect that the Parser has timed out by itself)
Assertions.assertDoesNotThrow(new Executable() {
@Override
public void execute() throws Throwable {
executorService.awaitTermination(10, TimeUnit.SECONDS);
}
});

// we should not have any Objects left in the weak reference map
verifier.assertGarbageCollected();
}
}
Loading