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
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ public static SingularOrListNode makeSingularOrListNode(
return new SingularOrListNode(value, expressionNodes);
}

public static SingularOrListNode makeSingularOrListNode(
ExpressionNode value, List<Object> rawValues, org.apache.spark.sql.types.DataType dataType) {
return new SingularOrListNode(value, rawValues, dataType);
}

public static WindowFunctionNode makeWindowFunction(
Integer functionId,
List<ExpressionNode> expressionNodes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.apache.gluten.substrait.expression;

import io.substrait.proto.Expression;
import org.apache.spark.sql.types.DataType;

import java.io.Serializable;
import java.util.ArrayList;
Expand All @@ -25,18 +26,39 @@
public class SingularOrListNode implements ExpressionNode, Serializable {
private final ExpressionNode value;
private final List<ExpressionNode> listNodes = new ArrayList<>();
// rawValues and dataType allow delaying literal node construction until toProtobuf()
private final List<Object> rawValues;
private final DataType dataType;

SingularOrListNode(ExpressionNode value, List<ExpressionNode> listNodes) {
this.value = value;
this.listNodes.addAll(listNodes);
this.rawValues = null;
this.dataType = null;
}

SingularOrListNode(ExpressionNode value, List<Object> rawValues, DataType dataType) {
this.value = value;
this.rawValues = new ArrayList<>(rawValues);
this.dataType = dataType;
}

@Override
public Expression toProtobuf() {
Expression.SingularOrList.Builder builder = Expression.SingularOrList.newBuilder();
builder.setValue(value.toProtobuf());
for (ExpressionNode expressionNode : listNodes) {
builder.addOptions(expressionNode.toProtobuf());
if (!listNodes.isEmpty()) {
for (ExpressionNode expressionNode : listNodes) {
builder.addOptions(expressionNode.toProtobuf());
}
} else if (rawValues != null) {
for (Object obj : rawValues) {
// construct a temporary LiteralNode and convert to protobuf to avoid keeping
// many LiteralNode objects in memory at once. Use per-value nullability.
LiteralNode literalNode =
(LiteralNode) ExpressionBuilder.makeLiteral(obj, dataType, obj == null);
builder.addOptions(literalNode.toProtobuf());
}

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.

Would it be better to create a separate class named like DeferredSingularOrListNode? Seems to be cleaner.

}
Expression.Builder expressionBuilder = Expression.newBuilder();
expressionBuilder.setSingularOrList(builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,18 @@ case class InSetTransformer(
original: InSet)
extends UnaryExpressionTransformer {
override def doTransform(context: SubstraitContext): ExpressionNode = {
InExpressionTransformer.toTransformer(
child.doTransform(context),
original.hset,
original.child.dataType)
val leftNode = child.doTransform(context)
val values = original.hset
val valueType = original.child.dataType

// Keep raw literal values and defer building LiteralNode objects until toProtobuf().
val rawValues = new java.util.ArrayList[Object](
values.toSeq
// Sort elements for deterministic behaviours.
.sortBy(Literal(_, valueType).toString())
.map(_.asInstanceOf[Object])
.asJava)
ExpressionBuilder.makeSingularOrListNode(leftNode, rawValues, valueType)
}
}

Expand Down