Skip to content

Commit 657cc6a

Browse files
committed
Allow binary arithmetic operation between string and numerics
Signed-off-by: Yuanchun Shen <yuanchu@amazon.com>
1 parent f5fda25 commit 657cc6a

4 files changed

Lines changed: 35 additions & 382 deletions

File tree

core/src/main/java/org/opensearch/sql/calcite/ExtendedRexBuilder.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@
1414
import org.apache.calcite.rex.RexBuilder;
1515
import org.apache.calcite.rex.RexLiteral;
1616
import org.apache.calcite.rex.RexNode;
17+
import org.apache.calcite.sql.SqlCallBinding;
1718
import org.apache.calcite.sql.SqlIntervalQualifier;
19+
import org.apache.calcite.sql.SqlKind;
20+
import org.apache.calcite.sql.SqlOperator;
1821
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
1922
import org.apache.calcite.sql.parser.SqlParserPos;
2023
import org.apache.calcite.sql.type.SqlTypeName;
2124
import org.apache.calcite.sql.type.SqlTypeUtil;
25+
import org.apache.calcite.sql.validate.implicit.TypeCoercionImpl;
2226
import org.opensearch.sql.ast.expression.SpanUnit;
2327
import org.opensearch.sql.calcite.type.AbstractExprRelDataType;
2428
import org.opensearch.sql.calcite.utils.OpenSearchTypeFactory;
@@ -185,4 +189,34 @@ else if ((SqlTypeUtil.isApproximateNumeric(sourceType) || SqlTypeUtil.isDecimal(
185189
}
186190
return super.makeCast(pos, type, exp, matchNullability, safe, format);
187191
}
192+
193+
/**
194+
* Derives the return type of call to an operator.
195+
*
196+
* <p>In Calcite, coercion between STRING and NUMERIC operands takes place during converting SQL
197+
* to RelNode. However, as we are building logical plans directly, the coercion is not yet
198+
* implemented at this point. Hence, we duplicate {@link
199+
* TypeCoercionImpl#binaryArithmeticWithStrings} here to infer the correct type, enabling
200+
* operations like {@code "5" / 10}. The actual coercion will be inserted later when performing
201+
* validation on SqlNode.
202+
*
203+
* @see TypeCoercionImpl#binaryArithmeticCoercion(SqlCallBinding)
204+
* @param op the operator being called
205+
* @param exprs actual operands
206+
* @return derived type
207+
*/
208+
@Override
209+
public RelDataType deriveReturnType(SqlOperator op, List<? extends RexNode> exprs) {
210+
if (op.getKind().belongsTo(SqlKind.BINARY_ARITHMETIC) && exprs.size() == 2) {
211+
final RelDataType type1 = exprs.get(0).getType();
212+
final RelDataType type2 = exprs.get(1).getType();
213+
if (OpenSearchTypeFactory.isNumericType(type1) && OpenSearchTypeFactory.isCharacter(type2)) {
214+
return type1;
215+
} else if (OpenSearchTypeFactory.isCharacter(type1)
216+
&& OpenSearchTypeFactory.isNumericType(type2)) {
217+
return type2;
218+
}
219+
}
220+
return super.deriveReturnType(op, exprs);
221+
}
188222
}

core/src/main/java/org/opensearch/sql/expression/function/CoercionUtils.java

Lines changed: 0 additions & 274 deletions
This file was deleted.

core/src/main/java/org/opensearch/sql/expression/function/PPLFuncImpTable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ void populate() {
925925
FunctionImp add =
926926
(builder, args) -> {
927927
SqlOperator op =
928-
(Stream.of(args).map(RexNode::getType).anyMatch(OpenSearchTypeFactory::isCharacter))
928+
(Stream.of(args).map(RexNode::getType).allMatch(OpenSearchTypeFactory::isCharacter))
929929
? SqlStdOperatorTable.CONCAT
930930
: SqlStdOperatorTable.PLUS;
931931
return builder.makeCall(op, args);

0 commit comments

Comments
 (0)