Skip to content
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

Unparse struct to sql #13493

Merged
merged 8 commits into from
Nov 21, 2024
Merged

Unparse struct to sql #13493

merged 8 commits into from
Nov 21, 2024

Conversation

delamarch3
Copy link
Contributor

@delamarch3 delamarch3 commented Nov 19, 2024

Which issue does this PR close?

Closes #13477

Rationale for this change

Support roundtrip for statements containing named_struct and get_field

What changes are included in this PR?

Implement expr_to_sql for named_struct and get_field

Are these changes tested?

Yes

Are there any user-facing changes?

No

@github-actions github-actions bot added the sql SQL Planner label Nov 19, 2024
@delamarch3 delamarch3 marked this pull request as draft November 19, 2024 19:34
@delamarch3 delamarch3 marked this pull request as ready for review November 20, 2024 08:46
Copy link
Contributor

@jonathanc-n jonathanc-n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This look good to me! Just left some minor error changes.

ast::Expr::CompoundIdentifier(idents) => idents,
_ => unreachable!(),
},
_ => return internal_err!("get_field column is invalid"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_ => return internal_err!("get_field column is invalid"),
_ => return internal_err!("get_field expects first argument to be column, but received {:?}", args[0]),

Error message should be more clear here for feedback

Expr::Column(col) => match self.col_to_sql(col)? {
ast::Expr::Identifier(ident) => vec![ident],
ast::Expr::CompoundIdentifier(idents) => idents,
_ => unreachable!(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_ => unreachable!(),
_ => return internal_err!("get_field expects an Identifier or CompoundIdentifier, but received: {:?}", other)

I feel like unreachable should be avoided

@delamarch3
Copy link
Contributor Author

Thanks @jonathanc-n, I've updated the errors

@alamb alamb added the unparser unparser component label Nov 20, 2024
Copy link
Contributor

@goldmedal goldmedal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @delamarch3 overall looks good to me 👍 Only some suggestions.

datafusion/sql/src/unparser/expr.rs Outdated Show resolved Hide resolved
Comment on lines +547 to +554
let mut id = match &args[0] {
Expr::Column(col) => match self.col_to_sql(col)? {
ast::Expr::Identifier(ident) => vec![ident],
ast::Expr::CompoundIdentifier(idents) => idents,
other => return internal_err!("expected col_to_sql to return an Identifier or CompoundIdentifier, but received: {:?}", other),
},
_ => return internal_err!("get_field expects first argument to be column, but received: {:?}", &args[0]),
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider the more complex cases, a struct contains a struct field. Consider the following SQL that uses another way to access the struct:

> explain SELECT s.a['a1'] FROM (SELECT {a:{a1:c1}, b:{a1:c1}} AS s from t1);
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| plan_type     | plan                                                                                                                                      |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| logical_plan  | Projection: get_field(get_field(named_struct(Utf8("a"), __common_expr_1, Utf8("b"), __common_expr_1), Utf8("a")), Utf8("a1")) AS s[a][a1] |
|               |   Projection: named_struct(Utf8("a1"), t1.c1) AS __common_expr_1                                                                          |
|               |     TableScan: t1 projection=[c1]   

You can see the get_field accepts another get_field function. However, I think we can't do a roundtrip test for this kind of case currently because SQL like select s.a.a1 isn't supported (apache/datafusion-sqlparser-rs#1541 will address it).

By the way, I think we can file a follow-up issue for the nested case. We don't need to support it in this PR.

@delamarch3
Copy link
Contributor Author

Thanks for the review @goldmedal

@alamb alamb merged commit e7d9504 into apache:main Nov 21, 2024
25 checks passed
@alamb
Copy link
Contributor

alamb commented Nov 21, 2024

🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
sql SQL Planner unparser unparser component
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unparse Struct plan to SQL string
4 participants