-
Notifications
You must be signed in to change notification settings - Fork 774
Separate the LAMBDA keyword syntax from the -> lambda syntax #2458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
efaff5e
fe38a95
d192b32
290f106
98b8dcb
7b472d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -535,10 +535,37 @@ pub trait Dialect: Debug + Any { | |
| /// ```sql | ||
| /// SELECT transform(array(1, 2, 3), x -> x + 1); -- returns [2,3,4] | ||
| /// ``` | ||
| /// | ||
| /// This enables both the `->` spelling above and the `LAMBDA` keyword | ||
| /// spelling gated by [`Self::supports_lambda_keyword_syntax`]. A dialect | ||
| /// that uses `->` as a binary operator should override only the latter. | ||
| fn supports_lambda_functions(&self) -> bool { | ||
| false | ||
| } | ||
|
|
||
| /// Returns true if the dialect supports the `LAMBDA` keyword spelling of | ||
| /// lambda functions, for example: | ||
| /// | ||
| /// ```sql | ||
| /// SELECT list_transform([1, 2, 3], lambda x : x + 1); -- returns [2, 3, 4] | ||
| /// ``` | ||
| /// | ||
| /// This spelling does not claim the `->` token, so it can be enabled by | ||
| /// dialects that already give `->` a different meaning — for example JSON | ||
| /// member access. DuckDB uses `->` for both, resolving the ambiguity from | ||
| /// the function signature at bind time rather than while parsing, and | ||
| /// deprecated the arrow lambda form in v1.3 in favour of this one; v2.0 | ||
| /// disables the arrow form by default. | ||
| /// | ||
| /// Defaults to [`Self::supports_lambda_functions`], so dialects supporting | ||
| /// the `->` spelling accept the `LAMBDA` spelling too unless they say | ||
| /// otherwise. | ||
| /// | ||
| /// See <https://duckdb.org/docs/stable/sql/functions/lambda> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Im not sure I understood the problem being solved for - the description mentions pg as an example, suggesting there is some ambiguous grammar in play but pg doesnt have lambda syntax to my knowledge? is there an example syntax that issupported by a dialect and the parser doesnt cover?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a fair point. I replied in #2458 (comment) but reflecting a bit more I think there's an even stronger framing. Your hesitation comes from PostgreSQL being a bad example. It has no lambda syntax, so the new flag For DuckDB this enables fixing a live bug rather than a hypothetical. // DuckDbDialect
"SELECT j -> 'field' FROM t" // => Expr::Lambda { params: [j], body: 'field' } ❌
"SELECT t.j -> 'field' FROM t" // => BinaryOp { op: Arrow } ✅A bare column becomes a lambda, a qualified one stays JSON access. Both print back as DuckDB itself resolves I've deliberately not flipped This PR also pplies to custom dialects wanting JSON accessors and lambdas at once, which
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @iffyio please let me know if this explanation clarified things or if it is still unclear |
||
| fn supports_lambda_keyword_syntax(&self) -> bool { | ||
|
adriangb marked this conversation as resolved.
|
||
| self.supports_lambda_functions() | ||
| } | ||
|
Comment on lines
+565
to
+567
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One could argue for adding
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Arrow-only is already expressible by overriding |
||
|
|
||
| /// Returns true if the dialect supports multiple variable assignment | ||
| /// using parentheses in a `SET` variable declaration. | ||
| /// | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -902,6 +902,24 @@ fn test_duckdb_lambda_function() { | |||||||||||||||
| let sql_arrow = "SELECT list_filter([1, 2, 3], x -> x > 1)"; | ||||||||||||||||
| duckdb().verified_stmt(sql_arrow); | ||||||||||||||||
|
|
||||||||||||||||
| // `->` is ambiguous in DuckDB: it is both the arrow lambda spelling and | ||||||||||||||||
| // JSON member access, and DuckDB resolves it from the function signature | ||||||||||||||||
| // at bind time. `DuckDbDialect` currently resolves it to a lambda. Both | ||||||||||||||||
| // readings print identically, so round-tripping cannot tell them apart — | ||||||||||||||||
| // assert the shape so any future change to that choice is visible here. | ||||||||||||||||
|
Comment on lines
+905
to
+909
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The bind-time detail repeats the trait doc, I think we can deduplicate it in this manner:
Suggested change
|
||||||||||||||||
| let select = duckdb().verified_only_select(sql_arrow); | ||||||||||||||||
| let Expr::Function(func) = expr_from_projection(only(&select.projection)) else { | ||||||||||||||||
| panic!("expected a function call"); | ||||||||||||||||
| }; | ||||||||||||||||
| let FunctionArguments::List(args) = &func.args else { | ||||||||||||||||
| panic!("expected an argument list"); | ||||||||||||||||
| }; | ||||||||||||||||
| let [_, FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Lambda(lambda)))] = &args.args[..] | ||||||||||||||||
| else { | ||||||||||||||||
| panic!("expected the second argument to be a lambda"); | ||||||||||||||||
| }; | ||||||||||||||||
| assert_eq!(LambdaSyntax::Arrow, lambda.syntax); | ||||||||||||||||
|
|
||||||||||||||||
| // Test lambda with multiple parameters (with index) | ||||||||||||||||
| let sql_multi = "SELECT list_filter([1, 3, 1, 5], lambda x, i : x > i)"; | ||||||||||||||||
| duckdb().verified_stmt(sql_multi); | ||||||||||||||||
|
|
||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Version numbers in a doc comment go stale without anyone noticing, and the DuckDB page you link already carries them. I think we can trim this down in this fashion.