Skip to content

Commit f162cfe

Browse files
perf: drop the list-form probes in ExpressionList (#2877)
`ExpressionList()` ran three 3-token lookaheads to choose between the complex, simple and parenthesed list forms, and `ParenthesedExpressionList()` scanned into the list on the parse path to tell an empty body from a non-empty one. Together they took about 5% of parser CPU on `performance.sql`. The probes decided nothing: `ComplexExpressionList()` accepts every list the other two forms do, including `()` and bracketed operands such as `( 1 + a ) / ( 1 + b )`, so it won wherever they could have. It is now called directly, and the parenthesed body is guarded by the token kind of the closing bracket. Parser CPU per parse drops from 29.0 ms to 27.7 ms (-4.5%, three interleaved pairs, on top of #2876), and `./gradlew jmh` from 32.67 to 28.54 ms/op.
1 parent 83f9066 commit f162cfe

2 files changed

Lines changed: 15 additions & 23 deletions

File tree

‎src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt‎

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12723,23 +12723,9 @@ ExpressionList ExpressionList() #ExpressionList:
1272312723
ExpressionList expressionList;
1272412724
}
1272512725
{
12726-
(
12727-
LOOKAHEAD(3, { !interrupted }) expressionList = ComplexExpressionList()
12728-
|
12729-
LOOKAHEAD(3) expressionList = SimpleExpressionList()
12730-
|
12731-
LOOKAHEAD(3) expressionList = ParenthesedExpressionList()
12732-
|
12733-
// Fallback, see isUnparenthesizedSelectAhead(): the three probes above are
12734-
// syntactic and cannot see through the Pratt operator loop, which lives in a
12735-
// Java action. They all fail on a bracketed operand of a larger expression,
12736-
// e.g. "( 1 + a ) / ( 1 + b )" or "( 1 + a )" - the third token is an operator
12737-
// where the probe expects "," or ")". Such input is still a valid expression
12738-
// list, so parse it as one instead of raising a ParseException.
12739-
LOOKAHEAD({ !interrupted }) expressionList = ComplexExpressionList()
12740-
|
12741-
expressionList = SimpleExpressionList()
12742-
)
12726+
// ComplexExpressionList() parses every list form, "()" and bracketed operands such as
12727+
// "( 1 + a ) / ( 1 + b )" included.
12728+
expressionList = ComplexExpressionList()
1274312729
{
1274412730
// Avoid redundant ExpressionLists containing only one ParenthesedExpressionList
1274512731
// return the Parenthesed Sub ExpressionList instead
@@ -12771,11 +12757,7 @@ ParenthesedExpressionList ParenthesedExpressionList():
1277112757
}
1277212758
{
1277312759
"("
12774-
(
12775-
LOOKAHEAD({ !interrupted }) expressions = ComplexExpressionList()
12776-
|
12777-
expressions = SimpleExpressionList()
12778-
)?
12760+
[ LOOKAHEAD({ getToken(1).kind != CLOSING_BRACKET }) expressions = ComplexExpressionList() ]
1277912761
")"
1278012762
{
1278112763
return new ParenthesedExpressionList(expressions);
@@ -12843,7 +12825,7 @@ ExpressionList ComplexExpressionList():
1284312825
|
1284412826
LOOKAHEAD(2, { isNamedParameterAssignmentAhead() }) expr=PostgresNamedFunctionParameter()
1284512827
|
12846-
// JavaCC scans an unguarded alternative's first token; a semantic-only lookahead enters directly
12828+
// The semantic lookahead makes JavaCC enter Expression() with no scan of its first token.
1284712829
LOOKAHEAD({ !interrupted }) expr=Expression()
1284812830
)
1284912831
{

‎src/test/java/net/sf/jsqlparser/expression/FunctionTest.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,14 @@ void testAesDecryptWithKeyExpressionInSelect() throws JSQLParserException {
157157

158158
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
159159
}
160+
161+
@Test
162+
void testBracketedOperandAndEmptyListArguments() throws JSQLParserException {
163+
TestUtils.assertSqlCanBeParsedAndDeparsed(
164+
"SELECT f((1 + a) / (1 + b), (c + d) * 2) FROM t", true);
165+
166+
TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT f(()) FROM t", true);
167+
168+
TestUtils.assertSqlCanBeParsedAndDeparsed("INSERT INTO t VALUES ()", true);
169+
}
160170
}

0 commit comments

Comments
 (0)