Skip to content
Open
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
24 changes: 24 additions & 0 deletions core/src/main/java/io/substrait/plan/Plan.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import io.substrait.SubstraitVersion;
import io.substrait.extension.AdvancedExtension;
import io.substrait.relation.Rel;
import io.substrait.type.NamedFieldCountingTypeVisitor;
import java.util.List;
import java.util.Optional;
import org.immutables.value.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Value.Immutable
public abstract class Plan {
Expand Down Expand Up @@ -61,10 +64,31 @@ private static Version loadVersion() {

@Value.Immutable
public abstract static class Root {
private static final Logger LOGGER = LoggerFactory.getLogger(Root.class);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't think this is a great solution. But considering that this update will result in stricter plan enforcement, I want to figure out a way where we can just warn on incorrect behavior for now, and then make it an actual error in the future.

But I'm not sure introducing a logger here where one isn't used anywhere else makes sense.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see. Left a comment on whether we want to make the spec more clear first. If the spec clearly says names are required then we can fire the exception straight away and we handle the change in behavior as a breaking change commit so it gets announced to consumers of substrait-java. That would then be sufficient in my opinion. Logging a warning to communicate the upcoming change is a nice gesture but who knows if consumers notice the warning message.


public abstract Rel getInput();

public abstract List<String> getNames();

@Value.Check
protected void check() {
final int actualNameCount = getNames().size();
if (actualNameCount == 0) {
LOGGER.warn(
"Plan.Root built without output names; this will be an error in the next release");
return;
}
Comment on lines +76 to +80
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I have the feeling like we need to make the spec more clear on names being required for Plan.Root.

We probably also should flesh out the Plan Root documentation a little bit more to describe the structure and reference to the NamedStruct documentation.

What do you think?


final int expectedFieldCount =
NamedFieldCountingTypeVisitor.countNames(getInput().getRecordType());
if (actualNameCount != expectedFieldCount) {
Comment thread
benbellick marked this conversation as resolved.
throw new IllegalArgumentException(
String.format(
"Plan.Root names count (%d) must match input record type depth-first named-field count (%d)",
actualNameCount, expectedFieldCount));
}
}

public static ImmutableRoot.Builder builder() {
return ImmutableRoot.builder();
}
Expand Down
160 changes: 1 addition & 159 deletions core/src/main/java/io/substrait/relation/VirtualTableScan.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package io.substrait.relation;

import io.substrait.expression.Expression;
import io.substrait.type.NamedFieldCountingTypeVisitor;
import io.substrait.type.Type;
import io.substrait.type.TypeVisitor;
import io.substrait.util.VisitationContext;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -90,162 +90,4 @@ public <O, C extends VisitationContext, E extends Exception> O accept(
public static ImmutableVirtualTableScan.Builder builder() {
return ImmutableVirtualTableScan.builder();
}

private static class NamedFieldCountingTypeVisitor
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice, I had no idea we already had such a visitor in the code base

implements TypeVisitor<Integer, RuntimeException> {

private static final NamedFieldCountingTypeVisitor VISITOR =
new NamedFieldCountingTypeVisitor();

private static Integer countNames(Type type) {
return type.accept(VISITOR);
}

@Override
public Integer visit(Type.Bool type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.I8 type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.I16 type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.I32 type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.I64 type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.FP32 type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.FP64 type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.Str type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.Binary type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.Date type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.Time type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.TimestampTZ type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.Timestamp type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.PrecisionTimestamp type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.PrecisionTime type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.PrecisionTimestampTZ type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.IntervalYear type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.IntervalDay type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.IntervalCompound type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.UUID type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.FixedChar type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.VarChar type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.FixedBinary type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.Decimal type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.Struct type) throws RuntimeException {
// Only struct fields have names - the top level column names are also
// captured by this since the whole schema is wrapped in a Struct type
return type.fields().stream().mapToInt(field -> 1 + field.accept(this)).sum();
}

@Override
public Integer visit(Type.ListType type) throws RuntimeException {
return type.elementType().accept(this);
}

@Override
public Integer visit(Type.Map type) throws RuntimeException {
return type.key().accept(this) + type.value().accept(this);
}

@Override
public Integer visit(Type.UserDefined type) throws RuntimeException {
return 0;
}

@Override
public Integer visit(Type.Func type) throws RuntimeException {
return 0;
}
}
}
Loading
Loading