Skip to content

Commit 85690dc

Browse files
committed
perf: drop the list-form probes in ExpressionList
`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 a0e0861 commit 85690dc

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
@@ -12715,23 +12715,9 @@ ExpressionList ExpressionList() #ExpressionList:
1271512715
ExpressionList expressionList;
1271612716
}
1271712717
{
12718-
(
12719-
LOOKAHEAD(3, { !interrupted }) expressionList = ComplexExpressionList()
12720-
|
12721-
LOOKAHEAD(3) expressionList = SimpleExpressionList()
12722-
|
12723-
LOOKAHEAD(3) expressionList = ParenthesedExpressionList()
12724-
|
12725-
// Fallback, see isUnparenthesizedSelectAhead(): the three probes above are
12726-
// syntactic and cannot see through the Pratt operator loop, which lives in a
12727-
// Java action. They all fail on a bracketed operand of a larger expression,
12728-
// e.g. "( 1 + a ) / ( 1 + b )" or "( 1 + a )" - the third token is an operator
12729-
// where the probe expects "," or ")". Such input is still a valid expression
12730-
// list, so parse it as one instead of raising a ParseException.
12731-
LOOKAHEAD({ !interrupted }) expressionList = ComplexExpressionList()
12732-
|
12733-
expressionList = SimpleExpressionList()
12734-
)
12718+
// ComplexExpressionList() parses every list form, "()" and bracketed operands such as
12719+
// "( 1 + a ) / ( 1 + b )" included.
12720+
expressionList = ComplexExpressionList()
1273512721
{
1273612722
// Avoid redundant ExpressionLists containing only one ParenthesedExpressionList
1273712723
// return the Parenthesed Sub ExpressionList instead
@@ -12763,11 +12749,7 @@ ParenthesedExpressionList ParenthesedExpressionList():
1276312749
}
1276412750
{
1276512751
"("
12766-
(
12767-
LOOKAHEAD({ !interrupted }) expressions = ComplexExpressionList()
12768-
|
12769-
expressions = SimpleExpressionList()
12770-
)?
12752+
[ LOOKAHEAD({ getToken(1).kind != CLOSING_BRACKET }) expressions = ComplexExpressionList() ]
1277112753
")"
1277212754
{
1277312755
return new ParenthesedExpressionList(expressions);
@@ -12835,7 +12817,7 @@ ExpressionList ComplexExpressionList():
1283512817
|
1283612818
LOOKAHEAD(2, { isNamedParameterAssignmentAhead() }) expr=PostgresNamedFunctionParameter()
1283712819
|
12838-
// JavaCC scans an unguarded alternative's first token; a semantic-only lookahead enters directly
12820+
// The semantic lookahead makes JavaCC enter Expression() with no scan of its first token.
1283912821
LOOKAHEAD({ !interrupted }) expr=Expression()
1284012822
)
1284112823
{

‎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)