From 4f0488ccb4611f0b6cd06fdb27db81a779636508 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Wed, 17 May 2023 16:06:50 +0700 Subject: [PATCH] fix: Complex Parsing Approach - optionally provide a global Executor, instead spawning one for each parse - run into Complex Parsing only, when Complex Parsing was allowed - provide a Logger - fixes #1792 --- .../jsqlparser/parser/CCJSqlParserUtil.java | 120 ++++++++++++------ .../util/validation/ParseCapability.java | 19 ++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 45 ++++--- .../parser/CCJSqlParserUtilTest.java | 74 +++++++++++ .../statement/ShowStatementTest.java | 2 +- .../statement/UnsupportedStatementTest.java | 35 ++--- .../statement/create/CreateTableTest.java | 18 +-- .../statement/select/SelectTest.java | 7 +- 8 files changed, 232 insertions(+), 88 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java index 81cf095b9..5ea5ff05a 100644 --- a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java +++ b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java @@ -19,6 +19,9 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; + import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.parser.feature.Feature; @@ -33,13 +36,25 @@ @SuppressWarnings("PMD.CyclomaticComplexity") public final class CCJSqlParserUtil { + public final static Logger LOGGER = Logger.getLogger(CCJSqlParserUtil.class.getName()); + static { + LOGGER.setLevel(Level.WARNING); + } + public final static int ALLOWED_NESTING_DEPTH = 10; private CCJSqlParserUtil() {} public static Statement parse(Reader statementReader) throws JSQLParserException { + ExecutorService executorService = Executors.newSingleThreadExecutor(); + Statement statement = null; CCJSqlParser parser = new CCJSqlParser(new StreamProvider(statementReader)); - return parseStatement(parser); + try { + statement = parseStatement(parser, executorService); + } finally { + executorService.shutdown(); + } + return statement; } public static Statement parse(String sql) throws JSQLParserException { @@ -62,22 +77,41 @@ public static Statement parse(String sql) throws JSQLParserException { */ public static Statement parse(String sql, Consumer consumer) throws JSQLParserException { + + ExecutorService executorService = Executors.newSingleThreadExecutor(); + Statement statement = null; + try { + statement = parse(sql, executorService, consumer); + } finally { + executorService.shutdown(); + } + return statement; + } + + public static Statement parse(String sql, ExecutorService executorService, + Consumer consumer) + throws JSQLParserException { Statement statement = null; // first, try to parse fast and simple + CCJSqlParser parser = newParser(sql); + if (consumer != null) { + consumer.accept(parser); + } + boolean allowComplex = parser.getConfiguration().getAsBoolean(Feature.allowComplexParsing); + LOGGER.info("Allowed Complex Parsing: " + allowComplex); try { - CCJSqlParser parser = newParser(sql).withAllowComplexParsing(false); - if (consumer != null) { - consumer.accept(parser); - } - statement = parseStatement(parser); + LOGGER.info("Trying SIMPLE parsing " + (allowComplex ? "first" : "only")); + statement = parseStatement(parser.withAllowComplexParsing(false), executorService); } catch (JSQLParserException ex) { - if (getNestingDepth(sql) <= ALLOWED_NESTING_DEPTH) { - CCJSqlParser parser = newParser(sql).withAllowComplexParsing(true); + if (allowComplex && getNestingDepth(sql) <= ALLOWED_NESTING_DEPTH) { + LOGGER.info("Trying COMPLEX parsing when SIMPLE parsing failed"); + // beware: the parser must not be reused, but needs to be re-initiated + parser = newParser(sql); if (consumer != null) { consumer.accept(parser); } - statement = parseStatement(parser); + statement = parseStatement(parser.withAllowComplexParsing(true), executorService); } else { throw ex; } @@ -252,24 +286,25 @@ public static Expression parseCondExpression(String conditionalExpressionStr, } /** - * @param parser - * @return the statement parsed - * @throws JSQLParserException + * @param parser the Parser armed with a Statement text + * @param executorService the Executor Service for parsing within a Thread + * @return the parsed Statement + * @throws JSQLParserException when either the Statement can't be parsed or the configured + * timeout is reached */ - public static Statement parseStatement(CCJSqlParser parser) throws JSQLParserException { + + public static Statement parseStatement(CCJSqlParser parser, ExecutorService executorService) + throws JSQLParserException { Statement statement = null; try { - ExecutorService executorService = Executors.newSingleThreadExecutor(); Future future = executorService.submit(new Callable() { @Override public Statement call() throws Exception { return parser.Statement(); } }); - executorService.shutdown(); - - statement = future.get( parser.getConfiguration().getAsLong(Feature.timeOut), TimeUnit.MILLISECONDS); - + statement = future.get(parser.getConfiguration().getAsLong(Feature.timeOut), + TimeUnit.MILLISECONDS); } catch (TimeoutException ex) { parser.interrupted = true; throw new JSQLParserException("Time out occurred.", ex); @@ -288,55 +323,68 @@ public static Statements parseStatements(String sqls) throws JSQLParserException return parseStatements(sqls, null); } + public static Statements parseStatements(String sqls, Consumer consumer) + throws JSQLParserException { + ExecutorService executorService = Executors.newSingleThreadExecutor(); + final Statements statements = parseStatements(sqls, executorService, consumer); + executorService.shutdown(); + + return statements; + } + /** * Parse a statement list. * * @return the statements parsed */ - public static Statements parseStatements(String sqls, Consumer consumer) + public static Statements parseStatements(String sqls, ExecutorService executorService, + Consumer consumer) throws JSQLParserException { Statements statements = null; + CCJSqlParser parser = newParser(sqls); + if (consumer != null) { + consumer.accept(parser); + } + boolean allowComplex = parser.getConfiguration().getAsBoolean(Feature.allowComplexParsing); + // first, try to parse fast and simple try { - CCJSqlParser parser = newParser(sqls).withAllowComplexParsing(false); - if (consumer != null) { - consumer.accept(parser); - } - statements = parseStatements(parser); + statements = parseStatements(parser.withAllowComplexParsing(false), executorService); } catch (JSQLParserException ex) { // when fast simple parsing fails, try complex parsing but only if it has a chance to // succeed - if (getNestingDepth(sqls) <= ALLOWED_NESTING_DEPTH) { - CCJSqlParser parser = newParser(sqls).withAllowComplexParsing(true); + if (allowComplex && getNestingDepth(sqls) <= ALLOWED_NESTING_DEPTH) { + // beware: parser must not be re-used but needs to be re-initiated + parser = newParser(sqls); if (consumer != null) { consumer.accept(parser); } - statements = parseStatements(parser); + statements = parseStatements(parser.withAllowComplexParsing(true), executorService); } } return statements; } /** - * @param parser - * @return the statements parsed - * @throws JSQLParserException + * @param parser the Parser armed with a Statement text + * @param executorService the Executor Service for parsing within a Thread + * @return the Statements (representing a List of single statements) + * @throws JSQLParserException when either the Statement can't be parsed or the configured + * timeout is reached */ - public static Statements parseStatements(CCJSqlParser parser) throws JSQLParserException { + public static Statements parseStatements(CCJSqlParser parser, ExecutorService executorService) + throws JSQLParserException { Statements statements = null; try { - ExecutorService executorService = Executors.newSingleThreadExecutor(); Future future = executorService.submit(new Callable() { @Override public Statements call() throws Exception { return parser.Statements(); } }); - executorService.shutdown(); - - statements = future.get( parser.getConfiguration().getAsLong(Feature.timeOut) , TimeUnit.MILLISECONDS); - + statements = future.get(parser.getConfiguration().getAsLong(Feature.timeOut), + TimeUnit.MILLISECONDS); } catch (TimeoutException ex) { parser.interrupted = true; throw new JSQLParserException("Time out occurred.", ex); diff --git a/src/main/java/net/sf/jsqlparser/util/validation/ParseCapability.java b/src/main/java/net/sf/jsqlparser/util/validation/ParseCapability.java index 606c19126..b0cf02ff0 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/ParseCapability.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/ParseCapability.java @@ -9,14 +9,16 @@ */ package net.sf.jsqlparser.util.validation; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.function.Consumer; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statements; /** - * package - private class for {@link Validation} to parse the statements - * within it's own {@link ValidationCapability} + * package - private class for {@link Validation} to parse the statements within it's own + * {@link ValidationCapability} * * @author gitmotte */ @@ -36,8 +38,7 @@ public String getStatements() { } /** - * @return null on parse error, otherwise the {@link Statements} - * parsed. + * @return null on parse error, otherwise the {@link Statements} parsed. */ public Statements getParsedStatements() { return parsedStatement; @@ -45,11 +46,17 @@ public Statements getParsedStatements() { @Override public void validate(ValidationContext context, Consumer errorConsumer) { + ExecutorService executorService = Executors.newSingleThreadExecutor(); try { this.parsedStatement = CCJSqlParserUtil.parseStatements( - CCJSqlParserUtil.newParser(statements).withConfiguration(context.getConfiguration())); + CCJSqlParserUtil.newParser(statements) + .withConfiguration(context.getConfiguration()), + executorService); } catch (JSQLParserException e) { - errorConsumer.accept(new ParseException("Cannot parse statement: " + e.getMessage(), e)); + errorConsumer + .accept(new ParseException("Cannot parse statement: " + e.getMessage(), e)); + } finally { + executorService.shutdown(); } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 5459328ec..66f5c339d 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -3081,7 +3081,7 @@ Expression AndExpression() : } { ( - LOOKAHEAD(Condition()) + LOOKAHEAD(Condition(), {!interrupted}) left=Condition() | [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] @@ -3093,7 +3093,7 @@ Expression AndExpression() : { boolean useOperator = false; } ( | {useOperator=true;} ) ( - LOOKAHEAD(Condition()) + LOOKAHEAD(Condition(), {!interrupted}) right=Condition() | [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] @@ -3216,8 +3216,8 @@ Expression SQLCondition(): { ( result=ExistsExpression() - | LOOKAHEAD(InExpression()) result=InExpression() - | LOOKAHEAD(OverlapsCondition()) result=OverlapsCondition() + | LOOKAHEAD(InExpression() , {!interrupted}) result=InExpression() + | LOOKAHEAD(OverlapsCondition(), {!interrupted}) result=OverlapsCondition() | left = SimpleExpression() { result = left; } [ LOOKAHEAD(2) ( @@ -3258,7 +3258,7 @@ Expression InExpression() #InExpression : ( LOOKAHEAD(2) token= { rightExpression = new StringValue(token.image); } | LOOKAHEAD(3) rightExpression = Function() - | LOOKAHEAD(ParenthesedSelect()) rightExpression = ParenthesedSelect() + | LOOKAHEAD(ParenthesedSelect(), {!interrupted}) rightExpression = ParenthesedSelect() | LOOKAHEAD(3) rightExpression = ParenthesedExpressionList() | rightExpression = SimpleExpression() ) @@ -4057,6 +4057,7 @@ JsonExpression JsonExpression() : { CastExpression castExpr = null; } { + // LOOKAHEAD(3, {getAsBoolean(Feature.allowComplexParsing) && !interrupted}) ( LOOKAHEAD(3, {!interrupted}) expr=CaseWhenExpression() | @@ -4066,13 +4067,13 @@ JsonExpression JsonExpression() : { | expr=UserVariable() | - LOOKAHEAD(JsonFunction(), {!interrupted}) expr = JsonFunction() + LOOKAHEAD(JsonFunction(), {getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expr = JsonFunction() | - LOOKAHEAD(JsonAggregateFunction(), {!interrupted}) expr = JsonAggregateFunction() + LOOKAHEAD(JsonAggregateFunction(), {getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expr = JsonAggregateFunction() | - LOOKAHEAD(FullTextSearch(), {!interrupted}) expr = FullTextSearch() + LOOKAHEAD(FullTextSearch(), {getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expr = FullTextSearch() | - LOOKAHEAD( 3 , {!interrupted && getAsBoolean(Feature.allowComplexParsing) } ) expr=Function() + LOOKAHEAD( 3 , {getAsBoolean(Feature.allowComplexParsing) && !interrupted} ) expr=Function() | LOOKAHEAD( 2, {!interrupted} ) expr=Column() | @@ -4551,9 +4552,14 @@ Expression CaseWhenExpression() #CaseWhenExpression: { caseCounter++; } [ switchExp=Expression() ] ( clause=WhenThenSearchCondition() { whenClauses.add(clause); } )+ - [ (LOOKAHEAD( ["("] CaseWhenExpression() [")"] ( | | ) ) ["("] elseExp=CaseWhenExpression() [")" { ((CaseExpression) elseExp).setUsingBrackets(true); } ] - | elseExp=Expression() - ) + [ + + ( + LOOKAHEAD(3, {!interrupted}) "(" elseExp=CaseWhenExpression() ")" { elseExp = new Parenthesis( elseExp ); } + | LOOKAHEAD(3, {!interrupted}) elseExp=CaseWhenExpression() + | LOOKAHEAD(3, {getAsBoolean(Feature.allowComplexParsing) && !interrupted}) elseExp=Expression() + | elseExp=SimpleExpression() + ) ] { caseCounter--; } { @@ -4567,16 +4573,17 @@ Expression CaseWhenExpression() #CaseWhenExpression: WhenClause WhenThenSearchCondition(): { WhenClause whenThen = new WhenClause(); - Expression whenExp = null; - Expression thenExp = null; + Expression whenExp; + Expression thenExp; } { whenExp=Expression() - ( - LOOKAHEAD( ["("] CaseWhenExpression() [")"] ( | | ) ) ["("] thenExp=CaseWhenExpression() [")" { ((CaseExpression) thenExp).setUsingBrackets(true); }] - | - thenExp=Expression() - ) + + ( + LOOKAHEAD({getAsBoolean(Feature.allowComplexParsing) && !interrupted}) thenExp=Expression() + | + thenExp=SimpleExpression() + ) { whenThen.setWhenExpression(whenExp); whenThen.setThenExpression(thenExp); diff --git a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java index b8d9e89a1..101cd9fc0 100644 --- a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java @@ -14,7 +14,10 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; +import java.util.logging.Level; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; @@ -26,11 +29,14 @@ import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statements; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +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; public class CCJSqlParserUtilTest { @@ -349,4 +355,72 @@ public void execute() throws Throwable { } }); } + + + @Test + @Timeout(2000) + void testIssue1792() throws JSQLParserException { + String sqlStr = + "SELECT ('{\"obj\":{\"field\": \"value\"}}'::JSON -> 'obj'::TEXT ->> 'field'::TEXT)"; + + + CCJSqlParserUtil.LOGGER.setLevel(Level.ALL); + ExecutorService executorService = Executors.newCachedThreadPool(); + + // Expect to fail within 6 seconds + Assertions.assertThrows(JSQLParserException.class, new Executable() { + @Override + public void execute() throws Throwable { + CCJSqlParserUtil.parse(sqlStr, executorService, parser -> { + parser.withTimeOut(6000); + parser.withAllowComplexParsing(true); + }); + } + }); + executorService.shutdown(); + } + + // Supposed to time out + @Test + void testComplexIssue1792() throws JSQLParserException { + ExecutorService executorService = Executors.newCachedThreadPool(); + + String sqlStr = + "SELECT\n" + + " CASE\n" + + " WHEN true\n" + + " THEN (SELECT ((('{\"obj\":{\"field\": \"value\"}}'::JSON -> 'obj'::TEXT ->> 'field'::TEXT))))\n" + + " END"; + + CCJSqlParserUtil.LOGGER.setLevel(Level.ALL); + + // Expect to fail fast with SIMPLE Parsing only when COMPLEX is not allowed + // No TIMEOUT Exception shall be thrown + // CCJSqlParserUtil.LOGGER will report: + // 1) Allowed Complex Parsing: false + // 2) Trying SIMPLE parsing only + try { + CCJSqlParserUtil.parse(sqlStr, executorService, parser -> { + parser.withTimeOut(6000); + parser.withAllowComplexParsing(false); + }); + } catch (JSQLParserException ex) { + assertFalse(ex.getCause() instanceof TimeoutException); + } + + // Expect to time-out with COMPLEX Parsing allowed + // CCJSqlParserUtil.LOGGER will report: + // 1) Allowed Complex Parsing: true + // 2) Trying SIMPLE parsing first + // 3) Trying COMPLEX parsing when SIMPLE parsing failed + try { + CCJSqlParserUtil.parse(sqlStr, executorService, parser -> { + parser.withTimeOut(6000); + parser.withAllowComplexParsing(true); + }); + } catch (JSQLParserException ex) { + assertTrue(ex.getCause() instanceof TimeoutException); + } + executorService.shutdown(); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/ShowStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/ShowStatementTest.java index 0a40a25bc..7f1033896 100644 --- a/src/test/java/net/sf/jsqlparser/statement/ShowStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/ShowStatementTest.java @@ -43,6 +43,6 @@ void testShowCreateTable() throws JSQLParserException { String sqlStr = "show create table my_table"; Statement statement = assertSqlCanBeParsedAndDeparsed(sqlStr, true); - Assertions.assertTrue( statement instanceof UnsupportedStatement); + Assertions.assertTrue(statement instanceof UnsupportedStatement); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/UnsupportedStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/UnsupportedStatementTest.java index 94d6492b8..cdf485358 100644 --- a/src/test/java/net/sf/jsqlparser/statement/UnsupportedStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/UnsupportedStatementTest.java @@ -24,12 +24,13 @@ public class UnsupportedStatementTest { public void testSingleUnsupportedStatement() throws JSQLParserException { String sqlStr = "this is an unsupported statement"; - assertSqlCanBeParsedAndDeparsed(sqlStr, true, parser -> parser.withUnsupportedStatements(true) ); + assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withUnsupportedStatements(true)); Assertions.assertThrowsExactly(JSQLParserException.class, new Executable() { @Override public void execute() throws Throwable { - CCJSqlParserUtil.parse(sqlStr, parser -> parser.withUnsupportedStatements(false) ); + CCJSqlParserUtil.parse(sqlStr, parser -> parser.withUnsupportedStatements(false)); } }); } @@ -38,7 +39,8 @@ public void execute() throws Throwable { public void testUnsupportedStatementsFirstInBlock() throws JSQLParserException { String sqlStr = "This is an unsupported statement; Select * from dual; Select * from dual;"; - Statements statements = CCJSqlParserUtil.parseStatements(sqlStr, parser -> parser.withUnsupportedStatements(true)); + Statements statements = CCJSqlParserUtil.parseStatements(sqlStr, + parser -> parser.withUnsupportedStatements(true)); Assertions.assertEquals(3, statements.getStatements().size()); Assertions.assertInstanceOf(UnsupportedStatement.class, statements.getStatements().get(0)); Assertions.assertInstanceOf(Select.class, statements.getStatements().get(1)); @@ -47,7 +49,8 @@ public void testUnsupportedStatementsFirstInBlock() throws JSQLParserException { Assertions.assertThrowsExactly(JSQLParserException.class, new Executable() { @Override public void execute() throws Throwable { - CCJSqlParserUtil.parseStatements(sqlStr, parser -> parser.withUnsupportedStatements(false) ); + CCJSqlParserUtil.parseStatements(sqlStr, + parser -> parser.withUnsupportedStatements(false)); } }); } @@ -56,22 +59,24 @@ public void execute() throws Throwable { public void testUnsupportedStatementsMiddleInBlock() throws JSQLParserException { String sqlStr = "Select * from dual; This is an unsupported statement; Select * from dual;"; - Statements statements = CCJSqlParserUtil.parseStatements(sqlStr, parser -> parser.withUnsupportedStatements(true)); + Statements statements = CCJSqlParserUtil.parseStatements(sqlStr, + parser -> parser.withUnsupportedStatements(true)); Assertions.assertEquals(3, statements.getStatements().size()); Assertions.assertInstanceOf(Select.class, statements.getStatements().get(0)); Assertions.assertInstanceOf(UnsupportedStatement.class, statements.getStatements().get(1)); Assertions.assertInstanceOf(Select.class, statements.getStatements().get(2)); -// This will not fail, but always return the Unsupported Statements -// Since we can't LOOKAHEAD in the Statements() production + // This will not fail, but always return the Unsupported Statements + // Since we can't LOOKAHEAD in the Statements() production -// Assertions.assertThrowsExactly(JSQLParserException.class, new Executable() { -// @Override -// public void execute() throws Throwable { -// CCJSqlParserUtil.parseStatements(sqlStr, parser -> parser.withUnsupportedStatements(false) ); -// } -// }); + // Assertions.assertThrowsExactly(JSQLParserException.class, new Executable() { + // @Override + // public void execute() throws Throwable { + // CCJSqlParserUtil.parseStatements(sqlStr, parser -> + // parser.withUnsupportedStatements(false) ); + // } + // }); } @Test @@ -79,7 +84,7 @@ void testAlter() throws JSQLParserException { String sqlStr = "ALTER INDEX idx_t_fa RENAME TO idx_t_fb"; Statement statement = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - Assertions.assertTrue( statement instanceof UnsupportedStatement); + Assertions.assertTrue(statement instanceof UnsupportedStatement); } @Test @@ -87,6 +92,6 @@ void testCreate() throws JSQLParserException { String sqlStr = "create trigger stud_marks before INSERT on Student for each row set Student.total = Student.subj1 + Student.subj2, Student.per = Student.total * 60 / 100"; Statement statement = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - Assertions.assertTrue( statement instanceof UnsupportedStatement); + Assertions.assertTrue(statement instanceof UnsupportedStatement); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java index 5bf2ccbaf..ae1564e15 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java @@ -1019,15 +1019,15 @@ void testCreateTableWithNextValueFor() throws JSQLParserException { sqlStr = "CREATE TABLE \"public\".\"device_bayonet_copy1\" ( " - + "\"id\" int8 NOT NULL" - + ", \"device_code\" varchar(128) COLLATE \"pg_catalog\".\"default\"" - + ", \"longitude_latitude\" varchar(128) COLLATE \"pg_catalog\".\"default\"" - + ", \"longitude_latitude_gis\" \"public\".\"geometry\"" - + ", \"direction\" varchar(128) COLLATE \"pg_catalog\".\"default\"" - + ", \"brand\" varchar(128) COLLATE \"pg_catalog\".\"default\"" - + ", \"test\" \"information_schema\".\"time_stamp\"" - + ", CONSTRAINT \"device_bayonet_copy1_pkey\" PRIMARY KEY (\"id\") " - + ")"; + + "\"id\" int8 NOT NULL" + + ", \"device_code\" varchar(128) COLLATE \"pg_catalog\".\"default\"" + + ", \"longitude_latitude\" varchar(128) COLLATE \"pg_catalog\".\"default\"" + + ", \"longitude_latitude_gis\" \"public\".\"geometry\"" + + ", \"direction\" varchar(128) COLLATE \"pg_catalog\".\"default\"" + + ", \"brand\" varchar(128) COLLATE \"pg_catalog\".\"default\"" + + ", \"test\" \"information_schema\".\"time_stamp\"" + + ", CONSTRAINT \"device_bayonet_copy1_pkey\" PRIMARY KEY (\"id\") " + + ")"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java index 5544cde60..195231e69 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -5504,17 +5504,19 @@ public void testParserInterruptedByTimeout() { int parallelThreads = Runtime.getRuntime().availableProcessors() + 1; ExecutorService executorService = Executors.newFixedThreadPool(parallelThreads); - + ExecutorService timeOutService = Executors.newSingleThreadExecutor(); 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); + Statement statement = + CCJSqlParserUtil.parseStatement(parser, timeOutService); } catch (JSQLParserException ignore) { // We expected that to happen. } @@ -5522,6 +5524,7 @@ public void run() { }); } executorService.shutdown(); + timeOutService.shutdown(); // we should not run in any timeout here (because we expect that the Parser has timed out by // itself)