in asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractNumericArithmeticEval.java [87:570]
protected abstract boolean evaluateDouble(double lhs, double rhs, AMutableDouble result)
throws HyracksDataException;
/**
* abstract method for arithmetic operation between a time instance (date/time/datetime)
* and a duration (duration/year-month-duration/day-time-duration)
*
* @param chronon first operand
* @param yearMonth year-month component of the second operand
* @param dayTime day-time component of the second operand
* @param result result holder
* @param ctx evaluator context
* @return {@code false} if the result is {@code NULL}, otherwise {@code true}
*/
protected abstract boolean evaluateTimeDurationArithmetic(long chronon, int yearMonth, long dayTime,
boolean isTimeOnly, AMutableInt64 result, IEvaluatorContext ctx) throws HyracksDataException;
/**
* abstract method for arithmetic operation between two time instances (date/time/datetime)
*
* @param chronon0 first operand
* @param chronon1 second operand
* @param result result holder
* @param ctx evaluator context
* @return {@code false} if the result is {@code NULL}, otherwise {@code true}
*/
protected abstract boolean evaluateTimeInstanceArithmetic(long chronon0, long chronon1, AMutableInt64 result,
IEvaluatorContext ctx) throws HyracksDataException;
@Override
public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) {
return new IScalarEvaluatorFactory() {
private static final long serialVersionUID = 1L;
@Override
public IScalarEvaluator createScalarEvaluator(IEvaluatorContext ctx) throws HyracksDataException {
return new IScalarEvaluator() {
private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
private final DataOutput out = resultStorage.getDataOutput();
private final IPointable argPtr0 = new VoidPointable();
private final IPointable argPtr1 = new VoidPointable();
private final IScalarEvaluator evalLeft = args[0].createScalarEvaluator(ctx);
private final IScalarEvaluator evalRight = args[1].createScalarEvaluator(ctx);
private final double[] operandsFloating = new double[args.length];
private final long[] operandsInteger = new long[args.length];
private final AMutableFloat aFloat = new AMutableFloat(0);
private final AMutableDouble aDouble = new AMutableDouble(0);
private final AMutableInt64 aInt64 = new AMutableInt64(0);
private final AMutableInt32 aInt32 = new AMutableInt32(0);
private final AMutableInt16 aInt16 = new AMutableInt16((short) 0);
private final AMutableInt8 aInt8 = new AMutableInt8((byte) 0);
private final AMutableDuration aDuration = new AMutableDuration(0, 0);
private final AMutableDate aDate = new AMutableDate(0);
private final AMutableTime aTime = new AMutableTime(0);
private final AMutableDateTime aDatetime = new AMutableDateTime(0);
private final FunctionIdentifier funID = getIdentifier();
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer int8Serde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT8);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer int16Serde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT16);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer int32Serde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT32);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer int64Serde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT64);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer floatSerde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AFLOAT);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer doubleSerde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ADOUBLE);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer dateSerde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ADATE);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer timeSerde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ATIME);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer dateTimeSerde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ADATETIME);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer durationSerde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ADURATION);
@SuppressWarnings("rawtypes")
private final ISerializerDeserializer nullSerde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ANULL);
private final byte[] EXP_TYPES = new byte[] { ATypeTag.SERIALIZED_INT8_TYPE_TAG,
ATypeTag.SERIALIZED_INT16_TYPE_TAG, ATypeTag.SERIALIZED_INT32_TYPE_TAG,
ATypeTag.SERIALIZED_INT64_TYPE_TAG, ATypeTag.SERIALIZED_FLOAT_TYPE_TAG,
ATypeTag.SERIALIZED_DOUBLE_TYPE_TAG, ATypeTag.SERIALIZED_DATE_TYPE_TAG,
ATypeTag.SERIALIZED_TIME_TYPE_TAG, ATypeTag.SERIALIZED_DATETIME_TYPE_TAG,
ATypeTag.SERIALIZED_DURATION_TYPE_TAG, ATypeTag.SERIALIZED_YEAR_MONTH_DURATION_TYPE_TAG,
ATypeTag.SERIALIZED_DAY_TIME_DURATION_TYPE_TAG };
@Override
@SuppressWarnings("unchecked")
public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
evalLeft.evaluate(tuple, argPtr0);
evalRight.evaluate(tuple, argPtr1);
resultStorage.reset();
if (PointableHelper.checkAndSetMissingOrNull(result, argPtr0, argPtr1)) {
return;
}
ATypeTag argTypeMax = null;
for (int i = 0; i < 2; i++) {
IPointable argPtr = i == 0 ? argPtr0 : argPtr1;
byte[] bytes = argPtr.getByteArray();
int offset = argPtr.getStartOffset();
ATypeTag currentType;
ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(bytes[offset]);
switch (typeTag) {
case TINYINT:
currentType = ATypeTag.TINYINT;
operandsInteger[i] = AInt8SerializerDeserializer.getByte(bytes, offset + 1);
operandsFloating[i] = operandsInteger[i];
break;
case SMALLINT:
currentType = ATypeTag.SMALLINT;
operandsInteger[i] = AInt16SerializerDeserializer.getShort(bytes, offset + 1);
operandsFloating[i] = operandsInteger[i];
break;
case INTEGER:
currentType = ATypeTag.INTEGER;
operandsInteger[i] = AInt32SerializerDeserializer.getInt(bytes, offset + 1);
operandsFloating[i] = operandsInteger[i];
break;
case BIGINT:
currentType = ATypeTag.BIGINT;
operandsInteger[i] = AInt64SerializerDeserializer.getLong(bytes, offset + 1);
operandsFloating[i] = operandsInteger[i];
break;
case FLOAT:
currentType = ATypeTag.FLOAT;
operandsFloating[i] = AFloatSerializerDeserializer.getFloat(bytes, offset + 1);
break;
case DOUBLE:
currentType = ATypeTag.DOUBLE;
operandsFloating[i] = ADoubleSerializerDeserializer.getDouble(bytes, offset + 1);
break;
case DATE:
case TIME:
case DATETIME:
case DURATION:
case YEARMONTHDURATION:
case DAYTIMEDURATION:
evaluateTemporalArithmeticOperation();
result.set(resultStorage);
return;
default:
ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funID, bytes[offset], i, EXP_TYPES);
PointableHelper.setNull(result);
return;
}
if (i == 0 || currentType.ordinal() > argTypeMax.ordinal()) {
argTypeMax = currentType;
}
}
ATypeTag resultType = getNumericResultType(argTypeMax);
long lres;
double dres;
switch (resultType) {
case TINYINT:
if (evaluateInteger(operandsInteger[0], operandsInteger[1], aInt64)) {
lres = aInt64.getLongValue();
if (lres > Byte.MAX_VALUE) {
throw new OverflowException(sourceLoc, getIdentifier());
}
if (lres < Byte.MIN_VALUE) {
throw new UnderflowException(sourceLoc, getIdentifier());
}
aInt8.setValue((byte) lres);
int8Serde.serialize(aInt8, out);
} else {
nullSerde.serialize(ANull.NULL, out);
}
break;
case SMALLINT:
if (evaluateInteger(operandsInteger[0], operandsInteger[1], aInt64)) {
lres = aInt64.getLongValue();
if (lres > Short.MAX_VALUE) {
throw new OverflowException(sourceLoc, getIdentifier());
}
if (lres < Short.MIN_VALUE) {
throw new UnderflowException(sourceLoc, getIdentifier());
}
aInt16.setValue((short) lres);
int16Serde.serialize(aInt16, out);
} else {
nullSerde.serialize(ANull.NULL, out);
}
break;
case INTEGER:
if (evaluateInteger(operandsInteger[0], operandsInteger[1], aInt64)) {
lres = aInt64.getLongValue();
if (lres > Integer.MAX_VALUE) {
throw new OverflowException(sourceLoc, getIdentifier());
}
if (lres < Integer.MIN_VALUE) {
throw new UnderflowException(sourceLoc, getIdentifier());
}
aInt32.setValue((int) lres);
int32Serde.serialize(aInt32, out);
} else {
nullSerde.serialize(ANull.NULL, out);
}
break;
case BIGINT:
if (evaluateInteger(operandsInteger[0], operandsInteger[1], aInt64)) {
int64Serde.serialize(aInt64, out);
} else {
nullSerde.serialize(ANull.NULL, out);
}
break;
case FLOAT:
if (evaluateDouble(operandsFloating[0], operandsFloating[1], aDouble)) {
dres = aDouble.getDoubleValue();
if (Double.isFinite(dres)) {
if (dres > Float.MAX_VALUE) {
throw new OverflowException(sourceLoc, getIdentifier());
}
if (dres < -Float.MAX_VALUE) {
throw new UnderflowException(sourceLoc, getIdentifier());
}
}
aFloat.setValue((float) dres);
floatSerde.serialize(aFloat, out);
} else {
nullSerde.serialize(ANull.NULL, out);
}
break;
case DOUBLE:
if (evaluateDouble(operandsFloating[0], operandsFloating[1], aDouble)) {
doubleSerde.serialize(aDouble, out);
} else {
nullSerde.serialize(ANull.NULL, out);
}
break;
}
result.set(resultStorage);
}
@SuppressWarnings("unchecked")
private void evaluateTemporalArithmeticOperation() throws HyracksDataException {
byte[] bytes1 = argPtr1.getByteArray();
int offset1 = argPtr1.getStartOffset();
ATypeTag rightType = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(bytes1[offset1]);
byte[] bytes0 = argPtr0.getByteArray();
int offset0 = argPtr0.getStartOffset();
ATypeTag leftType = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(bytes0[offset0]);
if (rightType == leftType) {
long leftChronon = 0, rightChronon = 0, dayTime = 0;
int yearMonth = 0;
boolean yearMonthIsNull = false, dayTimeIsNull = false;
switch (leftType) {
case DATE:
leftChronon = ADateSerializerDeserializer.getChronon(bytes0, offset0 + 1)
* GregorianCalendarSystem.CHRONON_OF_DAY;
rightChronon = ADateSerializerDeserializer.getChronon(bytes1, offset1 + 1)
* GregorianCalendarSystem.CHRONON_OF_DAY;
break;
case TIME:
leftChronon = ATimeSerializerDeserializer.getChronon(bytes0, offset0 + 1);
rightChronon = ATimeSerializerDeserializer.getChronon(bytes1, offset1 + 1);
break;
case DATETIME:
leftChronon = ADateTimeSerializerDeserializer.getChronon(bytes0, offset0 + 1);
rightChronon = ADateTimeSerializerDeserializer.getChronon(bytes1, offset1 + 1);
break;
case YEARMONTHDURATION:
if (evaluateTimeInstanceArithmetic(
AYearMonthDurationSerializerDeserializer.getYearMonth(bytes0, offset0 + 1),
AYearMonthDurationSerializerDeserializer.getYearMonth(bytes1, offset1 + 1),
aInt64, ctx)) {
yearMonth = (int) aInt64.getLongValue();
} else {
yearMonthIsNull = true;
}
break;
case DAYTIMEDURATION:
leftChronon =
ADayTimeDurationSerializerDeserializer.getDayTime(bytes0, offset0 + 1);
rightChronon =
ADayTimeDurationSerializerDeserializer.getDayTime(bytes1, offset1 + 1);
break;
default:
ExceptionUtil.warnUnsupportedType(ctx, sourceLoc, funID.getName(), rightType);
nullSerde.serialize(ANull.NULL, out);
return;
}
if (evaluateTimeInstanceArithmetic(leftChronon, rightChronon, aInt64, ctx)) {
dayTime = aInt64.getLongValue();
} else {
dayTimeIsNull = true;
}
if (yearMonthIsNull || dayTimeIsNull) {
nullSerde.serialize(ANull.NULL, out);
} else {
aDuration.setValue(yearMonth, dayTime);
durationSerde.serialize(aDuration, out);
}
} else {
long chronon = 0, dayTime = 0;
int yearMonth = 0;
ATypeTag resultType = null;
ISerializerDeserializer serde = null;
boolean isTimeOnly = false;
switch (leftType) {
case TIME:
serde = timeSerde;
chronon = ATimeSerializerDeserializer.getChronon(bytes0, offset0 + 1);
isTimeOnly = true;
resultType = ATypeTag.TIME;
switch (rightType) {
case DAYTIMEDURATION:
dayTime = ADayTimeDurationSerializerDeserializer.getDayTime(bytes1,
offset1 + 1);
break;
case DURATION:
dayTime = ADurationSerializerDeserializer.getDayTime(bytes1, offset1 + 1);
yearMonth =
ADurationSerializerDeserializer.getYearMonth(bytes1, offset1 + 1);
break;
default:
ExceptionUtil.warnIncompatibleType(ctx, sourceLoc, funID.getName(),
leftType, rightType);
nullSerde.serialize(ANull.NULL, out);
return;
}
break;
case DATE:
serde = dateSerde;
resultType = ATypeTag.DATE;
chronon = ADateSerializerDeserializer.getChronon(bytes0, offset0 + 1)
* GregorianCalendarSystem.CHRONON_OF_DAY;
case DATETIME:
if (leftType == ATypeTag.DATETIME) {
serde = dateTimeSerde;
resultType = ATypeTag.DATETIME;
chronon = ADateTimeSerializerDeserializer.getChronon(bytes0, offset0 + 1);
}
switch (rightType) {
case DURATION:
yearMonth =
ADurationSerializerDeserializer.getYearMonth(bytes1, offset1 + 1);
dayTime = ADurationSerializerDeserializer.getDayTime(bytes1, offset1 + 1);
break;
case YEARMONTHDURATION:
yearMonth = AYearMonthDurationSerializerDeserializer.getYearMonth(bytes1,
offset1 + 1);
break;
case DAYTIMEDURATION:
dayTime = ADayTimeDurationSerializerDeserializer.getDayTime(bytes1,
offset1 + 1);
break;
default:
ExceptionUtil.warnIncompatibleType(ctx, sourceLoc, funID.getName(),
leftType, rightType);
nullSerde.serialize(ANull.NULL, out);
return;
}
break;
case YEARMONTHDURATION:
yearMonth =
AYearMonthDurationSerializerDeserializer.getYearMonth(bytes0, offset0 + 1);
switch (rightType) {
case DATETIME:
serde = dateTimeSerde;
resultType = ATypeTag.DATETIME;
chronon = ADateTimeSerializerDeserializer.getChronon(bytes1, offset1 + 1);
break;
case DATE:
serde = dateSerde;
resultType = ATypeTag.DATE;
chronon = ADateSerializerDeserializer.getChronon(bytes1, offset1 + 1)
* GregorianCalendarSystem.CHRONON_OF_DAY;
break;
default:
ExceptionUtil.warnIncompatibleType(ctx, sourceLoc, funID.getName(),
leftType, rightType);
nullSerde.serialize(ANull.NULL, out);
return;
}
break;
case DURATION:
yearMonth = ADurationSerializerDeserializer.getYearMonth(bytes0, offset0 + 1);
dayTime = ADurationSerializerDeserializer.getDayTime(bytes0, offset0 + 1);
case DAYTIMEDURATION:
if (leftType == ATypeTag.DAYTIMEDURATION) {
dayTime =
ADayTimeDurationSerializerDeserializer.getDayTime(bytes0, offset0 + 1);
}
switch (rightType) {
case DATETIME:
serde = dateTimeSerde;
resultType = ATypeTag.DATETIME;
chronon = ADateTimeSerializerDeserializer.getChronon(bytes1, offset1 + 1);
break;
case DATE:
serde = dateSerde;
resultType = ATypeTag.DATE;
chronon = ADateSerializerDeserializer.getChronon(bytes1, offset1 + 1)
* GregorianCalendarSystem.CHRONON_OF_DAY;
break;
case TIME:
if (yearMonth == 0) {
serde = timeSerde;
resultType = ATypeTag.TIME;
chronon = ATimeSerializerDeserializer.getChronon(bytes1, offset1 + 1);
isTimeOnly = true;
break;
}
default:
ExceptionUtil.warnIncompatibleType(ctx, sourceLoc, funID.getName(),
leftType, rightType);
nullSerde.serialize(ANull.NULL, out);
return;
}
break;
default:
ExceptionUtil.warnIncompatibleType(ctx, sourceLoc, funID.getName(), leftType,
rightType);
nullSerde.serialize(ANull.NULL, out);
return;
}
if (evaluateTimeDurationArithmetic(chronon, yearMonth, dayTime, isTimeOnly, aInt64, ctx)) {
chronon = aInt64.getLongValue();
switch (resultType) {
case DATE:
if (chronon < 0 && chronon % GregorianCalendarSystem.CHRONON_OF_DAY != 0) {
chronon = chronon / GregorianCalendarSystem.CHRONON_OF_DAY - 1;
} else {
chronon = chronon / GregorianCalendarSystem.CHRONON_OF_DAY;
}
aDate.setValue((int) chronon);
serde.serialize(aDate, out);
break;
case TIME:
aTime.setValue((int) chronon);
serde.serialize(aTime, out);
break;
case DATETIME:
aDatetime.setValue(chronon);
serde.serialize(aDatetime, out);
break;
default:
ExceptionUtil.warnIncompatibleType(ctx, sourceLoc, funID.getName(), leftType,
rightType);
nullSerde.serialize(ANull.NULL, out);
return;
}
} else {
nullSerde.serialize(ANull.NULL, out);
}
}
}
};
}
};
}