-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
fix: preserve qualifiers when rewriting expressions #12341
Conversation
@@ -336,12 +338,14 @@ impl NamePreserver { | |||
} | |||
|
|||
impl SavedName { | |||
/// Ensures the name of the rewritten expression is preserved | |||
/// Ensures the qualified name of the rewritten expression is preserved | |||
pub fn restore(self, expr: Expr) -> Result<Expr> { |
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.
The return value no longer needs Result
, but removing it breaks many optimization rules. Maybe we can handle it in the next PR.
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.
Looks like a very nice fix to me -- thank you @jonahgao
cc @JasonLi-cn
@@ -303,9 +303,11 @@ pub struct NamePreserver { | |||
use_alias: bool, | |||
} | |||
|
|||
type QualifiedName = (Option<TableReference>, String); |
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.
I would personally suggest creating an enum to make this more explicit (rather than two level of options)-- perhaps something like
pub enum SavedName {
/// name is not preserved
None,
/// qualified name is preserved
Saved {
relation: QualifiedName,
name: String,
}
}
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.
Done.
pub fn restore(self, expr: Expr) -> Result<Expr> { | ||
let Self(original_name) = self; | ||
match original_name { | ||
Some(name) => expr.alias_if_changed(name), |
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.
I seems like we could potentially also remove Expr::alias_if_changed
which doesn't properly account for qualifiers 🤔
The only other use of it seems to be in
pub fn rewrite_preserving_name<R>(expr: Expr, rewriter: &mut R) -> Result<Expr> |
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.
alias_if_changed
is being used by substrait. Maybe we can review this later.
rewrite_preserving_name
has been removed.
|
||
let original_name = expr_from.schema_name().to_string(); | ||
let new_name = expr.schema_name().to_string(); | ||
let saved_name = NamePreserver { use_alias: true }.save(&expr_from).unwrap(); |
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.
Tests use NamePreserver
instead of rewrite_preserving_name
.
Thanks @JasonLi-cn @alamb @Dandandan |
Which issue does this PR close?
A more general fix for #12183
Rationale for this change
The two expressions in the following code have the same
schema_name
s, so theNamePreserver
will not take effect whenexpr1
is rewritten toexpr2
. But they will produce different fields, which will result in schema changes.Therefore, the
NamePreserver
needs to preserve both the qualifier and the schema name to ensure that the rewritten expression has the sameto_field()
result as before.What changes are included in this PR?
Are these changes tested?
Yes
Are there any user-facing changes?
No