Skip to content
Merged
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 @@ -111,10 +111,9 @@ public void convertTypes(Object[] arguments) {
}

PinotDataType parameterType = _parameterTypes[i];
PinotDataType argumentType = FunctionUtils.getArgumentType(argumentClass);
Preconditions.checkArgument(parameterType != null && argumentType != null,
Preconditions.checkArgument(parameterType != null,
"Cannot convert value from class: %s to class: %s", argumentClass, parameterClass);
arguments[i] = parameterType.convert(argument, argumentType);
arguments[i] = parameterType.convert(argument, FunctionUtils.getArgumentType(argument));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.pinot.common.utils.DataSchema.ColumnDataType;
import org.apache.pinot.common.utils.PinotDataType;
import org.apache.pinot.spi.data.FieldSpec.DataType;


public class FunctionUtils {
Expand Down Expand Up @@ -57,65 +56,14 @@ private FunctionUtils() {
put(float[].class, PinotDataType.PRIMITIVE_FLOAT_ARRAY);
put(double[].class, PinotDataType.PRIMITIVE_DOUBLE_ARRAY);
put(BigDecimal[].class, PinotDataType.BIG_DECIMAL_ARRAY);
put(boolean[].class, PinotDataType.PRIMITIVE_BOOLEAN_ARRAY);
put(Timestamp[].class, PinotDataType.TIMESTAMP_ARRAY);
put(String[].class, PinotDataType.STRING_ARRAY);
put(byte[][].class, PinotDataType.BYTES_ARRAY);
put(Map.class, PinotDataType.MAP);
put(Object.class, PinotDataType.OBJECT);
}};

// Types allowed as the function argument (actual value passed into the function) for type conversion
private static final Map<Class<?>, PinotDataType> ARGUMENT_TYPE_MAP = new HashMap<>() {{
put(Byte.class, PinotDataType.BYTE);
put(Boolean.class, PinotDataType.BOOLEAN);
put(Character.class, PinotDataType.CHARACTER);
put(Short.class, PinotDataType.SHORT);
Comment thread
Jackie-Jiang marked this conversation as resolved.
put(Integer.class, PinotDataType.INTEGER);
put(Long.class, PinotDataType.LONG);
put(Float.class, PinotDataType.FLOAT);
put(Double.class, PinotDataType.DOUBLE);
put(BigDecimal.class, PinotDataType.BIG_DECIMAL);
put(Timestamp.class, PinotDataType.TIMESTAMP);
put(String.class, PinotDataType.STRING);
put(byte[].class, PinotDataType.BYTES);
put(int[].class, PinotDataType.PRIMITIVE_INT_ARRAY);
put(Integer[].class, PinotDataType.INTEGER_ARRAY);
put(long[].class, PinotDataType.PRIMITIVE_LONG_ARRAY);
put(Long[].class, PinotDataType.LONG_ARRAY);
put(float[].class, PinotDataType.PRIMITIVE_FLOAT_ARRAY);
put(Float[].class, PinotDataType.FLOAT_ARRAY);
put(double[].class, PinotDataType.PRIMITIVE_DOUBLE_ARRAY);
put(Double[].class, PinotDataType.DOUBLE_ARRAY);
put(BigDecimal[].class, PinotDataType.BIG_DECIMAL_ARRAY);
put(String[].class, PinotDataType.STRING_ARRAY);
put(byte[][].class, PinotDataType.BYTES_ARRAY);
put(Object.class, PinotDataType.OBJECT);
put(Object[].class, PinotDataType.OBJECT_ARRAY);
}};

private static final Map<Class<?>, DataType> DATA_TYPE_MAP = new HashMap<>() {{
put(int.class, DataType.INT);
put(Integer.class, DataType.INT);
put(long.class, DataType.LONG);
put(Long.class, DataType.LONG);
put(float.class, DataType.FLOAT);
put(Float.class, DataType.FLOAT);
put(double.class, DataType.DOUBLE);
put(Double.class, DataType.DOUBLE);
put(BigDecimal.class, DataType.BIG_DECIMAL);
put(boolean.class, DataType.BOOLEAN);
put(Boolean.class, DataType.BOOLEAN);
put(Timestamp.class, DataType.TIMESTAMP);
put(String.class, DataType.STRING);
put(byte[].class, DataType.BYTES);
put(int[].class, DataType.INT);
put(long[].class, DataType.LONG);
put(float[].class, DataType.FLOAT);
put(double[].class, DataType.DOUBLE);
put(BigDecimal[].class, DataType.BIG_DECIMAL);
put(String[].class, DataType.STRING);
put(byte[][].class, DataType.BYTES);
}};

private static final Map<Class<?>, ColumnDataType> COLUMN_DATA_TYPE_MAP = new HashMap<>() {{
put(int.class, ColumnDataType.INT);
put(Integer.class, ColumnDataType.INT);
Expand All @@ -136,6 +84,8 @@ private FunctionUtils() {
put(float[].class, ColumnDataType.FLOAT_ARRAY);
put(double[].class, ColumnDataType.DOUBLE_ARRAY);
put(BigDecimal[].class, ColumnDataType.BIG_DECIMAL_ARRAY);
put(boolean[].class, ColumnDataType.BOOLEAN_ARRAY);
put(Timestamp[].class, ColumnDataType.TIMESTAMP_ARRAY);
put(String[].class, ColumnDataType.STRING_ARRAY);
put(byte[][].class, ColumnDataType.BYTES_ARRAY);
put(Object.class, ColumnDataType.OBJECT);
Expand All @@ -149,26 +99,55 @@ public static PinotDataType getParameterType(Class<?> clazz) {
return PARAMETER_TYPE_MAP.get(clazz);
}

/**
* Returns the corresponding PinotDataType for the given argument class, or {@code null} if there is no one matching.
*/
@Nullable
public static PinotDataType getArgumentType(Class<?> clazz) {
if (Collection.class.isAssignableFrom(clazz)) {
return PinotDataType.COLLECTION;
/// Returns the corresponding [PinotDataType] for the given argument value (the actual value passed into
/// the function). Returns [PinotDataType#OBJECT] / [PinotDataType#OBJECT_ARRAY] for unrecognized types,
/// matching [PinotDataType#getSingleValueType]'s best-effort fallback. Subclasses of non-final types
/// (e.g. vendor `Timestamp` subclasses returned by JDBC drivers) are matched by their parent type.
///
/// Dispatch (single-value first since it's the dominant case for function arguments):
/// - Single values → delegated to [PinotDataType#getSingleValueType] (covers all scalar types
/// including `byte[]` → [PinotDataType#BYTES]).
/// - Reference arrays (`Object[]` and subtypes including `byte[][]`) → first non-null element is
/// sampled and [PinotDataType#getMultiValueType] is consulted. Empty / all-null reference arrays
/// fall back to [PinotDataType#OBJECT_ARRAY] since the element type is undeterminable.
/// - Primitive arrays (`int[]` / `long[]` / `float[]` / `double[]` / `boolean[]`) → handled here, since
/// they can't be element-sampled into a boxed type.
/// - [PinotDataType#COLLECTION] for any [Collection]; otherwise falls back to [PinotDataType#OBJECT].
public static PinotDataType getArgumentType(Object value) {
PinotDataType singleValueType = PinotDataType.getSingleValueType(value);
if (singleValueType != PinotDataType.OBJECT) {
return singleValueType;
}
Comment thread
Jackie-Jiang marked this conversation as resolved.
Comment thread
Jackie-Jiang marked this conversation as resolved.
if (Map.class.isAssignableFrom(clazz)) {
return PinotDataType.MAP;
if (value instanceof Object[]) {
Object[] array = (Object[]) value;
for (Object element : array) {
if (element == null) {
continue;
}
return PinotDataType.getMultiValueType(element);
}
// Empty or all-null reference array — element type undeterminable.
return PinotDataType.OBJECT_ARRAY;
}
Comment thread
Jackie-Jiang marked this conversation as resolved.
return ARGUMENT_TYPE_MAP.get(clazz);
}

/**
* Returns the corresponding DataType for the given class, or {@code null} if there is no one matching.
*/
@Nullable
public static DataType getDataType(Class<?> clazz) {
return DATA_TYPE_MAP.get(clazz);
if (value instanceof int[]) {
return PinotDataType.PRIMITIVE_INT_ARRAY;
}
if (value instanceof long[]) {
return PinotDataType.PRIMITIVE_LONG_ARRAY;
}
if (value instanceof float[]) {
return PinotDataType.PRIMITIVE_FLOAT_ARRAY;
}
if (value instanceof double[]) {
return PinotDataType.PRIMITIVE_DOUBLE_ARRAY;
}
if (value instanceof boolean[]) {
return PinotDataType.PRIMITIVE_BOOLEAN_ARRAY;
}
if (value instanceof Collection) {
return PinotDataType.COLLECTION;
}
return PinotDataType.OBJECT;
Comment thread
Jackie-Jiang marked this conversation as resolved.
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ private DataTypeConversionFunctions() {
public static Object cast(Object value, String targetTypeLiteral) {
Class<?> clazz = value.getClass();
// TODO: Support cast for MV
Preconditions.checkArgument(!clazz.isArray() | clazz == byte[].class, "%s must not be an array type", clazz);
PinotDataType sourceType = PinotDataType.getSingleValueType(clazz);
Preconditions.checkArgument(!clazz.isArray() || clazz == byte[].class, "%s must not be an array type", clazz);
PinotDataType sourceType = PinotDataType.getSingleValueType(value);
String transformed = targetTypeLiteral.toUpperCase();
PinotDataType targetDataType;
switch (transformed) {
Expand Down
Loading
Loading