blob: bf3444a25a5649b989cac46ef4f72b1d6a7cd1dc [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.pinot.core.operator.transform.function;
import com.google.common.base.Preconditions;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.pinot.common.function.FunctionInfo;
import org.apache.pinot.common.function.FunctionInvoker;
import org.apache.pinot.common.function.FunctionUtils;
import org.apache.pinot.common.utils.PinotDataType;
import org.apache.pinot.core.operator.ColumnContext;
import org.apache.pinot.core.operator.blocks.ValueBlock;
import org.apache.pinot.core.operator.transform.TransformResultMetadata;
import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.roaringbitmap.IntConsumer;
import org.roaringbitmap.RoaringBitmap;
/**
* Wrapper transform function on the annotated scalar function.
*/
public class ScalarTransformFunctionWrapper extends BaseTransformFunction {
private final String _name;
private final FunctionInvoker _functionInvoker;
private final PinotDataType _resultType;
private final TransformResultMetadata _resultMetadata;
private Object[] _scalarArguments;
private int _numNonLiteralArguments;
private int[] _nonLiteralIndices;
private TransformFunction[] _nonLiteralFunctions;
private Object[][] _nonLiteralValues;
public ScalarTransformFunctionWrapper(FunctionInfo functionInfo) {
_name = functionInfo.getMethod().getName();
_functionInvoker = new FunctionInvoker(functionInfo);
Class<?>[] parameterClasses = _functionInvoker.getParameterClasses();
PinotDataType[] parameterTypes = _functionInvoker.getParameterTypes();
int numParameters = parameterClasses.length;
for (int i = 0; i < numParameters; i++) {
Preconditions.checkArgument(parameterTypes[i] != null, "Unsupported parameter class: %s for method: %s",
parameterClasses[i], functionInfo.getMethod());
}
Class<?> resultClass = _functionInvoker.getResultClass();
PinotDataType resultType = FunctionUtils.getParameterType(resultClass);
if (resultType != null) {
_resultType = resultType;
_resultMetadata =
new TransformResultMetadata(FunctionUtils.getDataType(resultClass), _resultType.isSingleValue(), false);
} else {
// Handle unrecognized result class with STRING
_resultType = PinotDataType.STRING;
_resultMetadata = new TransformResultMetadata(DataType.STRING, true, false);
}
}
@Override
public String getName() {
return _name;
}
@Override
public void init(List<TransformFunction> arguments, Map<String, ColumnContext> columnContextMap) {
int numArguments = arguments.size();
PinotDataType[] parameterTypes = _functionInvoker.getParameterTypes();
Preconditions.checkArgument(numArguments == parameterTypes.length,
"Wrong number of arguments for method: %s, expected: %s, actual: %s", _functionInvoker.getMethod(),
parameterTypes.length, numArguments);
_scalarArguments = new Object[numArguments];
_nonLiteralIndices = new int[numArguments];
_nonLiteralFunctions = new TransformFunction[numArguments];
for (int i = 0; i < numArguments; i++) {
TransformFunction transformFunction = arguments.get(i);
if (transformFunction instanceof LiteralTransformFunction) {
LiteralTransformFunction literalTransformFunction = (LiteralTransformFunction) transformFunction;
DataType dataType = literalTransformFunction.getResultMetadata().getDataType();
switch (dataType) {
case BOOLEAN:
_scalarArguments[i] =
parameterTypes[i].convert(literalTransformFunction.getBooleanLiteral(), PinotDataType.BOOLEAN);
break;
case INT:
_scalarArguments[i] =
parameterTypes[i].convert(literalTransformFunction.getIntLiteral(), PinotDataType.INTEGER);
break;
case LONG:
_scalarArguments[i] =
parameterTypes[i].convert(literalTransformFunction.getLongLiteral(), PinotDataType.LONG);
break;
case FLOAT:
_scalarArguments[i] =
parameterTypes[i].convert(literalTransformFunction.getFloatLiteral(), PinotDataType.FLOAT);
break;
case DOUBLE:
_scalarArguments[i] =
parameterTypes[i].convert(literalTransformFunction.getDoubleLiteral(), PinotDataType.DOUBLE);
break;
case BIG_DECIMAL:
_scalarArguments[i] =
parameterTypes[i].convert(literalTransformFunction.getBigDecimalLiteral(), PinotDataType.BIG_DECIMAL);
break;
case TIMESTAMP:
_scalarArguments[i] =
parameterTypes[i].convert(literalTransformFunction.getLongLiteral(), PinotDataType.TIMESTAMP);
break;
case STRING:
_scalarArguments[i] =
parameterTypes[i].convert(literalTransformFunction.getStringLiteral(), PinotDataType.STRING);
break;
case UNKNOWN:
_scalarArguments[i] = null;
break;
default:
throw new RuntimeException("Unsupported data type:" + dataType);
}
} else {
_nonLiteralIndices[_numNonLiteralArguments] = i;
_nonLiteralFunctions[_numNonLiteralArguments] = transformFunction;
_numNonLiteralArguments++;
}
}
_nonLiteralValues = new Object[_numNonLiteralArguments][];
}
@Override
public TransformResultMetadata getResultMetadata() {
return _resultMetadata;
}
@Override
public int[] transformToIntValuesSV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.INT) {
return super.transformToIntValuesSV(valueBlock);
}
int length = valueBlock.getNumDocs();
initIntValuesSV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_intValuesSV[i] = (int) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _intValuesSV;
}
@Override
public Pair<int[], RoaringBitmap> transformToIntValuesSVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.INT) {
return super.transformToIntValuesSVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initIntValuesSV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_intValuesSV[i] = (int) result;
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_intValuesSV, bitmap);
}
@Override
public long[] transformToLongValuesSV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.LONG) {
return super.transformToLongValuesSV(valueBlock);
}
int length = valueBlock.getNumDocs();
initLongValuesSV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_longValuesSV[i] = (long) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _longValuesSV;
}
@Override
public Pair<long[], RoaringBitmap> transformToLongValuesSVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.LONG) {
return super.transformToLongValuesSVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initLongValuesSV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_longValuesSV[i] = (long) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_longValuesSV, bitmap);
}
@Override
public float[] transformToFloatValuesSV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.FLOAT) {
return super.transformToFloatValuesSV(valueBlock);
}
int length = valueBlock.getNumDocs();
initFloatValuesSV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_floatValuesSV[i] = (float) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _floatValuesSV;
}
@Override
public Pair<float[], RoaringBitmap> transformToFloatValuesSVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.FLOAT) {
return super.transformToFloatValuesSVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initFloatValuesSV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_floatValuesSV[i] = (float) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_floatValuesSV, bitmap);
}
@Override
public double[] transformToDoubleValuesSV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.DOUBLE) {
return super.transformToDoubleValuesSV(valueBlock);
}
int length = valueBlock.getNumDocs();
initDoubleValuesSV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_doubleValuesSV[i] = (double) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _doubleValuesSV;
}
@Override
public Pair<double[], RoaringBitmap> transformToDoubleValuesSVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.DOUBLE) {
return super.transformToDoubleValuesSVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initDoubleValuesSV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_doubleValuesSV[i] = (double) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_doubleValuesSV, bitmap);
}
@Override
public BigDecimal[] transformToBigDecimalValuesSV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.BIG_DECIMAL) {
return super.transformToBigDecimalValuesSV(valueBlock);
}
int length = valueBlock.getNumDocs();
initBigDecimalValuesSV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_bigDecimalValuesSV[i] = (BigDecimal) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _bigDecimalValuesSV;
}
@Override
public Pair<BigDecimal[], RoaringBitmap> transformToBigDecimalValuesSVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.BIG_DECIMAL) {
return super.transformToBigDecimalValuesSVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initBigDecimalValuesSV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_bigDecimalValuesSV[i] = (BigDecimal) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_bigDecimalValuesSV, bitmap);
}
@Override
public String[] transformToStringValuesSV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.STRING) {
return super.transformToStringValuesSV(valueBlock);
}
int length = valueBlock.getNumDocs();
initStringValuesSV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
_stringValuesSV[i] =
_resultType == PinotDataType.STRING ? result.toString() : (String) _resultType.toInternal(result);
}
return _stringValuesSV;
}
@Override
public Pair<String[], RoaringBitmap> transformToStringValuesSVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.STRING) {
return super.transformToStringValuesSVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initStringValuesSV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_stringValuesSV[i] = (String) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_stringValuesSV, bitmap);
}
@Override
public byte[][] transformToBytesValuesSV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.BYTES) {
return super.transformToBytesValuesSV(valueBlock);
}
int length = valueBlock.getNumDocs();
initBytesValuesSV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_bytesValuesSV[i] = (byte[]) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _bytesValuesSV;
}
@Override
public Pair<byte[][], RoaringBitmap> transformToBytesValuesSVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.BYTES) {
return super.transformToBytesValuesSVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initBytesValuesSV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_bytesValuesSV[i] = (byte[]) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_bytesValuesSV, bitmap);
}
@Override
public int[][] transformToIntValuesMV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.INT) {
return super.transformToIntValuesMV(valueBlock);
}
int length = valueBlock.getNumDocs();
initIntValuesMV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_intValuesMV[i] = (int[]) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _intValuesMV;
}
@Override
public Pair<int[][], RoaringBitmap> transformToIntValuesMVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.INT) {
return super.transformToIntValuesMVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initIntValuesMV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_intValuesMV[i] = (int[]) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_intValuesMV, bitmap);
}
@Override
public long[][] transformToLongValuesMV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.LONG) {
return super.transformToLongValuesMV(valueBlock);
}
int length = valueBlock.getNumDocs();
initLongValuesMV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_longValuesMV[i] = (long[]) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _longValuesMV;
}
@Override
public Pair<long[][], RoaringBitmap> transformToLongValuesMVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.LONG) {
return super.transformToLongValuesMVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initLongValuesMV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_longValuesMV[i] = (long[]) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_longValuesMV, bitmap);
}
@Override
public float[][] transformToFloatValuesMV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.FLOAT) {
return super.transformToFloatValuesMV(valueBlock);
}
int length = valueBlock.getNumDocs();
initFloatValuesMV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_floatValuesMV[i] = (float[]) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _floatValuesMV;
}
@Override
public Pair<float[][], RoaringBitmap> transformToFloatValuesMVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.FLOAT) {
return super.transformToFloatValuesMVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initFloatValuesMV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_floatValuesMV[i] = (float[]) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_floatValuesMV, bitmap);
}
@Override
public double[][] transformToDoubleValuesMV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.DOUBLE) {
return super.transformToDoubleValuesMV(valueBlock);
}
int length = valueBlock.getNumDocs();
initDoubleValuesMV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_doubleValuesMV[i] = (double[]) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _doubleValuesMV;
}
@Override
public Pair<double[][], RoaringBitmap> transformToDoubleValuesMVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.DOUBLE) {
return super.transformToDoubleValuesMVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initDoubleValuesMV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_doubleValuesMV[i] = (double[]) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_doubleValuesMV, bitmap);
}
@Override
public String[][] transformToStringValuesMV(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.STRING) {
return super.transformToStringValuesMV(valueBlock);
}
int length = valueBlock.getNumDocs();
initStringValuesMV(length);
getNonLiteralValues(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
_stringValuesMV[i] = (String[]) _resultType.toInternal(_functionInvoker.invoke(_scalarArguments));
}
return _stringValuesMV;
}
@Override
public Pair<String[][], RoaringBitmap> transformToStringValuesMVWithNull(ValueBlock valueBlock) {
if (_resultMetadata.getDataType().getStoredType() != DataType.STRING) {
return super.transformToStringValuesMVWithNull(valueBlock);
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
initStringValuesMV(length);
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result != null) {
_stringValuesMV[i] = (String[]) _resultType.toInternal(result);
} else {
bitmap.add(i);
}
}
return ImmutablePair.of(_stringValuesMV, bitmap);
}
@Override
public RoaringBitmap getNullBitmap(ValueBlock valueBlock) {
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
getNonLiteralValuesWithNull(valueBlock);
for (int i = 0; i < length; i++) {
for (int j = 0; j < _numNonLiteralArguments; j++) {
_scalarArguments[_nonLiteralIndices[j]] = _nonLiteralValues[j][i];
}
Object result = _functionInvoker.invoke(_scalarArguments);
if (result == null) {
bitmap.add(i);
}
}
if (bitmap != null && bitmap.isEmpty()) {
return null;
}
return bitmap;
}
/**
* Helper method to fetch values for the non-literal transform functions based on the parameter types.
*/
private void getNonLiteralValues(ValueBlock valueBlock) {
PinotDataType[] parameterTypes = _functionInvoker.getParameterTypes();
for (int i = 0; i < _numNonLiteralArguments; i++) {
PinotDataType parameterType = parameterTypes[_nonLiteralIndices[i]];
TransformFunction transformFunction = _nonLiteralFunctions[i];
switch (parameterType) {
case INTEGER:
_nonLiteralValues[i] = ArrayUtils.toObject(transformFunction.transformToIntValuesSV(valueBlock));
break;
case LONG:
_nonLiteralValues[i] = ArrayUtils.toObject(transformFunction.transformToLongValuesSV(valueBlock));
break;
case FLOAT:
_nonLiteralValues[i] = ArrayUtils.toObject(transformFunction.transformToFloatValuesSV(valueBlock));
break;
case DOUBLE:
_nonLiteralValues[i] = ArrayUtils.toObject(transformFunction.transformToDoubleValuesSV(valueBlock));
break;
case BIG_DECIMAL:
_nonLiteralValues[i] = transformFunction.transformToBigDecimalValuesSV(valueBlock);
break;
case BOOLEAN: {
int[] intValues = transformFunction.transformToIntValuesSV(valueBlock);
int numValues = intValues.length;
Boolean[] booleanValues = new Boolean[numValues];
for (int j = 0; j < numValues; j++) {
booleanValues[j] = intValues[j] == 1;
}
_nonLiteralValues[i] = booleanValues;
break;
}
case TIMESTAMP: {
long[] longValues = transformFunction.transformToLongValuesSV(valueBlock);
int numValues = longValues.length;
Timestamp[] timestampValues = new Timestamp[numValues];
for (int j = 0; j < numValues; j++) {
timestampValues[j] = new Timestamp(longValues[j]);
}
_nonLiteralValues[i] = timestampValues;
break;
}
case STRING:
_nonLiteralValues[i] = transformFunction.transformToStringValuesSV(valueBlock);
break;
case BYTES:
_nonLiteralValues[i] = transformFunction.transformToBytesValuesSV(valueBlock);
break;
case PRIMITIVE_INT_ARRAY:
_nonLiteralValues[i] = transformFunction.transformToIntValuesMV(valueBlock);
break;
case PRIMITIVE_LONG_ARRAY:
_nonLiteralValues[i] = transformFunction.transformToLongValuesMV(valueBlock);
break;
case PRIMITIVE_FLOAT_ARRAY:
_nonLiteralValues[i] = transformFunction.transformToFloatValuesMV(valueBlock);
break;
case PRIMITIVE_DOUBLE_ARRAY:
_nonLiteralValues[i] = transformFunction.transformToDoubleValuesMV(valueBlock);
break;
case STRING_ARRAY:
_nonLiteralValues[i] = transformFunction.transformToStringValuesMV(valueBlock);
break;
default:
throw new IllegalStateException("Unsupported parameter type: " + parameterType);
}
}
}
/**
* Helper method to fetch values with null for the non-literal transform functions based on the parameter types.
*/
private void getNonLiteralValuesWithNull(ValueBlock valueBlock) {
PinotDataType[] parameterTypes = _functionInvoker.getParameterTypes();
for (int i = 0; i < _numNonLiteralArguments; i++) {
PinotDataType parameterType = parameterTypes[_nonLiteralIndices[i]];
TransformFunction transformFunction = _nonLiteralFunctions[i];
RoaringBitmap bitmap = null;
switch (parameterType) {
case INTEGER:
Pair<int[], RoaringBitmap> intResult = transformFunction.transformToIntValuesSVWithNull(valueBlock);
_nonLiteralValues[i] = ArrayUtils.toObject(intResult.getLeft());
bitmap = intResult.getRight();
break;
case LONG:
Pair<long[], RoaringBitmap> longResult = transformFunction.transformToLongValuesSVWithNull(valueBlock);
_nonLiteralValues[i] = ArrayUtils.toObject(longResult.getLeft());
bitmap = longResult.getRight();
break;
case FLOAT:
Pair<float[], RoaringBitmap> floatResult = transformFunction.transformToFloatValuesSVWithNull(valueBlock);
_nonLiteralValues[i] = ArrayUtils.toObject(floatResult.getLeft());
bitmap = floatResult.getRight();
break;
case DOUBLE:
Pair<double[], RoaringBitmap> doubleResult = transformFunction.transformToDoubleValuesSVWithNull(valueBlock);
_nonLiteralValues[i] = ArrayUtils.toObject(doubleResult.getLeft());
bitmap = doubleResult.getRight();
break;
case BIG_DECIMAL:
Pair<BigDecimal[], RoaringBitmap> bigDecimalResult =
transformFunction.transformToBigDecimalValuesSVWithNull(valueBlock);
_nonLiteralValues[i] = bigDecimalResult.getLeft();
bitmap = bigDecimalResult.getRight();
break;
case BOOLEAN: {
Pair<int[], RoaringBitmap> boolResult = transformFunction.transformToIntValuesSVWithNull(valueBlock);
int numValues = boolResult.getLeft().length;
Boolean[] booleanValues = new Boolean[numValues];
for (int j = 0; j < numValues; j++) {
booleanValues[j] = boolResult.getLeft()[j] == 1;
}
_nonLiteralValues[i] = booleanValues;
bitmap = boolResult.getRight();
break;
}
case TIMESTAMP: {
Pair<long[], RoaringBitmap> timeResult = transformFunction.transformToLongValuesSVWithNull(valueBlock);
int numValues = timeResult.getLeft().length;
Timestamp[] timestampValues = new Timestamp[numValues];
for (int j = 0; j < numValues; j++) {
timestampValues[j] = new Timestamp(timeResult.getLeft()[j]);
}
_nonLiteralValues[i] = timestampValues;
bitmap = timeResult.getRight();
break;
}
case STRING:
Pair<String[], RoaringBitmap> stringResult = transformFunction.transformToStringValuesSVWithNull(valueBlock);
_nonLiteralValues[i] = stringResult.getLeft();
bitmap = stringResult.getRight();
break;
case BYTES:
Pair<byte[][], RoaringBitmap> byteResult = transformFunction.transformToBytesValuesSVWithNull(valueBlock);
_nonLiteralValues[i] = byteResult.getLeft();
bitmap = byteResult.getRight();
break;
case PRIMITIVE_INT_ARRAY:
Pair<int[][], RoaringBitmap> intMVResult = transformFunction.transformToIntValuesMVWithNull(valueBlock);
_nonLiteralValues[i] = intMVResult.getLeft();
bitmap = intMVResult.getRight();
break;
case PRIMITIVE_LONG_ARRAY:
Pair<long[][], RoaringBitmap> longMVResult = transformFunction.transformToLongValuesMVWithNull(valueBlock);
_nonLiteralValues[i] = longMVResult.getLeft();
bitmap = longMVResult.getRight();
break;
case PRIMITIVE_FLOAT_ARRAY:
Pair<float[][], RoaringBitmap> floatMVResult = transformFunction.transformToFloatValuesMVWithNull(valueBlock);
_nonLiteralValues[i] = floatMVResult.getLeft();
bitmap = floatMVResult.getRight();
break;
case PRIMITIVE_DOUBLE_ARRAY:
Pair<double[][], RoaringBitmap> doubleMVResult =
transformFunction.transformToDoubleValuesMVWithNull(valueBlock);
_nonLiteralValues[i] = doubleMVResult.getLeft();
bitmap = doubleMVResult.getRight();
break;
case STRING_ARRAY:
Pair<String[][], RoaringBitmap> stringMVResult =
transformFunction.transformToStringValuesMVWithNull(valueBlock);
_nonLiteralValues[i] = stringMVResult.getLeft();
bitmap = stringMVResult.getRight();
break;
default:
throw new IllegalStateException("Unsupported parameter type: " + parameterType);
}
if (bitmap != null) {
int finalI = i;
bitmap.forEach((IntConsumer) (j) -> {
_nonLiteralValues[finalI][j] = null;
});
}
}
}
}