@@ -294,6 +294,26 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
294294 }
295295 }
296296
297+ /**
298+ * True when the next token can only start a bare (unparenthesized) sub-select.
299+ *
300+ * Used where the alternative to Select() is an ExpressionList: the Pratt
301+ * arithmetic loop runs inside a Java action (prattArithRest) and JavaCC does
302+ * not execute actions while evaluating syntactic lookahead, so a jj_3R probe
303+ * cannot see through any infix operator. A syntactic LOOKAHEAD(n) over an
304+ * expression therefore fails as soon as an operator appears within the first
305+ * n tokens - e.g. "( 1 + a ) / ( 1 + b )" - and control wrongly falls through
306+ * to the Select() branch. This O(1) token check replaces that probe.
307+ */
308+ protected boolean isUnparenthesizedSelectAhead() {
309+ try {
310+ int kind = getToken(1).kind;
311+ return kind == K_SELECT || kind == K_WITH || kind == K_VALUES;
312+ } catch (TokenMgrError e) {
313+ return false;
314+ }
315+ }
316+
297317 /**
298318 * Pratt arithmetic operator precedence loop.
299319 * Handles: *, /, %, ^, DIV (prec=6) and +, -, ||, |, &, <<, >> (prec=5)
@@ -385,7 +405,7 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
385405 }
386406
387407 // True when "(" opens a parenthesised FROM item (table/function/lateral/join)
388- // rather than a SELECT subquery. Cheap 2-token check replaces expensive
408+ // rather than a SELECT subquery. Cheap 2-token check replaces expensive
389409 // syntactic LOOKAHEAD(ParenthesedFromItem()).
390410 protected boolean isParenthesedFromItemAhead() {
391411 try {
@@ -7376,6 +7396,16 @@ ExpressionList ExpressionList() #ExpressionList:
73767396 LOOKAHEAD(3) expressionList = SimpleExpressionList()
73777397 |
73787398 LOOKAHEAD(3) expressionList = ParenthesedExpressionList()
7399+ |
7400+ // Fallback, see isUnparenthesizedSelectAhead(): the three probes above are
7401+ // syntactic and cannot see through the Pratt operator loop, which lives in a
7402+ // Java action. They all fail on a bracketed operand of a larger expression,
7403+ // e.g. "( 1 + a ) / ( 1 + b )" or "( 1 + a )" - the third token is an operator
7404+ // where the probe expects "," or ")". Such input is still a valid expression
7405+ // list, so parse it as one instead of raising a ParseException.
7406+ LOOKAHEAD({ !interrupted }) expressionList = ComplexExpressionList()
7407+ |
7408+ expressionList = SimpleExpressionList()
73797409 )
73807410 {
73817411 // Avoid redundant ExpressionLists containing only one ParenthesedExpressionList
@@ -9490,11 +9520,7 @@ Function InternalFunction(boolean escaped):
94909520 Expression expr = null;
94919521 Expression attributeExpression = null;
94929522 Column attributeColumn = null;
9493- List<OrderByElement> orderByList;
9494- String onOverflowTruncate = null;
9495- Token overflowToken = null;
94969523 Limit limit;
9497- Token extraKeywordToken;
94989524 List<Function.KeywordArgument> keywordArgs = null;
94999525}
95009526{
@@ -9511,18 +9537,15 @@ Function InternalFunction(boolean escaped):
95119537 )
95129538 ]
95139539 (
9514- LOOKAHEAD(3) [ LOOKAHEAD(2) extraKeywordToken = <K_TABLE> { retval.setExtraKeyword(extraKeywordToken.image); } ]
9515- expressionList=ExpressionList()
9516- [ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ]
9540+ LOOKAHEAD(3) expressionList = FunctionArgumentList(retval)
95179541
9518- // https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/LISTAGG.html
9519- [
9520- <K_ON> <K_OVERFLOW> ( overflowToken=<K_TRUNCATE> | overflowToken=<K_ERROR> ) { onOverflowTruncate=overflowToken.image; }
9521- [
9522- overflowToken = <S_CHAR_LITERAL> { onOverflowTruncate+= " " + overflowToken.image; }
9523- [ ( overflowToken=<K_WITH> | overflowToken=<K_WITHOUT> ) <K_COUNT> { onOverflowTruncate+=" " + overflowToken.image + " COUNT"; }]
9524- ]
9525- ] { retval.setOnOverflowTruncate(onOverflowTruncate); }
9542+ |
9543+ // The probe above is syntactic and cannot see through the Pratt operator
9544+ // loop, so it fails on arguments such as "( 1 + a ) / ( 1 + b )" and used
9545+ // to fall through to Select(), reporting "Encountered <OPENING_BRACKET> ...
9546+ // was expecting <K_WITH>". Select() is only reachable here for a bare
9547+ // sub-select, so decide on that instead.
9548+ LOOKAHEAD({ !isUnparenthesizedSelectAhead() }) expressionList = FunctionArgumentList(retval)
95269549
95279550 |
95289551 LOOKAHEAD({ !getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) expr = Select() { expressionList = new ExpressionList(expr); }
@@ -9604,6 +9627,37 @@ Function InternalFunction(boolean escaped):
96049627 }
96059628}
96069629
9630+ /**
9631+ * Argument list of a Function, extracted from InternalFunction() so that it can be
9632+ * reached from more than one lookahead guard without duplicating the expansion.
9633+ */
9634+ ExpressionList FunctionArgumentList(Function retval):
9635+ {
9636+ ExpressionList expressionList = null;
9637+ List<OrderByElement> orderByList;
9638+ String onOverflowTruncate = null;
9639+ Token overflowToken = null;
9640+ Token extraKeywordToken;
9641+ }
9642+ {
9643+ [ LOOKAHEAD(2) extraKeywordToken = <K_TABLE> { retval.setExtraKeyword(extraKeywordToken.image); } ]
9644+ expressionList=ExpressionList()
9645+ [ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ]
9646+
9647+ // https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/LISTAGG.html
9648+ [
9649+ <K_ON> <K_OVERFLOW> ( overflowToken=<K_TRUNCATE> | overflowToken=<K_ERROR> ) { onOverflowTruncate=overflowToken.image; }
9650+ [
9651+ overflowToken = <S_CHAR_LITERAL> { onOverflowTruncate+= " " + overflowToken.image; }
9652+ [ ( overflowToken=<K_WITH> | overflowToken=<K_WITHOUT> ) <K_COUNT> { onOverflowTruncate+=" " + overflowToken.image + " COUNT"; }]
9653+ ]
9654+ ] { retval.setOnOverflowTruncate(onOverflowTruncate); }
9655+
9656+ {
9657+ return expressionList;
9658+ }
9659+ }
9660+
96079661XMLSerializeExpr XMLSerializeExpr(): {
96089662 XMLSerializeExpr result;
96099663 Expression expression;
0 commit comments