blob: ec9f0101017dda67e5bc7e30a17c0d71111f6a70 [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.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.pinot.common.request.context.LiteralContext;
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.segment.spi.index.reader.Dictionary;
import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.apache.pinot.spi.utils.BooleanUtils;
import org.apache.pinot.spi.utils.BytesUtils;
import org.roaringbitmap.RoaringBitmap;
/**
* The <code>LiteralTransformFunction</code> class is a special transform function which is a wrapper on top of a
* LITERAL. The data type is inferred from the literal string.
*/
public class LiteralTransformFunction implements TransformFunction {
public static final String FUNCTION_NAME = "literal";
private final Object _literal;
private final DataType _dataType;
private final int _intLiteral;
private final long _longLiteral;
private final float _floatLiteral;
private final double _doubleLiteral;
private final BigDecimal _bigDecimalLiteral;
// literals may be shared but values are intentionally not volatile as assignment races are benign
private int[] _intResult;
private long[] _longResult;
private float[] _floatResult;
private double[] _doubleResult;
private BigDecimal[] _bigDecimalResult;
private String[] _stringResult;
private byte[][] _bytesResult;
public LiteralTransformFunction(LiteralContext literalContext) {
Preconditions.checkNotNull(literalContext);
_literal = literalContext.getValue();
_dataType = literalContext.getType();
_bigDecimalLiteral = literalContext.getBigDecimalValue();
_intLiteral = _bigDecimalLiteral.intValue();
_longLiteral = _bigDecimalLiteral.longValue();
_floatLiteral = _bigDecimalLiteral.floatValue();
_doubleLiteral = _bigDecimalLiteral.doubleValue();
}
public boolean getBooleanLiteral() {
return BooleanUtils.toBoolean(_literal);
}
public int getIntLiteral() {
return _intLiteral;
}
public long getLongLiteral() {
return _longLiteral;
}
public float getFloatLiteral() {
return _floatLiteral;
}
public double getDoubleLiteral() {
return _doubleLiteral;
}
public BigDecimal getBigDecimalLiteral() {
return _bigDecimalLiteral;
}
public String getStringLiteral() {
return String.valueOf(_literal);
}
@Override
public String getName() {
return FUNCTION_NAME;
}
@Override
public void init(List<TransformFunction> arguments, Map<String, ColumnContext> columnContextMap) {
}
@Override
public TransformResultMetadata getResultMetadata() {
return new TransformResultMetadata(_dataType, true, false);
}
@Override
public Dictionary getDictionary() {
return null;
}
@Override
public int[] transformToDictIdsSV(ValueBlock valueBlock) {
throw new UnsupportedOperationException();
}
@Override
public int[][] transformToDictIdsMV(ValueBlock valueBlock) {
throw new UnsupportedOperationException();
}
@Override
public int[] transformToIntValuesSV(ValueBlock valueBlock) {
int numDocs = valueBlock.getNumDocs();
int[] intResult = _intResult;
if (intResult == null || intResult.length < numDocs) {
intResult = new int[numDocs];
if (_dataType != DataType.BOOLEAN) {
if (_intLiteral != 0) {
Arrays.fill(intResult, _intLiteral);
}
} else {
Arrays.fill(intResult, _intLiteral);
}
_intResult = intResult;
}
return intResult;
}
@Override
public long[] transformToLongValuesSV(ValueBlock valueBlock) {
int numDocs = valueBlock.getNumDocs();
long[] longResult = _longResult;
if (longResult == null || longResult.length < numDocs) {
longResult = new long[numDocs];
if (_dataType != DataType.TIMESTAMP) {
if (_longLiteral != 0) {
Arrays.fill(longResult, _longLiteral);
}
} else {
Arrays.fill(longResult, Timestamp.valueOf(getStringLiteral()).getTime());
}
_longResult = longResult;
}
return longResult;
}
@Override
public float[] transformToFloatValuesSV(ValueBlock valueBlock) {
int numDocs = valueBlock.getNumDocs();
float[] floatResult = _floatResult;
if (floatResult == null || floatResult.length < numDocs) {
floatResult = new float[numDocs];
if (_floatLiteral != 0F) {
Arrays.fill(floatResult, _floatLiteral);
}
_floatResult = floatResult;
}
return floatResult;
}
@Override
public double[] transformToDoubleValuesSV(ValueBlock valueBlock) {
int numDocs = valueBlock.getNumDocs();
double[] doubleResult = _doubleResult;
if (doubleResult == null || doubleResult.length < numDocs) {
doubleResult = new double[numDocs];
if (_doubleLiteral != 0) {
Arrays.fill(doubleResult, _doubleLiteral);
}
_doubleResult = doubleResult;
}
return doubleResult;
}
@Override
public BigDecimal[] transformToBigDecimalValuesSV(ValueBlock valueBlock) {
int numDocs = valueBlock.getNumDocs();
BigDecimal[] bigDecimalResult = _bigDecimalResult;
if (bigDecimalResult == null || bigDecimalResult.length < numDocs) {
bigDecimalResult = new BigDecimal[numDocs];
Arrays.fill(bigDecimalResult, _bigDecimalLiteral);
_bigDecimalResult = bigDecimalResult;
}
return bigDecimalResult;
}
@Override
public String[] transformToStringValuesSV(ValueBlock valueBlock) {
int numDocs = valueBlock.getNumDocs();
String[] stringResult = _stringResult;
if (stringResult == null || stringResult.length < numDocs) {
stringResult = new String[numDocs];
Arrays.fill(stringResult, getStringLiteral());
_stringResult = stringResult;
}
return stringResult;
}
@Override
public byte[][] transformToBytesValuesSV(ValueBlock valueBlock) {
int numDocs = valueBlock.getNumDocs();
byte[][] bytesResult = _bytesResult;
if (bytesResult == null || bytesResult.length < numDocs) {
bytesResult = new byte[numDocs][];
// TODO: Handle null literal
Arrays.fill(bytesResult, BytesUtils.toBytes(getStringLiteral()));
_bytesResult = bytesResult;
}
return bytesResult;
}
@Override
public int[][] transformToIntValuesMV(ValueBlock valueBlock) {
throw new UnsupportedOperationException();
}
@Override
public long[][] transformToLongValuesMV(ValueBlock valueBlock) {
throw new UnsupportedOperationException();
}
@Override
public float[][] transformToFloatValuesMV(ValueBlock valueBlock) {
throw new UnsupportedOperationException();
}
@Override
public double[][] transformToDoubleValuesMV(ValueBlock valueBlock) {
throw new UnsupportedOperationException();
}
@Override
public String[][] transformToStringValuesMV(ValueBlock valueBlock) {
throw new UnsupportedOperationException();
}
@Override
public byte[][][] transformToBytesValuesMV(ValueBlock valueBlock) {
throw new UnsupportedOperationException();
}
@Override
public RoaringBitmap getNullBitmap(ValueBlock valueBlock) {
// Treat all unknown type values as null regardless of the value.
if (_dataType != DataType.UNKNOWN) {
return null;
}
int length = valueBlock.getNumDocs();
RoaringBitmap bitmap = new RoaringBitmap();
bitmap.add(0L, length);
return bitmap;
}
}