Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/changelog/137040.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pr: 137040
summary: Introduce a new interface to declare functions depending on the `@timestamp`
attribute
area: ES|QL
type: enhancement
issues:
- 136772
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ public enum ParamOrdinal {
SECOND,
THIRD,
FOURTH,
FIFTH;
FIFTH,
IMPLICIT;

public static ParamOrdinal fromIndex(int index) {
return switch (index) {
return index < 0 ? IMPLICIT : switch (index) {
case 0 -> FIRST;
case 1 -> SECOND;
case 2 -> THIRD;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@
public class UnresolvedAttribute extends Attribute implements Unresolvable {
private final boolean customMessage;
protected final String unresolvedMsg;
// TODO: unused and always null, remove this.
protected final Object resolutionMetadata;

// TODO: Check usage of constructors without qualifiers, that's likely where qualifiers need to be plugged into resolution logic.
public UnresolvedAttribute(Source source, String name) {
Expand All @@ -45,17 +43,11 @@ public UnresolvedAttribute(Source source, String name, @Nullable String unresolv
}

public UnresolvedAttribute(Source source, @Nullable String qualifier, String name, @Nullable String unresolvedMessage) {
this(source, qualifier, name, null, unresolvedMessage, null);
this(source, qualifier, name, null, unresolvedMessage);
}

public UnresolvedAttribute(
Source source,
String name,
@Nullable NameId id,
@Nullable String unresolvedMessage,
Object resolutionMetadata
) {
this(source, null, name, id, unresolvedMessage, resolutionMetadata);
public UnresolvedAttribute(Source source, String name, @Nullable NameId id, @Nullable String unresolvedMessage) {
this(source, null, name, id, unresolvedMessage);
}

@SuppressWarnings("this-escape")
Expand All @@ -64,15 +56,11 @@ public UnresolvedAttribute(
@Nullable String qualifier,
String name,
@Nullable NameId id,
@Nullable String unresolvedMessage,
Object resolutionMetadata
@Nullable String unresolvedMessage
) {
super(source, qualifier, name, id);
this.customMessage = unresolvedMessage != null;
this.unresolvedMsg = unresolvedMessage == null
? errorMessage(qualifier() != null ? qualifiedName() : name(), null)
: unresolvedMessage;
this.resolutionMetadata = resolutionMetadata;
this.unresolvedMsg = unresolvedMessage != null ? unresolvedMessage : defaultUnresolvedMessage(null);
}

@Override
Expand All @@ -87,11 +75,7 @@ public String getWriteableName() {

@Override
protected NodeInfo<? extends UnresolvedAttribute> info() {
return NodeInfo.create(this, UnresolvedAttribute::new, qualifier(), name(), id(), unresolvedMsg, resolutionMetadata);
}

public Object resolutionMetadata() {
return resolutionMetadata;
return NodeInfo.create(this, UnresolvedAttribute::new, qualifier(), name(), id(), unresolvedMsg);
}

public boolean customMessage() {
Expand Down Expand Up @@ -120,11 +104,11 @@ protected Attribute clone(
// Cannot just use the super method because that requires a data type.
@Override
public UnresolvedAttribute withId(NameId id) {
return new UnresolvedAttribute(source(), qualifier(), name(), id, unresolvedMessage(), resolutionMetadata());
return new UnresolvedAttribute(source(), qualifier(), name(), id, unresolvedMessage());
}

public UnresolvedAttribute withUnresolvedMessage(String unresolvedMessage) {
return new UnresolvedAttribute(source(), qualifier(), name(), id(), unresolvedMessage, resolutionMetadata());
return new UnresolvedAttribute(source(), qualifier(), name(), id(), unresolvedMessage);
}

@Override
Expand Down Expand Up @@ -169,6 +153,10 @@ public String unresolvedMessage() {
return unresolvedMsg;
}

public String defaultUnresolvedMessage(@Nullable List<String> potentialMatches) {
return errorMessage(qualifier() != null ? qualifiedName() : name(), potentialMatches);
}

public static String errorMessage(String name, List<String> potentialMatches) {
String msg = "Unknown column [" + name + "]";
if (CollectionUtils.isEmpty(potentialMatches) == false) {
Expand All @@ -181,14 +169,12 @@ public static String errorMessage(String name, List<String> potentialMatches) {

@Override
protected int innerHashCode(boolean ignoreIds) {
return Objects.hash(super.innerHashCode(ignoreIds), resolutionMetadata, unresolvedMsg);
return Objects.hash(super.innerHashCode(ignoreIds), unresolvedMsg);
}

@Override
protected boolean innerEquals(Object o, boolean ignoreIds) {
var other = (UnresolvedAttribute) o;
return super.innerEquals(o, ignoreIds)
&& Objects.equals(resolutionMetadata, other.resolutionMetadata)
&& Objects.equals(unresolvedMsg, other.unresolvedMsg);
return super.innerEquals(o, ignoreIds) && Objects.equals(unresolvedMsg, other.unresolvedMsg);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,65 +7,43 @@

package org.elasticsearch.xpack.esql.core.expression;

import org.elasticsearch.core.Nullable;
import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
import org.elasticsearch.xpack.esql.core.tree.Source;

import java.util.Objects;
import java.util.List;

public class UnresolvedTimestamp extends UnresolvedAttribute {
private final String errorMessage;

public UnresolvedTimestamp(Source source, String errorMessage) {
this(source, null, MetadataAttribute.TIMESTAMP_FIELD, null, null, null, errorMessage);
public static final String UNRESOLVED_SUFFIX = "requires the ["
+ MetadataAttribute.TIMESTAMP_FIELD
+ "] field, which was either not present in the source index, or has been dropped"
+ " or renamed"; // TODO: track the name change

public UnresolvedTimestamp(Source source) {
this(source, null, MetadataAttribute.TIMESTAMP_FIELD, null, null);
}

public UnresolvedTimestamp(
Source source,
String qualifier,
String name,
NameId id,
String unresolvedMessage,
Object resolutionMetadata,
String errorMessage
) {
super(source, qualifier, name, id, unresolvedMessage, resolutionMetadata);
this.errorMessage = errorMessage;
public UnresolvedTimestamp(Source source, String qualifier, String name, NameId id, String unresolvedMessage) {
super(source, qualifier, name, id, unresolvedMessage);
}

@Override
protected NodeInfo<UnresolvedTimestamp> info() {
return NodeInfo.create(
this,
UnresolvedTimestamp::new,
qualifier(),
name(),
id(),
super.unresolvedMessage(),
resolutionMetadata(),
errorMessage
);
return NodeInfo.create(this, UnresolvedTimestamp::new, qualifier(), name(), id(), super.unresolvedMessage());
}

@Override
public UnresolvedTimestamp withUnresolvedMessage(String unresolvedMessage) {
return new UnresolvedTimestamp(source(), qualifier(), name(), id(), unresolvedMessage, resolutionMetadata(), errorMessage);
return new UnresolvedTimestamp(source(), qualifier(), name(), id(), unresolvedMessage);
}

@Override
public String unresolvedMessage() {
if (super.unresolvedMessage() != null) {
return errorMessage;
}
return null;
public String defaultUnresolvedMessage(@Nullable List<String> ignored) {
return "[" + sourceText() + "] " + UNRESOLVED_SUFFIX;
}

@Override
protected int innerHashCode(boolean ignoreIds) {
return Objects.hash(super.innerHashCode(ignoreIds), errorMessage);
}

@Override
protected boolean innerEquals(Object o, boolean ignoreIds) {
return super.innerEquals(o, ignoreIds) && Objects.equals(errorMessage, ((UnresolvedTimestamp) o).errorMessage);
public static UnresolvedTimestamp withSource(Source source) {
return new UnresolvedTimestamp(source);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -501,63 +501,23 @@ protected LogicalPlan rule(LogicalPlan plan, AnalyzerContext context) {
childrenOutput.addAll(output);
}

if (plan instanceof Aggregate aggregate) {
return resolveAggregate(aggregate, childrenOutput);
}

if (plan instanceof Completion c) {
return resolveCompletion(c, childrenOutput);
}

if (plan instanceof Drop d) {
return resolveDrop(d, childrenOutput);
}

if (plan instanceof Rename r) {
return resolveRename(r, childrenOutput);
}

if (plan instanceof Keep p) {
return resolveKeep(p, childrenOutput);
}

if (plan instanceof Fork f) {
return resolveFork(f, context);
}

if (plan instanceof Eval p) {
return resolveEval(p, childrenOutput);
}

if (plan instanceof Enrich p) {
return resolveEnrich(p, childrenOutput);
}

if (plan instanceof MvExpand p) {
return resolveMvExpand(p, childrenOutput);
}

if (plan instanceof Lookup l) {
return resolveLookup(l, childrenOutput);
}

if (plan instanceof LookupJoin j) {
return resolveLookupJoin(j, context);
}

if (plan instanceof Insist i) {
return resolveInsist(i, childrenOutput, context);
}

if (plan instanceof Fuse fuse) {
return resolveFuse(fuse, childrenOutput);
}

if (plan instanceof Rerank r) {
return resolveRerank(r, childrenOutput);
}

return plan.transformExpressionsOnly(UnresolvedAttribute.class, ua -> maybeResolveAttribute(ua, childrenOutput));
return switch (plan) {
Copy link
Member

Choose a reason for hiding this comment

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

👍

case Aggregate a -> resolveAggregate(a, childrenOutput);
case Completion c -> resolveCompletion(c, childrenOutput);
case Drop d -> resolveDrop(d, childrenOutput);
case Rename r -> resolveRename(r, childrenOutput);
case Keep p -> resolveKeep(p, childrenOutput);
case Fork f -> resolveFork(f, context);
case Eval p -> resolveEval(p, childrenOutput);
case Enrich p -> resolveEnrich(p, childrenOutput);
case MvExpand p -> resolveMvExpand(p, childrenOutput);
case Lookup l -> resolveLookup(l, childrenOutput);
case LookupJoin j -> resolveLookupJoin(j, context);
case Insist i -> resolveInsist(i, childrenOutput, context);
case Fuse fuse -> resolveFuse(fuse, childrenOutput);
case Rerank r -> resolveRerank(r, childrenOutput);
default -> plan.transformExpressionsOnly(UnresolvedAttribute.class, ua -> maybeResolveAttribute(ua, childrenOutput));
};
}

private Aggregate resolveAggregate(Aggregate aggregate, List<Attribute> childrenOutput) {
Expand Down Expand Up @@ -715,8 +675,7 @@ private LogicalPlan resolveLookup(Lookup l, List<Attribute> childrenOutput) {
+ joinedAttribute.dataType().typeName()
+ "] and original column was ["
+ attr.dataType().typeName()
+ "]",
null
+ "]"
);
}
}
Expand Down Expand Up @@ -1431,7 +1390,7 @@ private static List<Attribute> resolveAgainstList(UnresolvedNamePattern up, Coll

private static List<Attribute> resolveAgainstList(UnresolvedAttribute ua, Collection<Attribute> attrList) {
var matches = AnalyzerRules.maybeResolveAgainstList(ua, attrList, a -> Analyzer.handleSpecialFields(ua, a));
return potentialCandidatesIfNoMatchesFound(ua, matches, attrList, list -> UnresolvedAttribute.errorMessage(ua.name(), list));
return potentialCandidatesIfNoMatchesFound(ua, matches, attrList, ua::defaultUnresolvedMessage);
}

private static List<Attribute> potentialCandidatesIfNoMatchesFound(
Expand Down Expand Up @@ -1703,7 +1662,7 @@ private static Expression processScalarOrGroupingFunction(
if (arg.foldable() && ((arg instanceof EsqlScalarFunction) == false)) {
if (i < targetDataTypes.size()) {
targetDataType = targetDataTypes.get(i);
}
} // else the last type applies to all elements in a possible list (variadic)
if (targetDataType != NULL && targetDataType != UNSUPPORTED) {
Expression e = castStringLiteral(arg, targetDataType);
if (e != arg) {
Expand Down
Loading