Skip to content

feat: add DuckDB dialect support#2644

Open
adamatmotherduck wants to merge 4 commits intotaozhi8833998:masterfrom
adamatmotherduck:feat/duckdb-dialect
Open

feat: add DuckDB dialect support#2644
adamatmotherduck wants to merge 4 commits intotaozhi8833998:masterfrom
adamatmotherduck:feat/duckdb-dialect

Conversation

@adamatmotherduck
Copy link
Copy Markdown

Summary

Adds a complete DuckDB SQL dialect to node-sql-parser, enabling parsing and SQL generation for DuckDB-specific syntax. This has been a highly requested feature (13 upvotes).

  • New grammar: pegjs/duckdb.pegjs (based on PostgreSQL grammar with extensive DuckDB-specific additions)
  • 107 new tests in test/duckdb.spec.js covering all added features
  • Minimal changes to shared src/ files (56 lines added across 8 files) with zero regressions to existing 1515 tests

DuckDB-specific syntax supported

Feature Example
:: type casts (incl. array) val::INTEGER, arr::DATE[]
QUALIFY clause SELECT ... QUALIFY ROW_NUMBER() OVER (...) = 1
GROUP BY ALL / ORDER BY ALL SELECT col, SUM(x) FROM t GROUP BY ALL
EXCLUDE / REPLACE SELECT * EXCLUDE (col) REPLACE (expr AS col)
PIVOT / UNPIVOT FROM t PIVOT (SUM(x) FOR col IN ('a', 'b'))
Lambda expressions list_transform(arr, x -> x + 1)
Struct / list literals {'key': value}, [1, 2, 3]
COLUMNS() expression SELECT COLUMNS('pattern.*') FROM t
UNION BY NAME SELECT * FROM t1 UNION BY NAME SELECT * FROM t2
ASOF / SEMI / ANTI / POSITIONAL JOIN FROM t1 ASOF JOIN t2 ON ...
INSERT BY NAME INSERT INTO t BY NAME SELECT * FROM src
INSERT OR REPLACE / IGNORE INSERT OR REPLACE INTO t ...
IS NOT DISTINCT FROM t1.col IS NOT DISTINCT FROM t2.col
CREATE OR REPLACE TABLE CREATE OR REPLACE TABLE t AS SELECT ...
COPY with subquery COPY (SELECT ...) TO 'file.parquet' (FORMAT PARQUET)
FROM-first queries FROM t WHERE x > 1 LIMIT 10
DESCRIBE / SUMMARIZE SUMMARIZE my_table
ATTACH / DETACH ATTACH 'db.duckdb' AS mydb
DuckDB types HUGEINT, UBIGINT, BLOB, STRUCT, MAP, LIST, UNION
PARTITION BY tuple PARTITION BY (col1, col2)

Files changed

File Change
pegjs/duckdb.pegjs New — DuckDB grammar (182KB)
test/duckdb.spec.js New — 107 tests incl. real-world query patterns
src/parser.all.js Add duckdb import
src/util.js Add duckdb to double-quote identifier list
src/column.js Handle EXCLUDE+REPLACE combo columns
src/create.js Handle OR REPLACE for DuckDB CREATE
src/expr.js Add struct_value serialization
src/insert.js Add BY NAME support
src/sql.js Register new statement types
src/union.js Add summarize/detach/copy SQL generation

Test plan

  • All 107 new DuckDB tests pass
  • All 1515 existing tests pass (zero regressions)
  • npm run build succeeds
  • Grammar size (182KB) is comparable to PostgreSQL (171KB)

Closes #1944

🤖 Generated with Claude Code

adamatmotherduck and others added 4 commits February 12, 2026 12:56
Add a complete DuckDB SQL grammar and 107 tests covering DuckDB-specific
syntax. The grammar is based on the PostgreSQL dialect with extensive
modifications for DuckDB features.

Supported DuckDB-specific syntax:
- :: type casts (including array types like ::DATE[])
- QUALIFY clause (window function filtering)
- GROUP BY ALL / ORDER BY ALL
- SELECT * EXCLUDE (...) / REPLACE (...)
- PIVOT / UNPIVOT
- LIST() aggregate with ORDER BY
- Lambda expressions (x -> x + 1)
- Struct literals ({'key': value})
- List literals ([1, 2, 3])
- COLUMNS() expression
- UNION BY NAME / UNION ALL BY NAME
- ASOF JOIN, SEMI JOIN, ANTI JOIN, POSITIONAL JOIN
- INSERT INTO ... BY NAME
- INSERT OR REPLACE / INSERT OR IGNORE
- CREATE OR REPLACE TABLE
- IS NOT DISTINCT FROM
- COPY with subquery support
- FROM-first queries (FROM t WHERE ...)
- DESCRIBE, SUMMARIZE, ATTACH, DETACH
- DuckDB data types (HUGEINT, UBIGINT, BLOB, etc.)
- Composite types (STRUCT, MAP, LIST, UNION)
- PARTITION BY (col1, col2) tuple syntax

Test suite includes real-world query patterns from MotherDuck usage.

Closes taozhi8833998#1944

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add standalone PIVOT syntax (PIVOT table ON col USING aggr())
- Fix PARTITION BY tuple syntax ((col1, col2))
- Fix IS NOT DISTINCT FROM operator
- Fix EXCLUDE + REPLACE combined syntax
- Fix COPY with subquery (COPY (SELECT ...) TO ...)
- Fix INSERT INTO ... BY NAME
- Fix ::TYPE[] array type casts in cast_data_type
- Add reserved keywords: ASOF, SEMI, ANTI, POSITIONAL, CROSS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When installed directly from GitHub (e.g. github:user/repo#branch),
npm needs a prepare script to compile and bundle the parser.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The webpack config outputs to output/prod/build/ but package.json's
files field expects build/ at the repo root.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support DuckDB Dialect

1 participant