{"record":{"id":"7a4d5eac6fe4cbe1","repo":"oracle/graal","slug":"nested-quantifier-in-regular-expression","errorCode":null,"errorMessage":"nested quantifier in regular expression","messagePattern":"nested quantifier in regular expression","errorType":"exception","errorClass":"UnsupportedRegexException","httpStatus":null,"severity":"error","filePath":"regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/flavor/oracledb/OracleDBRegexParser.java","lineNumber":178,"sourceCode":"                    astBuilder.addDollar();\n                    astBuilder.nextSequence();\n                    astBuilder.pushLookAheadAssertion(false);\n                    astBuilder.addCharClass(CodePointSet.create('\\n'));\n                    if (token.kind == Token.Kind.Z || !flags.isMultiline()) {\n                        astBuilder.addDollar();\n                    }\n                    astBuilder.popGroup();\n                    if (token.kind == Token.Kind.dollar && flags.isMultiline()) {\n                        astBuilder.addPositionAssertion(PositionAssertion.Type.MATCH_END);\n                    }\n                    astBuilder.popGroup();\n                    break;\n                case backReference:\n                    astBuilder.addBackReference((Token.BackReference) token, flags.isIgnoreCase());\n                    break;\n                case quantifier:\n                    if (prevKind == Token.Kind.quantifier) {\n                        throw new UnsupportedRegexException(OracleDBErrorMessages.NESTED_QUANTIFIER);\n                    }\n                    if (astBuilder.getCurTerm() == null || prevKind == Token.Kind.captureGroupBegin) {\n                        // quantifiers without target are ignored\n                        break;\n                    }\n                    astBuilder.addQuantifier((Token.Quantifier) token);\n                    break;\n                case alternation:\n                    astBuilder.nextSequence();\n                    break;\n                case captureGroupBegin:\n                    if (lexer.numberOfCaptureGroupsSoFar() <= 10) {\n                        // oracledb only tracks capture groups 0 - 9\n                        astBuilder.pushCaptureGroup(token);\n                    } else {\n                        astBuilder.pushGroup(token);\n                    }\n                    break;","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/flavor/oracledb/OracleDBRegexParser.java#L160-L196","documentation":"Thrown by the OracleDB-flavor parser when a quantifier token immediately follows another quantifier token. Oracle's SQL regex dialect does not allow stacked quantifiers (no possessive or lazy modifiers on quantifiers), so prevKind == Token.Kind.quantifier triggers UnsupportedRegexException(NESTED_QUANTIFIER).","triggerScenarios":"Compiling an OracleDB-flavor regex such as 'a**', 'a++', 'a*?', '(ab)+?' or 'a{2,3}*' — any pattern where a quantifier directly follows another quantifier token. The parser sees the second quantifier with prevKind == quantifier and throws.","commonSituations":"Porting PCRE/Java patterns with lazy ('*?') or possessive ('*+', '++') quantifiers into Oracle Database regex semantics (e.g. via a GraalVM-based SQL engine using TRegex's OracleDB flavor); JS/Python-style regexes pasted into SQL REGEXP_LIKE calls.","solutions":["Replace the two-letter quantifier forms with the plain greedy form: 'a*?' -> 'a*', 'a++' -> 'a+'","Wrap the inner quantified expression in a group if you need repetition of a repetition: 'a**' is invalid, '(a*)*' is the closest legal form (mind the semantics)","Strip lazy/possessive suffixes when translating patterns from other dialects into OracleDB flavor"],"exampleFix":"-- before (OracleDB flavor)\na.*?b  -- lazy quantifier\n\n-- after\na.*b   -- greedy quantifier","handlingStrategy":"try-catch","validationCode":"boolean hasStackedQuantifiers(String pattern) {\n    return java.util.regex.Pattern.compile(\"([*+?]|\\\\{[0-9]+(,[0-9]*)?\\\\})([*+?]|\\\\{)\").matcher(pattern).find();\n}","typeGuard":null,"tryCatchPattern":"try {\n    RegexObject re = compileOracleDB(pattern);\n} catch (UnsupportedRegexException e) {\n    if (e.getReason().contains(\"nested quantifier\")) {\n        // drop lazy/possessive second quantifier and retry once\n    } else { throw e; }\n}","preventionTips":["When porting to OracleDB flavor, remove '*?', '+?', '?+', '*+', '++' forms","Validate SQL-bound regexes in application code before sending them to REGEXP_LIKE-style calls"],"tags":["regex","oracledb-flavor","quantifier","syntax-error"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}