Skip to content

Commit 867697c

Browse files
authored
fix(isthmus): use explicit return type for scalar function expressions (#355)
1 parent ae70dc4 commit 867697c

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

isthmus/src/main/java/io/substrait/isthmus/expression/ExpressionRexConverter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,8 @@ public RexNode visit(Expression.ScalarFunctionInvocation expr) throws RuntimeExc
321321
.mapToObj(i -> eArgs.get(i).accept(expr.declaration(), i, this))
322322
.collect(java.util.stream.Collectors.toList());
323323

324-
return rexBuilder.makeCall(operator, args);
324+
RelDataType returnType = typeConverter.toCalcite(typeFactory, expr.outputType());
325+
return rexBuilder.makeCall(returnType, operator, args);
325326
}
326327

327328
private String callConversionFailureMessage(

isthmus/src/test/java/io/substrait/isthmus/SubstraitExpressionConverterTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
import io.substrait.dsl.SubstraitBuilder;
88
import io.substrait.expression.Expression;
9+
import io.substrait.expression.Expression.ScalarFunctionInvocation;
10+
import io.substrait.expression.ExpressionCreator;
11+
import io.substrait.extension.DefaultExtensionCatalog;
912
import io.substrait.isthmus.expression.ExpressionRexConverter;
1013
import io.substrait.relation.Project;
1114
import io.substrait.relation.Rel;
@@ -159,6 +162,32 @@ Rel createSubQueryRel() {
159162
commonTable));
160163
}
161164

165+
/**
166+
* Test that checks that we use the explicit return type provided in the Substrait plan instead of
167+
* relying on the return type inference by Calcite. Would throw an
168+
* java.lang.ArrayIndexOutOfBoundsException otherwise.
169+
*/
170+
@Test
171+
public void subtractDateTimeExplicitReturnTypeTest() {
172+
ScalarFunctionInvocation expr =
173+
b.scalarFn(
174+
DefaultExtensionCatalog.FUNCTIONS_DATETIME,
175+
"subtract:date_iday",
176+
TypeCreator.REQUIRED.DATE,
177+
ExpressionCreator.date(false, 10561),
178+
ExpressionCreator.intervalDay(false, 120, 0, 0, 6));
179+
180+
Project query = b.project(input -> List.of(expr), b.emptyScan());
181+
182+
SubstraitToCalcite substraitToCalcite = new SubstraitToCalcite(extensions, typeFactory);
183+
RelNode calciteRel = substraitToCalcite.convert(query);
184+
RexNode calciteExpr = ((LogicalProject) calciteRel).getProjects().get(0);
185+
186+
assertEquals(
187+
TypeConverter.DEFAULT.toCalcite(typeFactory, TypeCreator.REQUIRED.DATE),
188+
calciteExpr.getType());
189+
}
190+
162191
void assertTypeMatch(RelDataType actual, Type expected) {
163192
Type type = TypeConverter.DEFAULT.toSubstrait(actual);
164193
assertEquals(expected, type);

0 commit comments

Comments
 (0)