Skip to content

Commit 75bd163

Browse files
committed
Added coercion rules and placeholder UDF to handle VARBINARY
Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
1 parent c5ae56f commit 75bd163

5 files changed

Lines changed: 78 additions & 1 deletion

File tree

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ else if ((SqlTypeUtil.isApproximateNumeric(sourceType) || SqlTypeUtil.isDecimal(
183183
// NUMBER_TO_STRING uses java's built-in method to get the string representation of a number
184184
return makeCall(type, PPLBuiltinOperators.NUMBER_TO_STRING, List.of(exp));
185185
}
186+
// VARCHAR → VARBINARY for ip/binary fields. Emit BINARY(varchar) as a placeholder
187+
// RexCall the analytics backend adapter rewrites into a VARBINARY literal.
188+
else if (sqlType == SqlTypeName.VARBINARY
189+
&& sourceType.getSqlTypeName() == SqlTypeName.VARCHAR) {
190+
return makeCall(type, PPLBuiltinOperators.BINARY, List.of(exp));
191+
}
186192
return super.makeCast(pos, type, exp, matchNullability, safe, format);
187193
}
188194
}

core/src/main/java/org/opensearch/sql/calcite/utils/OpenSearchTypeFactory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ public static RelDataType convertExprTypeToRelDataType(ExprType fieldType, boole
174174
return TYPE_FACTORY.createUDT(ExprUDT.EXPR_TIME, nullable);
175175
case TIMESTAMP:
176176
return TYPE_FACTORY.createUDT(ExprUDT.EXPR_TIMESTAMP, nullable);
177+
case BINARY:
178+
return TYPE_FACTORY.createSqlType(SqlTypeName.VARBINARY, nullable);
177179
case ARRAY:
178180
return TYPE_FACTORY.createArrayType(
179181
TYPE_FACTORY.createSqlType(SqlTypeName.ANY, nullable), -1);
@@ -225,6 +227,7 @@ public static ExprType convertSqlTypeNameToExprType(SqlTypeName sqlTypeName) {
225227
case FLOAT, REAL -> FLOAT;
226228
case DOUBLE, DECIMAL -> DOUBLE; // TODO the decimal is only used for literal
227229
case CHAR, VARCHAR, MULTISET -> STRING; // call toString() for MULTISET
230+
case VARBINARY, BINARY -> BINARY;
228231
case BOOLEAN -> BOOLEAN;
229232
case DATE -> DATE;
230233
case TIME, TIME_TZ, TIME_WITH_LOCAL_TIME_ZONE -> TIME;

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,12 @@ public static boolean hasString(List<RexNode> rexNodeList) {
181181
(left, right) -> ExprCoreType.TIMESTAMP),
182182
CoercionRule.of(
183183
(left, right) -> hasString(left, right) && hasNumber(left, right),
184-
(left, right) -> ExprCoreType.DOUBLE));
184+
(left, right) -> ExprCoreType.DOUBLE),
185+
// (BINARY, STRING) → BINARY: ip/binary columns compared with string literals.
186+
// Triggers ExtendedRexBuilder.makeCast which wraps the literal with BINARY.
187+
CoercionRule.of(
188+
(left, right) -> hasString(left, right) && hasBinary(left, right),
189+
(left, right) -> ExprCoreType.BINARY));
185190

186191
private static boolean hasString(ExprType left, ExprType right) {
187192
return left == ExprCoreType.STRING || right == ExprCoreType.STRING;
@@ -195,6 +200,10 @@ private static boolean hasBoolean(ExprType left, ExprType right) {
195200
return left == ExprCoreType.BOOLEAN || right == ExprCoreType.BOOLEAN;
196201
}
197202

203+
private static boolean hasBinary(ExprType left, ExprType right) {
204+
return left == ExprCoreType.BINARY || right == ExprCoreType.BINARY;
205+
}
206+
198207
private record CoercionRule(
199208
BiPredicate<ExprType, ExprType> predicate, BinaryOperator<ExprType> resolver) {
200209

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
import org.opensearch.sql.expression.function.udf.condition.EarliestFunction;
8484
import org.opensearch.sql.expression.function.udf.condition.EnhancedCoalesceFunction;
8585
import org.opensearch.sql.expression.function.udf.condition.LatestFunction;
86+
import org.opensearch.sql.expression.function.udf.conversion.BinaryFunction;
8687
import org.opensearch.sql.expression.function.udf.datetime.AddSubDateFunction;
8788
import org.opensearch.sql.expression.function.udf.datetime.CurrentFunction;
8889
import org.opensearch.sql.expression.function.udf.datetime.DateAddSubFunction;
@@ -179,6 +180,9 @@ public class PPLBuiltinOperators extends ReflectiveSqlOperatorTable {
179180
public static final SqlOperator EARLIEST = new EarliestFunction().toUDF("EARLIEST");
180181
public static final SqlOperator LATEST = new LatestFunction().toUDF("LATEST");
181182

183+
// VARBINARY conversion (placeholder for ip/binary fields rewritten by analytics backend adapter)
184+
public static final SqlOperator BINARY = new BinaryFunction().toUDF("BINARY");
185+
182186
// Datetime function
183187
public static final SqlOperator TIMESTAMP = new TimestampFunction().toUDF("TIMESTAMP");
184188
public static final SqlOperator DATE =
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.expression.function.udf.conversion;
7+
8+
import static org.opensearch.sql.calcite.utils.OpenSearchTypeFactory.TYPE_FACTORY;
9+
10+
import java.util.List;
11+
import org.apache.calcite.adapter.enumerable.NotNullImplementor;
12+
import org.apache.calcite.adapter.enumerable.NullPolicy;
13+
import org.apache.calcite.adapter.enumerable.RexToLixTranslator;
14+
import org.apache.calcite.linq4j.tree.Expression;
15+
import org.apache.calcite.rex.RexCall;
16+
import org.apache.calcite.sql.type.FamilyOperandTypeChecker;
17+
import org.apache.calcite.sql.type.OperandTypes;
18+
import org.apache.calcite.sql.type.ReturnTypes;
19+
import org.apache.calcite.sql.type.SqlReturnTypeInference;
20+
import org.apache.calcite.sql.type.SqlTypeName;
21+
import org.opensearch.sql.expression.function.ImplementorUDF;
22+
import org.opensearch.sql.expression.function.UDFOperandMetadata;
23+
24+
/**
25+
* Placeholder UDF that wraps a VARCHAR literal cast to VARBINARY for ip/binary fields.
26+
*/
27+
public class BinaryFunction extends ImplementorUDF {
28+
29+
private static final SqlReturnTypeInference VARBINARY_FORCE_NULLABLE =
30+
ReturnTypes.explicit(
31+
TYPE_FACTORY.createTypeWithNullability(
32+
TYPE_FACTORY.createSqlType(SqlTypeName.VARBINARY), true));
33+
34+
public BinaryFunction() {
35+
super(new PassThroughImplementor(), NullPolicy.STRICT);
36+
}
37+
38+
@Override
39+
public SqlReturnTypeInference getReturnTypeInference() {
40+
return VARBINARY_FORCE_NULLABLE;
41+
}
42+
43+
@Override
44+
public UDFOperandMetadata getOperandMetadata() {
45+
return UDFOperandMetadata.wrap((FamilyOperandTypeChecker) OperandTypes.CHARACTER);
46+
}
47+
48+
public static class PassThroughImplementor implements NotNullImplementor {
49+
@Override
50+
public Expression implement(
51+
RexToLixTranslator translator, RexCall call, List<Expression> translatedOperands) {
52+
return translatedOperands.get(0);
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)