@@ -211,6 +211,17 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
211211 default: return false;
212212 }
213213 }
214+
215+ protected boolean isParenthesedSelectAhead() {
216+ if (getToken(1).kind != OPENING_BRACKET) {
217+ return false;
218+ }
219+ int nextKind = getToken(2).kind;
220+ return nextKind == K_SELECT
221+ || nextKind == K_WITH
222+ || nextKind == K_VALUES
223+ || nextKind == K_FROM;
224+ }
214225}
215226
216227PARSER_END(CCJSqlParser)
@@ -5700,23 +5711,32 @@ JdbcParameter JdbcParameter() : {
57005711Limit LimitWithOffset() #LimitWithOffset:
57015712{
57025713 Limit limit = new Limit();
5703- Expression rowCountExpression ;
5704- Expression offsetExpression ;
5714+ Expression firstExpression ;
5715+ Expression secondExpression ;
57055716}
57065717{
5718+ <K_LIMIT>
57075719 (
5708- LOOKAHEAD(<K_LIMIT> Expression() "," Expression()) (
5709- // mysql-> LIMIT offset,row_count
5710- <K_LIMIT>
5711- offsetExpression=Expression() { limit.setOffset( offsetExpression ); }
5712- ","
5713- rowCountExpression=Expression() { limit.setRowCount( rowCountExpression ); }
5714- )
5720+ LOOKAHEAD(3) firstExpression = ParenthesedSelect()
5721+ |
5722+ firstExpression = Expression()
5723+ )
5724+ (
5725+ // MySQL: LIMIT offset, row_count
5726+ ","
5727+ secondExpression = Expression()
5728+ {
5729+ limit.setOffset(firstExpression);
5730+ limit.setRowCount(secondExpression);
5731+ }
57155732 |
5716- limit = PlainLimit()
5733+ // PostgreSQL: LIMIT row_count
5734+ {
5735+ limit.setRowCount(firstExpression);
5736+ }
57175737 )
57185738 {
5719- linkAST(limit,jjtThis);
5739+ linkAST(limit, jjtThis);
57205740 return limit;
57215741 }
57225742}
@@ -6007,10 +6027,23 @@ Expression AndExpression() :
60076027{
60086028 Expression left, right, result;
60096029 boolean not = false;
6010- boolean exclamationMarkNot=false;
6030+ boolean exclamationMarkNot=false;
60116031}
60126032{
60136033 (
6034+ // Fast path: when NOT starting with ( or NOT/!, Condition() always succeeds
6035+ // (PrimaryExpression can always match an identifier, literal, CASE, etc.)
6036+ // No speculative parsing needed — go directly.
6037+ LOOKAHEAD({ getToken(1).kind != OPENING_BRACKET
6038+ && getToken(1).kind != K_NOT
6039+ && !getToken(1).image.equals("!") })
6040+ left=Condition()
6041+ |
6042+ // Slow path: ( or NOT might introduce a parenthesized boolean expression
6043+ // that Condition() can't handle (because ParenthesedExpressionList uses
6044+ // SimpleExpression which doesn't support LIKE/IN/BETWEEN/IS).
6045+ // Try Condition() first (handles "( a + b ) > 5"), fall back to
6046+ // "(" XorExpression() ")" (handles "( value LIKE '%x%' )").
60146047 LOOKAHEAD(Condition(), {!interrupted}) left=Condition()
60156048 |
60166049 [ <K_NOT> { not=true; } | "!" { not=true; exclamationMarkNot=true; } ]
@@ -6022,6 +6055,11 @@ Expression AndExpression() :
60226055 { boolean useOperator = false; }
60236056 (<K_AND> | <OP_DOUBLEAND> {useOperator=true;} )
60246057 (
6058+ LOOKAHEAD({ getToken(1).kind != OPENING_BRACKET
6059+ && getToken(1).kind != K_NOT
6060+ && !getToken(1).image.equals("!") })
6061+ right=Condition()
6062+ |
60256063 LOOKAHEAD(Condition(), {!interrupted}) right=Condition()
60266064 |
60276065 [ <K_NOT> { not=true; } | "!" { not=true; exclamationMarkNot=true; } ]
@@ -6296,7 +6334,7 @@ Expression Between(Expression leftExpression) :
62966334 )
62976335 ]
62986336 (
6299- LOOKAHEAD( ParenthesedSelect () ) betweenExpressionStart = ParenthesedSelect()
6337+ LOOKAHEAD({ isParenthesedSelectAhead () } ) betweenExpressionStart = ParenthesedSelect()
63006338 |
63016339 betweenExpressionStart = SimpleExpression()
63026340 [
@@ -6307,7 +6345,7 @@ Expression Between(Expression leftExpression) :
63076345
63086346 <K_AND>
63096347 (
6310- LOOKAHEAD( ParenthesedSelect () ) betweenExpressionEnd = ParenthesedSelect()
6348+ LOOKAHEAD({ isParenthesedSelectAhead () } ) betweenExpressionEnd = ParenthesedSelect()
63116349 |
63126350 betweenExpressionEnd = SimpleExpression()
63136351 [
0 commit comments