Repository navigation
Support the rest of DuckDB's CREATE MACRO syntax - #2783
Merged
manticore-projects merged 2 commits intoOct 13, 2026
Merged
Conversation
Contributor
|
Please resolve conflicts. |
added 2 commits
October 13, 2026 14:53
DuckDB's CREATE MACRO also takes `IF NOT EXISTS`, typed parameters (`a INTEGER`), several overloads (`name (a TINYINT) AS ..., (a INT) AS ...`) and `FUNCTION` as an alias of `MACRO`. All of these were rejected, and `CREATE FUNCTION f(a) AS a + 1` was parsed as an opaque `CreateFunction`. - `CreateMacro` keeps a list of `Overload`s, each with its parameters and body; `getParameters()`, `getExpression()`, `getSelect()` and their setters address the first one, as before. It also records `IF NOT EXISTS` and the `FUNCTION` keyword, and `Parameter` an optional type. - `CREATE FUNCTION` is routed to `CreateMacro` only when `AS` directly follows the parameters and the body is not a string, so PostgreSQL functions (`... RETURNS ...`, `... AS $$ ... $$ LANGUAGE ...`) keep their current parse. - `TablesNamesFinder` visits the queries of every overload.
`AS` directly after the parameters with a non-string body was not enough to tell a DuckDB macro apart: PostgreSQL's `AS $function$ ... $function$ LANGUAGE ...` (a tagged dollar quote lexes as an identifier), `AS U&'...' LANGUAGE ...` and BigQuery's `AS (expr) OPTIONS (...)` became macros and failed. `isCreateFunctionMacroAhead()` also rejects a `$tag$` body and a LANGUAGE or OPTIONS clause outside parentheses before the end of the statement. - `setOverloads()` copies its argument, so a null or immutable list no longer breaks the first-overload setters. - The Javadoc notes that, as in DuckDB, a `,` after a TABLE body ending with a list continues that list. - `testCreateOverloadedMacro` no longer mixes scalar and table overloads, which DuckDB rejects; `testCreateOverloadedTableMacro` covers table overloads.
guizmaii
force-pushed
the
duckdb-create-macro
branch
from
October 13, 2026 03:56
08ab771 to
c63f275
Compare
Contributor
Author
Contributor
|
Big DuckDB fan here, thank you much for this! |
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.
Purpose
Support the rest of DuckDB's CREATE MACRO syntax, which is currently rejected:
CREATE MACRO IF NOT EXISTS name (...) AS ...CREATE MACRO add (a INTEGER, b DOUBLE) AS a + bCREATE MACRO is_maximal (a TINYINT) AS a = 127, (a INT) AS a = 2147483647FUNCTIONas an alias ofMACRO:CREATE FUNCTION add (a, b) AS a + b, which today parses as an opaqueCreateFunctionChange
CreateMacrokeeps a list ofOverloads, each with its parameters and body (expression orTABLEquery).getParameters(),getExpression(),getSelect(),isTable()and their setters address the first overload, so existing callers keep working. It also recordsisIfNotExists()andisFunctionKeyword();Parametergets an optionalgetType().CREATE FUNCTIONis routed toCreateMacroonly whenASdirectly follows the parameter list, the body is not a string ('...',$$ ... $$,$tag$ ... $tag$), and noLANGUAGEorOPTIONSclause follows outside parentheses. Other dialects keep their current parse:... RETURNS ..., PostgreSQL's(IN a integer, OUT b integer) AS $function$ ... $function$ LANGUAGE ..., BigQuery'sAS (expr) OPTIONS (...).RETURNS/OPTIONS,CREATE [TEMP] FUNCTION f(x INT64) AS (x + 1), now parses as aCreateMacro(same shape as a DuckDB macro);CREATE OR REPLACE FUNCTION ds.f(x INT64) AS (x + 1)was an opaqueCreateFunctionbefore.,after aTABLEbody ending with a list (FROM a, ...,GROUP BY a, ...) continues that list rather than starting an overload (documented in the Javadoc).TablesNamesFindervisits the queries of every overload.Validation
check: 10,049 tests, zero failures/errors; Spotless, Checkstyle, PMD and SpotBugs pass.DuckDBTest:IF NOT EXISTS, typed and default parameters, scalar overloads, table overloads (AST andTablesNamesFinder), theFUNCTIONalias in scalar/table/OR REPLACE TEMPORARYforms, and PostgreSQL (RETURNS,$$,$function$) and BigQuery (OPTIONS)CREATE FUNCTIONs that must stayCreateFunction.ERRORSas an unquoted identifier #2781 (ERRORSas an identifier) and Support DuckDB'slambda x, y : exprsyntax #2782 (lambda x, y : expr), all 505 of our production DuckDB queries parse without any rewriting, against 319 on 5.4.