Conversation
h4nsmuller
added a commit
to h4nsmuller/duckdb
that referenced
this pull request
Sep 14, 2026
JSQLParser/JSqlParser#2634 adds MATCH_RECOGNIZE to JSqlParser with 32 fixtures, 17 of them executed against Oracle 23ai. Eleven parsed here; six did not, and four of those six are SQL:2016 rather than Oracle extensions. **AFTER MATCH SKIP TO <variable>.** The standard's skip target is `TO [FIRST | LAST] <variable>`, where saying neither means the variable's last row. Only the two explicit forms were accepted. **The empty pattern.** `()` is a row pattern primary that matches where it stands and takes no row, so `PATTERN (A ())` is one A and no more, and `PATTERN (A | ())` falls through to an empty match. It compiles to a concatenation of nothing, which the matcher already walks correctly. **RUNNING and FINAL anywhere a call can appear.** They were parsed at the measure level, so `RUNNING sum(x) + 1` worked and `1 + RUNNING sum(x)` did not, and `RUNNING sum(x) + FINAL sum(x)` - the shape Oracle's fixture uses - could not be written at all. They are now a prefix on a function call in the expression grammar, which is where the standard puts them, and the ordinary binder reports them outside MEASURES rather than leaving a missing function to explain it. A column named `running` is still a column: the call after the keyword is what the grammar needs to see. **ALL ROWS PER MATCH SHOW EMPTY MATCHES / OMIT EMPTY MATCHES / WITH UNMATCHED ROWS.** SHOW is what ALL ROWS PER MATCH already did. OMIT drops the rows of empty matches. WITH UNMATCHED ROWS keeps the rows that are in no match at all, reporting the row and nothing else - every measure is about a match, so a row without one has none. That needed no executor change: unnesting drops a row whose span list is empty, so the list becomes a single NULL span for those rows and the measures above read NULL through it. All 17 Oracle fixtures now run. Full suite green: 3,027,732 assertions in 6,840 test cases; MATCH_RECOGNIZE green under seven verification configs and storage compatibility. Claude-Session: https://claude.ai/code/session_01T8BCMvDgXtg7kL5RruuS2A
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DuckDB also has ongoing work to add native
MATCH_RECOGNIZEsupport in duckdb/duckdb#25255, which is currently open.MATCH_RECOGNIZE queries currently fail at the FROM clause, including the BigQuery query reported in #2350. This adds an editable relation and row-pattern AST, with parsing, deparsing, visitor traversal and static validation for BigQuery, Oracle and Snowflake syntax.
Closes #2350.
Implementation
MatchRecognizeas aFromItemwrapping its input, with independent input/result aliases and structured partitioning, ordering, measures, definitions, output modes, skip targets, subsets and options.PERMUTEis not expanded.RowPatternFunctionkeeps RUNNING/FINAL separate from the underlying function.$anchors even during nested SELECT lookahead, without changing dollar literals elsewhere.Refactoring
Clause rendering is shared between the AST and deparser. The same change fixes STRUCT rendering that replayed original tokens instead of edited argument expressions, which otherwise breaks nested BigQuery measures.
Visitor traversal now follows parenthesized input joins/set operations, pivot children and scalar subqueries in expression validation. These paths are needed to inspect and rewrite the new clause without losing its nested expressions or source relations.
Rendering and validation are organized by clause responsibilities, and table discovery reuses existing null-safe visitor helpers. Codacy's T-SQL linter excludes only the new Oracle/BigQuery SQL fixtures, where its SQL Server requirements do not apply.
Validation
29798771: grammar ambiguity checks and Gradle/Maven on Linux, Windows and macOS. Codacy also passed with no new issues../gradlew check --no-daemon: passed, 7,067 tests, 0 failures/errors, 25 skipped; grammar ambiguity, formatting, Checkstyle, PMD, SpotBugs and coverage checks passed.mvn --batch-mode --no-transfer-progress verify: passed, 7,049 tests, 0 failures/errors, 25 skipped.2026.9.1: all 15 original/deparsed fixture pairs executed with identical results, including [FEATURE] Add support for MATCH_RECOGNIZE clause (BigQuery) to JSQLParser #2350, longest-match behavior, reluctant/greedy matching, overlap, parameter bounds and nested STRUCT measures.23.26.2.0.0: all 17 original/deparsed fixture pairs executed with identical results, including SUBSET, PERMUTE, exclusions, RUNNING/FINAL and output/skip modes.Scope and remaining verification
GoogleSQL is the reference evaluator, not the BigQuery service. Snowflake syntax and AST behavior were checked against its official documentation and parser tests; no Snowflake account was available for execution. Its documentation gives alternation precedence over concatenation, so the Snowflake preset follows that rule and rendering inserts parentheses at mixed operator boundaries. Verifying that precedence against the service remains a useful review check.
This is a SQL parser/AST implementation. Function eligibility, aggregation/type rules, binding pattern-qualified columns to the input schema, and data-dependent matching or skip errors remain with the database. It does not implement a pattern execution engine or cross-dialect query translation.
Sources: BigQuery syntax, Oracle pattern matching, Snowflake syntax and precedence.