-
Notifications
You must be signed in to change notification settings - Fork 25.6k
ESQL: Make equals include ids for Alias, TypedAttribute #132455
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
Changes from all commits
a707bec
2048598
d0a994f
d34572a
3e8e919
a2bb5e9
a191f30
f77652c
41a60d3
c67035c
eb07eb6
eeb6c5a
4771dba
eb47b87
9db6528
782067b
6b7fa4e
09cd30a
8309ca6
5f4cd4f
9dcbd41
6ff0283
1e6b100
4dab56b
5f62f72
f5add18
9d9ad86
c73b45d
8800d90
e40f95f
9800b8e
53d50e9
99dd677
8d6a0fa
5afab2f
6c5bd8c
44f580d
c6b4c24
4443fcd
349c3fe
b00b639
af30e47
6253ef0
f3acb8f
826d4b6
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 |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| pr: 132455 | ||
| summary: "Make equals include ids for Alias, `TypedAttribute`" | ||
| area: ES|QL | ||
| type: bug | ||
| issues: | ||
| - 131509 | ||
| - 132634 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,16 +22,55 @@ | |
| /** | ||
| * {@link Expression}s that can be materialized and describe properties of the derived table. | ||
| * In other words, an attribute represent a column in the results of a query. | ||
| * | ||
| * <p> | ||
| * In the statement {@code SELECT ABS(foo), A, B+C FROM ...} the three named | ||
| * expressions {@code ABS(foo), A, B+C} get converted to attributes and the user can | ||
| * only see Attributes. | ||
| * | ||
| * <p> | ||
| * In the statement {@code SELECT foo FROM TABLE WHERE foo > 10 + 1} only {@code foo} inside the SELECT | ||
| * is a named expression (an {@code Alias} will be created automatically for it). | ||
| * The rest are not as they are not part of the projection and thus are not part of the derived table. | ||
| * <p> | ||
| * Note on equality: Because the name alone is not sufficient to identify an attribute | ||
| * (two different relations can have the same attribute name), attributes get a unique {@link #id()} | ||
| * assigned at creation which is respected in equality checks and hashing. | ||
| * <p> | ||
| * Caution! {@link #semanticEquals(Expression)} and {@link #semanticHash()} rely solely on the id. | ||
| * But this doesn't extend to expressions containing attributes as children. | ||
| */ | ||
| public abstract class Attribute extends NamedExpression { | ||
|
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 attribute hierarchy is getting scarier for me. Something like: this will have the super set of all fields needed for everything but will be much easier to check equality and type (opposed to instanceof). Updating serialization accordingly might be a chllenge. 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. Hm, maybe that's possible, but will mess with many |
||
| /** | ||
| * A wrapper class where equality of the contained attribute ignores the {@link Attribute#id()}. Useful when we want to create new | ||
alex-spies marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| * attributes and want to avoid duplicates. Because we assign unique ids on creation, a normal equality check would always fail when | ||
| * we create the "same" attribute again. | ||
| * <p> | ||
| * C.f. {@link AttributeMap} (and its contained wrapper class) which does the exact opposite: ignores everything but the id by | ||
| * using {@link Attribute#semanticEquals(Expression)}. | ||
| */ | ||
| public record IdIgnoringWrapper(Attribute inner) { | ||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) { | ||
| return true; | ||
| } | ||
| if (o == null || getClass() != o.getClass()) { | ||
| return false; | ||
| } | ||
|
|
||
| Attribute otherAttribute = ((IdIgnoringWrapper) o).inner(); | ||
| return inner().equals(otherAttribute, true); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return inner().hashCode(true); | ||
| } | ||
| } | ||
|
|
||
| public IdIgnoringWrapper ignoreId() { | ||
| return new IdIgnoringWrapper(this); | ||
| } | ||
|
|
||
| /** | ||
| * Changing this will break bwc with 8.15, see {@link FieldAttribute#fieldName()}. | ||
| */ | ||
|
|
@@ -152,7 +191,7 @@ public int semanticHash() { | |
|
|
||
| @Override | ||
| public boolean semanticEquals(Expression other) { | ||
| return other instanceof Attribute ? id().equals(((Attribute) other).id()) : false; | ||
| return other instanceof Attribute otherAttr && id().equals(otherAttr.id()); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -161,15 +200,16 @@ protected Expression canonicalize() { | |
| } | ||
|
|
||
| @Override | ||
| @SuppressWarnings("checkstyle:EqualsHashCode")// equals is implemented in parent. See innerEquals instead | ||
| public int hashCode() { | ||
| return Objects.hash(super.hashCode(), qualifier, nullability); | ||
| protected int innerHashCode(boolean ignoreIds) { | ||
| return Objects.hash(super.innerHashCode(ignoreIds), qualifier, nullability); | ||
| } | ||
|
|
||
| @Override | ||
| protected boolean innerEquals(Object o) { | ||
| protected boolean innerEquals(Object o, boolean ignoreIds) { | ||
| var other = (Attribute) o; | ||
| return super.innerEquals(other) && Objects.equals(qualifier, other.qualifier) && Objects.equals(nullability, other.nullability); | ||
| return super.innerEquals(other, ignoreIds) | ||
| && Objects.equals(qualifier, other.qualifier) | ||
| && Objects.equals(nullability, other.nullability); | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.