Skip to content

Commit cb78ea7

Browse files
committed
Deprecate interface UDFOperandMetadata.wrapUDT
Signed-off-by: Yuanchun Shen <yuanchu@amazon.com>
1 parent e6b80e5 commit cb78ea7

8 files changed

Lines changed: 226 additions & 126 deletions

File tree

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,27 @@ public static boolean isCharacter(RelDataType type) {
153153
* @return true if the type is an IP address type, false otherwise
154154
*/
155155
public static boolean isIp(RelDataType type) {
156+
return isIp(type, false);
157+
}
158+
159+
/**
160+
* Checks whether a {@link RelDataType} represents an IP address type. If {@code acceptOther} is
161+
* set, {@link SqlTypeName#OTHER} is also accepted as an IP type.
162+
*
163+
* <p>{@link SqlTypeName#OTHER} is "borrowed" to represent IP type during validation because
164+
* <i>SqlTypeName.IP</i> does not exist
165+
*
166+
* @param type the type to check
167+
* @param acceptOther whether to accept OTHER as a valid IP type
168+
* @return true if the type is an IP address type, false otherwise
169+
*/
170+
public static boolean isIp(RelDataType type, boolean acceptOther) {
156171
if (isUserDefinedType(type)) {
157172
return ((AbstractExprRelDataType<?>) type).getUdt() == OpenSearchTypeFactory.ExprUDT.EXPR_IP;
158173
}
174+
if (acceptOther) {
175+
return type.getSqlTypeName() == SqlTypeName.OTHER;
176+
}
159177
return false;
160178
}
161179

@@ -175,4 +193,33 @@ public static boolean isBinary(RelDataType type) {
175193
}
176194
return SqlTypeName.BINARY_TYPES.contains(type.getSqlTypeName());
177195
}
196+
197+
/**
198+
* Checks whether a {@link RelDataType} represents a scalar type.
199+
*
200+
* <p>Scalar types include all primitive and atomic types such as numeric types (INTEGER, BIGINT,
201+
* FLOAT, DOUBLE, DECIMAL), string types (VARCHAR, CHAR), boolean, temporal types (DATE, TIME,
202+
* TIMESTAMP), and special scalar types (IP, BINARY, UUID).
203+
*
204+
* <p>This method returns false for composite types including:
205+
*
206+
* <ul>
207+
* <li>STRUCT types (structured records with named fields)
208+
* <li>MAP types (key-value pairs)
209+
* <li>ARRAY and MULTISET types (collections)
210+
* <li>ROW types (tuples)
211+
* </ul>
212+
*
213+
* @param type the type to check; may be null
214+
* @return true if the type is a scalar type, false if it is a composite type or null
215+
*/
216+
public static boolean isScalar(RelDataType type) {
217+
if (type == null) {
218+
return false;
219+
}
220+
return !type.isStruct()
221+
&& !SqlTypeUtil.isMap(type)
222+
&& !SqlTypeUtil.isCollection(type)
223+
&& !SqlTypeUtil.isRow(type);
224+
}
178225
}

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

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@
55

66
package org.opensearch.sql.calcite.utils;
77

8+
import java.util.Locale;
9+
import org.apache.calcite.sql.SqlCallBinding;
10+
import org.apache.calcite.sql.SqlOperandCountRange;
11+
import org.apache.calcite.sql.SqlOperator;
812
import org.apache.calcite.sql.type.CompositeOperandTypeChecker;
913
import org.apache.calcite.sql.type.FamilyOperandTypeChecker;
1014
import org.apache.calcite.sql.type.OperandTypes;
15+
import org.apache.calcite.sql.type.SqlOperandCountRanges;
1116
import org.apache.calcite.sql.type.SqlOperandTypeChecker;
1217
import org.apache.calcite.sql.type.SqlTypeFamily;
18+
import org.apache.calcite.sql.type.SqlTypeUtil;
1319
import org.opensearch.sql.expression.function.UDFOperandMetadata;
1420

1521
/**
@@ -21,48 +27,7 @@ public class PPLOperandTypes {
2127
// This class is not meant to be instantiated.
2228
private PPLOperandTypes() {}
2329

24-
/** List of all scalar type signatures (single parameter each) */
25-
private static final java.util.List<java.util.List<org.opensearch.sql.data.type.ExprType>>
26-
SCALAR_TYPES =
27-
java.util.List.of(
28-
// Numeric types
29-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.BYTE),
30-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.SHORT),
31-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.INTEGER),
32-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.LONG),
33-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.FLOAT),
34-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.DOUBLE),
35-
// String type
36-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.STRING),
37-
// Boolean type
38-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.BOOLEAN),
39-
// Temporal types
40-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.DATE),
41-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.TIME),
42-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.TIMESTAMP),
43-
// Special scalar types
44-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.IP),
45-
java.util.List.of(org.opensearch.sql.data.type.ExprCoreType.BINARY));
46-
47-
/** Helper method to create scalar types with optional integer parameter */
48-
private static java.util.List<java.util.List<org.opensearch.sql.data.type.ExprType>>
49-
createScalarWithOptionalInteger() {
50-
java.util.List<java.util.List<org.opensearch.sql.data.type.ExprType>> result =
51-
new java.util.ArrayList<>(SCALAR_TYPES);
52-
53-
// Add scalar + integer combinations
54-
SCALAR_TYPES.forEach(
55-
scalarType ->
56-
result.add(
57-
java.util.List.of(
58-
scalarType.get(0), org.opensearch.sql.data.type.ExprCoreType.INTEGER)));
59-
60-
return result;
61-
}
62-
6330
public static final UDFOperandMetadata NONE = UDFOperandMetadata.wrap(OperandTypes.family());
64-
public static final UDFOperandMetadata OPTIONAL_ANY =
65-
UDFOperandMetadata.wrap(OperandTypes.family(SqlTypeFamily.ANY).or(OperandTypes.family()));
6631

6732
public static final UDFOperandMetadata OPTIONAL_INTEGER =
6833
UDFOperandMetadata.wrap(OperandTypes.INTEGER.or(OperandTypes.family()));
@@ -78,8 +43,6 @@ private PPLOperandTypes() {}
7843
public static final UDFOperandMetadata ANY_OPTIONAL_INTEGER =
7944
UDFOperandMetadata.wrap(
8045
OperandTypes.ANY.or(OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.INTEGER)));
81-
public static final SqlOperandTypeChecker ANY_OPTIONAL_TIMESTAMP =
82-
OperandTypes.ANY.or(OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.TIMESTAMP));
8346
public static final UDFOperandMetadata INTEGER_INTEGER =
8447
UDFOperandMetadata.wrap(OperandTypes.INTEGER_INTEGER);
8548
public static final UDFOperandMetadata STRING_STRING =
@@ -137,7 +100,6 @@ private PPLOperandTypes() {}
137100

138101
public static final UDFOperandMetadata WIDTH_BUCKET_OPERAND =
139102
UDFOperandMetadata.wrap(
140-
141103
// 1. Numeric fields: bin age span=10
142104
OperandTypes.family(
143105
SqlTypeFamily.NUMERIC,
@@ -227,24 +189,13 @@ private PPLOperandTypes() {}
227189
UDFOperandMetadata.wrap(
228190
OperandTypes.DATETIME.or(
229191
OperandTypes.family(SqlTypeFamily.DATETIME, SqlTypeFamily.INTEGER)));
230-
public static final UDFOperandMetadata ANY_DATETIME_OR_STRING =
231-
UDFOperandMetadata.wrap(
232-
OperandTypes.family(SqlTypeFamily.ANY)
233-
.or(OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.DATETIME))
234-
.or(OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.STRING)));
235192

236193
public static final UDFOperandMetadata DATETIME_DATETIME =
237194
UDFOperandMetadata.wrap(OperandTypes.family(SqlTypeFamily.DATETIME, SqlTypeFamily.DATETIME));
238195
public static final UDFOperandMetadata DATETIME_OR_STRING_STRING =
239196
UDFOperandMetadata.wrap(
240197
OperandTypes.family(SqlTypeFamily.DATETIME, SqlTypeFamily.CHARACTER)
241198
.or(OperandTypes.CHARACTER_CHARACTER));
242-
public static final UDFOperandMetadata DATETIME_OR_STRING_DATETIME_OR_STRING =
243-
UDFOperandMetadata.wrap(
244-
OperandTypes.CHARACTER_CHARACTER
245-
.or(OperandTypes.family(SqlTypeFamily.DATETIME, SqlTypeFamily.DATETIME))
246-
.or(OperandTypes.family(SqlTypeFamily.DATETIME, SqlTypeFamily.CHARACTER))
247-
.or(OperandTypes.family(SqlTypeFamily.CHARACTER, SqlTypeFamily.DATETIME)));
248199
public static final UDFOperandMetadata STRING_TIMESTAMP =
249200
UDFOperandMetadata.wrap(
250201
OperandTypes.family(SqlTypeFamily.CHARACTER, SqlTypeFamily.TIMESTAMP));
@@ -288,12 +239,56 @@ private PPLOperandTypes() {}
288239
* booleans, datetime types, and special scalar types like IP and BINARY. Excludes complex types
289240
* like arrays, structs, and maps.
290241
*/
291-
public static final UDFOperandMetadata ANY_SCALAR = UDFOperandMetadata.wrapUDT(SCALAR_TYPES);
242+
public static final UDFOperandMetadata SCALAR =
243+
UDFOperandMetadata.wrap(
244+
new SqlOperandTypeChecker() {
245+
@Override
246+
public boolean checkOperandTypes(SqlCallBinding callBinding, boolean throwOnFailure) {
247+
if (!getOperandCountRange().isValidCount(callBinding.getOperandCount())) {
248+
return false;
249+
}
250+
return OpenSearchTypeUtil.isScalar(callBinding.getOperandType(0));
251+
}
252+
253+
@Override
254+
public SqlOperandCountRange getOperandCountRange() {
255+
return SqlOperandCountRanges.of(1);
256+
}
257+
258+
@Override
259+
public String getAllowedSignatures(SqlOperator op, String opName) {
260+
return String.format(Locale.ROOT, "%s(<SCALAR>)", opName);
261+
}
262+
});
292263

293264
/**
294265
* Operand type checker that accepts any scalar type with an optional integer argument. This is
295266
* used for aggregation functions that take a field and an optional limit/size parameter.
296267
*/
297-
public static final UDFOperandMetadata ANY_SCALAR_OPTIONAL_INTEGER =
298-
UDFOperandMetadata.wrapUDT(createScalarWithOptionalInteger());
268+
public static final UDFOperandMetadata SCALAR_OPTIONAL_INTEGER =
269+
UDFOperandMetadata.wrap(
270+
new SqlOperandTypeChecker() {
271+
@Override
272+
public boolean checkOperandTypes(SqlCallBinding callBinding, boolean throwOnFailure) {
273+
if (!getOperandCountRange().isValidCount(callBinding.getOperandCount())) {
274+
return false;
275+
}
276+
boolean valid = OpenSearchTypeUtil.isScalar(callBinding.getOperandType(0));
277+
if (callBinding.getOperandCount() == 2) {
278+
valid = valid && SqlTypeUtil.isIntType(callBinding.getOperandType(1));
279+
}
280+
return valid;
281+
}
282+
283+
@Override
284+
public SqlOperandCountRange getOperandCountRange() {
285+
return SqlOperandCountRanges.between(1, 2);
286+
}
287+
288+
@Override
289+
public String getAllowedSignatures(SqlOperator op, String opName) {
290+
return String.format(
291+
Locale.ROOT, "%s(<SCALAR>), %s(<SCALAR>, <INTEGER>)", opName, opName);
292+
}
293+
});
299294
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,13 @@ public class PPLBuiltinOperators extends ReflectiveSqlOperatorTable {
481481
OperandTypes.VARIADIC)); // operand types of patterns are very flexible
482482
public static final SqlAggFunction LIST =
483483
createUserDefinedAggFunction(
484-
ListAggFunction.class, "LIST", PPLReturnTypes.STRING_ARRAY, PPLOperandTypes.ANY_SCALAR);
484+
ListAggFunction.class, "LIST", PPLReturnTypes.STRING_ARRAY, PPLOperandTypes.SCALAR);
485485
public static final SqlAggFunction VALUES =
486486
createUserDefinedAggFunction(
487487
ValuesAggFunction.class,
488488
"VALUES",
489489
PPLReturnTypes.STRING_ARRAY,
490-
PPLOperandTypes.ANY_SCALAR_OPTIONAL_INTEGER);
490+
PPLOperandTypes.SCALAR_OPTIONAL_INTEGER);
491491

492492
public static final SqlFunction ATAN =
493493
new SqlFunction(

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

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,15 @@
55

66
package org.opensearch.sql.expression.function;
77

8-
import java.util.Collections;
98
import java.util.List;
109
import org.apache.calcite.rel.type.RelDataType;
1110
import org.apache.calcite.rel.type.RelDataTypeFactory;
1211
import org.apache.calcite.sql.SqlCallBinding;
1312
import org.apache.calcite.sql.SqlOperandCountRange;
1413
import org.apache.calcite.sql.SqlOperator;
15-
import org.apache.calcite.sql.type.SqlOperandCountRanges;
1614
import org.apache.calcite.sql.type.SqlOperandMetadata;
1715
import org.apache.calcite.sql.type.SqlOperandTypeChecker;
1816
import org.apache.calcite.sql.validate.SqlUserDefinedFunction;
19-
import org.opensearch.sql.data.type.ExprType;
2017

2118
/**
2219
* This class is created for the compatibility with {@link SqlUserDefinedFunction} constructors when
@@ -35,14 +32,16 @@ public SqlOperandTypeChecker getInnerTypeChecker() {
3532

3633
@Override
3734
public List<RelDataType> paramTypes(RelDataTypeFactory typeFactory) {
38-
// This function is not used in the current context, so we return an empty list.
39-
return Collections.emptyList();
35+
// This function is not used in the current context
36+
throw new UnsupportedOperationException(
37+
"paramTypes of UDFOperandMetadata is not implemented and should not be called");
4038
}
4139

4240
@Override
4341
public List<String> paramNames() {
44-
// This function is not used in the current context, so we return an empty list.
45-
return Collections.emptyList();
42+
// This function is not used in the current context
43+
throw new UnsupportedOperationException(
44+
"paramNames of UDFOperandMetadata is not implemented and should not be called");
4645
}
4746

4847
@Override
@@ -61,49 +60,4 @@ public String getAllowedSignatures(SqlOperator op, String opName) {
6160
}
6261
};
6362
}
64-
65-
static UDFOperandMetadata wrapUDT(List<List<ExprType>> allowSignatures) {
66-
return new UDTOperandMetadata(allowSignatures);
67-
}
68-
69-
record UDTOperandMetadata(List<List<ExprType>> allowedParamTypes) implements UDFOperandMetadata {
70-
@Override
71-
public SqlOperandTypeChecker getInnerTypeChecker() {
72-
return this;
73-
}
74-
75-
@Override
76-
public List<RelDataType> paramTypes(RelDataTypeFactory typeFactory) {
77-
return List.of();
78-
}
79-
80-
@Override
81-
public List<String> paramNames() {
82-
return List.of();
83-
}
84-
85-
@Override
86-
public boolean checkOperandTypes(SqlCallBinding callBinding, boolean throwOnFailure) {
87-
return false;
88-
}
89-
90-
@Override
91-
public SqlOperandCountRange getOperandCountRange() {
92-
if (allowedParamTypes == null || allowedParamTypes.isEmpty()) {
93-
return SqlOperandCountRanges.between(0, 0);
94-
}
95-
int max = Integer.MIN_VALUE;
96-
int min = Integer.MAX_VALUE;
97-
for (List<ExprType> paramTypes : allowedParamTypes) {
98-
max = Math.max(max, paramTypes.size());
99-
min = Math.min(min, paramTypes.size());
100-
}
101-
return SqlOperandCountRanges.between(min, max);
102-
}
103-
104-
@Override
105-
public String getAllowedSignatures(SqlOperator op, String opName) {
106-
return "";
107-
}
108-
}
10963
}

core/src/main/java/org/opensearch/sql/expression/function/udf/ip/CidrMatchFunction.java

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,20 @@
1111
import org.apache.calcite.adapter.enumerable.RexToLixTranslator;
1212
import org.apache.calcite.linq4j.tree.Expression;
1313
import org.apache.calcite.linq4j.tree.Expressions;
14+
import org.apache.calcite.rel.type.RelDataType;
1415
import org.apache.calcite.rex.RexCall;
16+
import org.apache.calcite.sql.SqlCallBinding;
17+
import org.apache.calcite.sql.SqlOperandCountRange;
18+
import org.apache.calcite.sql.SqlOperator;
19+
import org.apache.calcite.sql.type.OperandTypes;
1520
import org.apache.calcite.sql.type.ReturnTypes;
21+
import org.apache.calcite.sql.type.SqlOperandCountRanges;
22+
import org.apache.calcite.sql.type.SqlOperandTypeChecker;
1623
import org.apache.calcite.sql.type.SqlReturnTypeInference;
24+
import org.opensearch.sql.calcite.utils.OpenSearchTypeUtil;
1725
import org.opensearch.sql.data.model.ExprIpValue;
1826
import org.opensearch.sql.data.model.ExprValue;
1927
import org.opensearch.sql.data.model.ExprValueUtils;
20-
import org.opensearch.sql.data.type.ExprCoreType;
2128
import org.opensearch.sql.expression.function.ImplementorUDF;
2229
import org.opensearch.sql.expression.function.UDFOperandMetadata;
2330
import org.opensearch.sql.expression.ip.IPFunctions;
@@ -47,10 +54,29 @@ public UDFOperandMetadata getOperandMetadata() {
4754
// EXPR_IP is mapped to SqlTypeFamily.OTHER in
4855
// UserDefinedFunctionUtils.convertRelDataTypeToSqlTypeName
4956
// We use a specific type checker to serve
50-
return UDFOperandMetadata.wrapUDT(
51-
List.of(
52-
List.of(ExprCoreType.IP, ExprCoreType.STRING),
53-
List.of(ExprCoreType.STRING, ExprCoreType.STRING)));
57+
return UDFOperandMetadata.wrap(
58+
OperandTypes.CHARACTER_CHARACTER.or(
59+
new SqlOperandTypeChecker() {
60+
@Override
61+
public boolean checkOperandTypes(SqlCallBinding callBinding, boolean throwOnFailure) {
62+
if (!getOperandCountRange().isValidCount(callBinding.getOperandCount())) {
63+
return false;
64+
}
65+
List<RelDataType> types = callBinding.collectOperandTypes();
66+
return OpenSearchTypeUtil.isIp(types.get(0), true)
67+
&& OpenSearchTypeUtil.isCharacter(types.get(1));
68+
}
69+
70+
@Override
71+
public SqlOperandCountRange getOperandCountRange() {
72+
return SqlOperandCountRanges.of(2);
73+
}
74+
75+
@Override
76+
public String getAllowedSignatures(SqlOperator op, String opName) {
77+
return "CIDRMATCH(<IP>, <STRING>)";
78+
}
79+
}));
5480
}
5581

5682
public static class CidrMatchImplementor implements NotNullImplementor {

0 commit comments

Comments
 (0)