-
Notifications
You must be signed in to change notification settings - Fork 25.6k
#46396 fix npe on ambiguous group by #56489
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
1ac4aaf
250fee4
f7d8710
378e087
ae8ea65
99ecbed
cbe4c64
69afda9
f393faa
5c1419e
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,50 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License; | ||
| * you may not use this file except in compliance with the Elastic License. | ||
| */ | ||
|
|
||
| package org.elasticsearch.xpack.ql.expression; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class AttributeAlias { | ||
|
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. Could you please replace this with a Tuple<Attribute, Expression>? |
||
| private final Attribute attribute; | ||
| private final Expression expression; | ||
|
|
||
| public AttributeAlias(Attribute attribute, Expression expression) { | ||
| this.attribute = attribute; | ||
| this.expression = expression; | ||
| } | ||
|
|
||
| public Attribute getAttribute() { | ||
| return attribute; | ||
| } | ||
|
|
||
| public Expression getExpression() { | ||
| return expression; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) { | ||
| return true; | ||
| } | ||
| if (o == null || getClass() != o.getClass()) { | ||
| return false; | ||
| } | ||
| AttributeAlias that = (AttributeAlias) o; | ||
| return Objects.equals(attribute, that.attribute) && | ||
| Objects.equals(expression, that.expression); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(attribute, expression); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "Alias {" + attribute.toString() + " -> " + expression.toString() + "}"; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,7 @@ | |
| import org.elasticsearch.xpack.ql.common.Failure; | ||
| import org.elasticsearch.xpack.ql.expression.Alias; | ||
| import org.elasticsearch.xpack.ql.expression.Attribute; | ||
| import org.elasticsearch.xpack.ql.expression.AttributeMap; | ||
| import org.elasticsearch.xpack.ql.expression.AttributeAlias; | ||
| import org.elasticsearch.xpack.ql.expression.AttributeSet; | ||
| import org.elasticsearch.xpack.ql.expression.Expression; | ||
| import org.elasticsearch.xpack.ql.expression.Expressions; | ||
|
|
@@ -41,6 +41,7 @@ | |
| import org.elasticsearch.xpack.ql.rule.Rule; | ||
| import org.elasticsearch.xpack.ql.rule.RuleExecutor; | ||
| import org.elasticsearch.xpack.ql.session.Configuration; | ||
| import org.elasticsearch.xpack.ql.tree.Location; | ||
| import org.elasticsearch.xpack.ql.type.DataType; | ||
| import org.elasticsearch.xpack.ql.type.DataTypes; | ||
| import org.elasticsearch.xpack.ql.type.InvalidMappedField; | ||
|
|
@@ -181,7 +182,7 @@ private static Attribute resolveAgainstList(UnresolvedAttribute u, Collection<At | |
| // but also if the qualifier might not be quoted and if there's any ambiguity with nested fields | ||
| || Objects.equals(u.name(), attribute.qualifiedName())); | ||
| if (match) { | ||
| matches.add(attribute.withLocation(u.source())); | ||
| matches.add(attribute); | ||
|
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. Why removing it from here and adding it only if |
||
| } | ||
| } | ||
| } | ||
|
|
@@ -192,16 +193,24 @@ private static Attribute resolveAgainstList(UnresolvedAttribute u, Collection<At | |
| } | ||
|
|
||
| if (matches.size() == 1) { | ||
| return handleSpecialFields(u, matches.get(0), allowCompound); | ||
| Attribute match = matches.get(0).withLocation(u.source()); | ||
| return handleSpecialFields(u, match, allowCompound); | ||
| } | ||
|
|
||
| return u.withUnresolvedMessage("Reference [" + u.qualifiedName() | ||
| + "] is ambiguous (to disambiguate use quotes or qualifiers); matches any of " + | ||
| matches.stream() | ||
| .map(a -> "\"" + a.qualifier() + "\".\"" + a.name() + "\"") | ||
| .sorted() | ||
| .map(Analyzer::buildUnresolvedMessagesMatchesList) | ||
| .collect(toList()) | ||
| ); | ||
|
|
||
| } | ||
|
|
||
| private static String buildUnresolvedMessagesMatchesList(Attribute a) { | ||
| Location location = a.sourceLocation(); | ||
| String locationString = "line " + location.getLineNumber() + ":" + location.getColumnNumber(); | ||
| return locationString + " [" + (a.qualifier() != null ? "\"" + a.qualifier() + "\"." : "") + "\"" + a.name() + "\"]"; | ||
| } | ||
|
|
||
| private static Attribute handleSpecialFields(UnresolvedAttribute u, Attribute named, boolean allowCompound) { | ||
|
|
@@ -333,16 +342,25 @@ else if (plan instanceof Aggregate) { | |
| if (!a.expressionsResolved() && Resolvables.resolved(a.aggregates())) { | ||
| List<Expression> groupings = a.groupings(); | ||
| List<Expression> newGroupings = new ArrayList<>(); | ||
| AttributeMap<Expression> resolved = Expressions.aliases(a.aggregates()); | ||
| List<AttributeAlias> resolved = Expressions.aliases(a.aggregates()); | ||
|
|
||
| boolean changed = false; | ||
| for (Expression grouping : groupings) { | ||
| if (grouping instanceof UnresolvedAttribute) { | ||
| Attribute maybeResolved = resolveAgainstList((UnresolvedAttribute) grouping, resolved.keySet()); | ||
| Attribute maybeResolved = resolveAgainstList((UnresolvedAttribute) grouping, | ||
| resolved.stream().map(AttributeAlias::getAttribute).collect(toList())); | ||
| if (maybeResolved != null) { | ||
| changed = true; | ||
| // use the matched expression (not its attribute) | ||
| grouping = resolved.get(maybeResolved); | ||
| if (maybeResolved.resolved()) { | ||
| // use the matched expression (not its attribute) | ||
| grouping = resolved.stream() | ||
| .filter(attributeAlias -> attributeAlias.getAttribute().equals(maybeResolved)) | ||
|
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. Imho, it would be better to use a for loop to increase readability. |
||
| .map(AttributeAlias::getExpression) | ||
| .findAny() | ||
| .orElse(maybeResolved); | ||
| } else { | ||
| grouping = maybeResolved; | ||
| } | ||
| } | ||
| } | ||
| newGroupings.add(grouping); | ||
|
|
||
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.
Making generic class Attribute to implement Comparable just for the purposes of constructing a nice error message is a bit too much. Please remove the comparison implementation from here and use a custom comparator to sort the ambiguous attributes.