Skip to content

[DO NOT MERGE] ESQL: PoC for name qualifiers #126531

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

Draft
wants to merge 32 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
45dbae9
First attempt at qualifier grammar + some tests
alex-spies Feb 18, 2025
0495b99
Merge remote-tracking branch 'upstream/main' into qualifier-poc
alex-spies Feb 21, 2025
9d5645c
WIP: Update all NamedExpression c'tors
alex-spies Feb 21, 2025
9ad8093
More WIP
alex-spies Mar 10, 2025
7de25ac
Make it compile
alex-spies Mar 10, 2025
6e38051
Make the tests compile, too
alex-spies Mar 10, 2025
8d75844
Fix Alias c'tor
alex-spies Mar 10, 2025
31401c8
Fix mistakes when using UnresolvedAttribute
alex-spies Mar 10, 2025
721e62d
Fix another UnresolvedAttribute usage
alex-spies Mar 10, 2025
abf1008
Fix grammar
alex-spies Mar 12, 2025
7713ecf
WIP
alex-spies Mar 12, 2025
7afdae4
Use qualifiers when resolving
alex-spies Mar 14, 2025
af60385
Add qualifier to UnresolvedRelation
alex-spies Mar 14, 2025
cce600a
Propagate qualifier into FROM resolution
alex-spies Mar 14, 2025
31f0ca3
Make first csv test work with FROM
alex-spies Mar 14, 2025
e999a06
Update tests
alex-spies Mar 17, 2025
fe0a29a
Make EVAL without shadowing work
alex-spies Mar 17, 2025
4fa5c4c
Make RENAME test run
alex-spies Mar 17, 2025
6bf6bb7
Update LOOKUP JOIN test
alex-spies Mar 17, 2025
3d0bd82
Fix LOOKUP JOIN grammar with qualifiers
alex-spies Mar 18, 2025
6307cc3
Improve JOIN grammar, add more LOOKUP JOIN tests
alex-spies Mar 18, 2025
da70688
Make lookup join resolution qualifier-aware
alex-spies Mar 18, 2025
ae66bc8
Make most LOOKUP JOIN tests pass
alex-spies Mar 18, 2025
21139ae
Merge remote-tracking branch 'upstream/main' into qualifier-poc
alex-spies Mar 18, 2025
3b475bb
Merge remote-tracking branch 'upstream/main' into qualifier-poc
alex-spies Apr 8, 2025
6824302
Enable LOOKUP JOIN ... ON left attr == right other
alex-spies Apr 9, 2025
ff4ea32
Merge remote-tracking branch 'upstream/main' into qualifier-poc
alex-spies Apr 9, 2025
cb221a6
Fix tests
alex-spies Apr 9, 2025
8d056f3
Disable failing tests
alex-spies Apr 9, 2025
3d4c40f
Fix test case
alex-spies Apr 9, 2025
6403e8c
Disable the new yml tests for now
alex-spies Apr 9, 2025
ffcdd82
Revert "Disable the new yml tests for now"
alex-spies Apr 9, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@
*
*/
public final class Alias extends NamedExpression {
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(NamedExpression.class, "Alias", Alias::new);
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
NamedExpression.class,
"Alias",
Alias::readFrom
);

private final Expression child;

Expand All @@ -39,44 +43,44 @@ public final class Alias extends NamedExpression {
*/
private Attribute lazyAttribute;

/**
* Sets the qualifier to {@code null}.
* Mostly for tests and convenience wherever qualifiers aren't required.
*/
public Alias(Source source, String name, Expression child) {
this(source, name, child, null);
this(source, null, name, child, null);
}

public Alias(Source source, String name, Expression child, @Nullable NameId id) {
this(source, name, child, id, false);
public Alias(Source source, @Nullable String qualifier, String name, Expression child) {
this(source, qualifier, name, child, null);
}

public Alias(Source source, String name, Expression child, @Nullable NameId id, boolean synthetic) {
super(source, name, singletonList(child), id, synthetic);
this.child = child;
public Alias(Source source, @Nullable String qualifier, String name, Expression child, @Nullable NameId id) {
this(source, qualifier, name, child, id, false);
}

@Deprecated
/**
* Old constructor from when this had a qualifier string. Still needed to not break serialization.
*/
private Alias(Source source, String name, String qualifier, Expression child, @Nullable NameId id, boolean synthetic) {
this(source, name, child, id, synthetic);
public Alias(Source source, @Nullable String qualifier, String name, Expression child, @Nullable NameId id, boolean synthetic) {
super(source, qualifier, name, singletonList(child), id, synthetic);
this.child = child;
}

public Alias(StreamInput in) throws IOException {
this(
Source.readFrom((StreamInput & PlanStreamInput) in),
in.readString(),
in.readOptionalString(),
in.readNamedWriteable(Expression.class),
NameId.readFrom((StreamInput & PlanStreamInput) in),
in.readBoolean()
);
public static Alias readFrom(StreamInput in) throws IOException {
Source source = Source.readFrom((StreamInput & PlanStreamInput) in);
String name = in.readString();
String qualifier = in.readOptionalString();
Expression child = in.readNamedWriteable(Expression.class);
NameId id = NameId.readFrom((StreamInput & PlanStreamInput) in);
boolean synthetic = in.readBoolean();

return new Alias(source, qualifier, name, child, id, synthetic);
}

@Override
public void writeTo(StreamOutput out) throws IOException {
Source.EMPTY.writeTo(out);
out.writeString(name());
// We used to write the qualifier here. We can still do if needed in the future.
out.writeOptionalString(null);
out.writeOptionalString(qualifier());
out.writeNamedWriteable(child());
id().writeTo(out);
out.writeBoolean(synthetic());
Expand All @@ -89,16 +93,16 @@ public String getWriteableName() {

@Override
protected NodeInfo<Alias> info() {
return NodeInfo.create(this, Alias::new, name(), child, id(), synthetic());
return NodeInfo.create(this, Alias::new, qualifier(), name(), child, id(), synthetic());
}

public Alias replaceChild(Expression child) {
return new Alias(source(), name(), child, id(), synthetic());
return new Alias(source(), qualifier(), name(), child, id(), synthetic());
}

@Override
public Alias replaceChildren(List<Expression> newChildren) {
return new Alias(source(), name(), newChildren.get(0), id(), synthetic());
return new Alias(source(), qualifier(), name(), newChildren.get(0), id(), synthetic());
}

public Expression child() {
Expand All @@ -124,20 +128,20 @@ public DataType dataType() {
public Attribute toAttribute() {
if (lazyAttribute == null) {
lazyAttribute = resolved()
? new ReferenceAttribute(source(), name(), dataType(), nullable(), id(), synthetic())
: new UnresolvedAttribute(source(), name());
? new ReferenceAttribute(source(), qualifier(), name(), dataType(), nullable(), id(), synthetic())
: new UnresolvedAttribute(source(), qualifier(), name());
}
return lazyAttribute;
}

@Override
public String toString() {
return child + " AS " + name() + "#" + id();
return child + " AS " + qualifiedName() + "#" + id();
}

@Override
public String nodeString() {
return child.nodeString() + " AS " + name();
return child.nodeString() + " AS " + qualifiedName();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,23 @@ public abstract class Attribute extends NamedExpression {
// can the attr be null - typically used in JOINs
private final Nullability nullability;

public Attribute(Source source, String name, @Nullable NameId id) {
this(source, name, Nullability.TRUE, id);
public Attribute(Source source, @Nullable String qualifier, String name, @Nullable NameId id) {
this(source, qualifier, name, Nullability.TRUE, id);
}

public Attribute(Source source, String name, Nullability nullability, @Nullable NameId id) {
this(source, name, nullability, id, false);
public Attribute(Source source, @Nullable String qualifier, String name, Nullability nullability, @Nullable NameId id) {
this(source, qualifier, name, nullability, id, false);
}

public Attribute(Source source, String name, Nullability nullability, @Nullable NameId id, boolean synthetic) {
super(source, name, emptyList(), id, synthetic);
public Attribute(
Source source,
@Nullable String qualifier,
String name,
Nullability nullability,
@Nullable NameId id,
boolean synthetic
) {
super(source, qualifier, name, emptyList(), id, synthetic);
this.nullability = nullability;
}

Expand All @@ -70,26 +77,36 @@ public AttributeSet references() {
}

public Attribute withLocation(Source source) {
return Objects.equals(source(), source) ? this : clone(source, name(), dataType(), nullable(), id(), synthetic());
return Objects.equals(source(), source) ? this : clone(source, qualifier(), name(), dataType(), nullable(), id(), synthetic());
}

public Attribute withName(String name) {
return Objects.equals(name(), name) ? this : clone(source(), name, dataType(), nullable(), id(), synthetic());
return Objects.equals(name(), name) ? this : clone(source(), qualifier(), name, dataType(), nullable(), id(), synthetic());
}

public Attribute withNullability(Nullability nullability) {
return Objects.equals(nullable(), nullability) ? this : clone(source(), name(), dataType(), nullability, id(), synthetic());
return Objects.equals(nullable(), nullability)
? this
: clone(source(), qualifier(), name(), dataType(), nullability, id(), synthetic());
}

public Attribute withId(NameId id) {
return clone(source(), name(), dataType(), nullable(), id, synthetic());
return clone(source(), qualifier(), name(), dataType(), nullable(), id, synthetic());
}

public Attribute withDataType(DataType type) {
return Objects.equals(dataType(), type) ? this : clone(source(), name(), type, nullable(), id(), synthetic());
return Objects.equals(dataType(), type) ? this : clone(source(), qualifier(), name(), type, nullable(), id(), synthetic());
}

protected abstract Attribute clone(Source source, String name, DataType type, Nullability nullability, NameId id, boolean synthetic);
protected abstract Attribute clone(
Source source,
@Nullable String qualifier,
String name,
DataType type,
Nullability nullability,
NameId id,
boolean synthetic
);

@Override
public Attribute toAttribute() {
Expand All @@ -103,12 +120,12 @@ public int semanticHash() {

@Override
public boolean semanticEquals(Expression other) {
return other instanceof Attribute ? id().equals(((Attribute) other).id()) : false;
return other instanceof Attribute otherAttribute && id().equals(otherAttribute.id());
}

@Override
protected Expression canonicalize() {
return clone(Source.EMPTY, name(), dataType(), nullability, id(), synthetic());
return clone(Source.EMPTY, qualifier(), name(), dataType(), nullability, id(), synthetic());
}

@Override
Expand All @@ -125,7 +142,7 @@ protected boolean innerEquals(Object o) {

@Override
public String toString() {
return name() + "{" + label() + (synthetic() ? "$" : "") + "}" + "#" + id();
return qualifiedName() + "{" + label() + (synthetic() ? "$" : "") + "}" + "#" + id();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package org.elasticsearch.xpack.esql.core.expression;

import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
import org.elasticsearch.xpack.esql.core.tree.Source;
import org.elasticsearch.xpack.esql.core.type.DataType;
Expand All @@ -21,7 +22,7 @@
*/
public class EmptyAttribute extends Attribute {
public EmptyAttribute(Source source) {
super(source, StringUtils.EMPTY, null);
super(source, null, StringUtils.EMPTY, null);
}

@Override
Expand All @@ -35,7 +36,15 @@ public String getWriteableName() {
}

@Override
protected Attribute clone(Source source, String name, DataType type, Nullability nullability, NameId id, boolean synthetic) {
protected Attribute clone(
Source source,
@Nullable String qualifier,
String name,
DataType type,
Nullability nullability,
NameId id,
boolean synthetic
) {
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public final class Expressions {
private Expressions() {}

public static NamedExpression wrapAsNamed(Expression exp) {
return exp instanceof NamedExpression ne ? ne : new Alias(exp.source(), exp.sourceText(), exp);
return exp instanceof NamedExpression ne ? ne : new Alias(exp.source(), null, exp.sourceText(), exp);
}

public static List<Attribute> asAttributes(List<? extends NamedExpression> named) {
Expand Down
Loading