@SuppressWarnings("unchecked")
  @Override
  public void evaluate(IFrameTupleReference tuple) throws AlgebricksException {
    array0.reset();
    eval0.evaluate(tuple);
    array1.reset();
    eval1.evaluate(tuple);
    array2.reset();
    eval2.evaluate(tuple);

    try {
      if (array0.getByteArray()[0] == SER_NULL_TYPE_TAG
          || array1.getByteArray()[0] == SER_NULL_TYPE_TAG
          || array2.getByteArray()[0] == SER_NULL_TYPE_TAG) {
        nullSerde.serialize(ANull.NULL, dout);
        return;
      } else if (array0.getByteArray()[0] != SER_STRING_TYPE_TAG
          || array1.getByteArray()[0] != SER_STRING_TYPE_TAG
          || array2.getByteArray()[0] != SER_STRING_TYPE_TAG) {
        throw new AlgebricksException(
            funcID.getName()
                + ": expects input type (STRING/NULL, STRING/NULL, STRING/NULL), but got ("
                + EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(array0.getByteArray()[0])
                + ", "
                + EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(array1.getByteArray()[0])
                + ", "
                + EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(array2.getByteArray()[0])
                + ".");
      }
    } catch (HyracksDataException e) {
      throw new AlgebricksException(e);
    }

    strPtr1st.set(array0.getByteArray(), array0.getStartOffset() + 1, array0.getLength());
    strPtr2nd.set(array1.getByteArray(), array1.getStartOffset() + 1, array1.getLength());
    strPtr3rd.set(array2.getByteArray(), array2.getStartOffset() + 1, array2.getLength());

    String res = compute(strPtr1st, strPtr2nd, strPtr3rd);
    resultBuffer.setValue(res);
    try {
      strSerde.serialize(resultBuffer, dout);
    } catch (HyracksDataException e) {
      throw new AlgebricksException(e);
    }
  }
 protected void processPartialResults(IFrameTupleReference tuple) throws AlgebricksException {
   if (skipStep()) {
     return;
   }
   inputVal.reset();
   eval.evaluate(tuple);
   byte[] serBytes = inputVal.getByteArray();
   ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(serBytes[0]);
   switch (typeTag) {
     case NULL:
       {
         processNull();
         break;
       }
     case SYSTEM_NULL:
       {
         // Ignore and return.
         break;
       }
     case RECORD:
       {
         // Expected.
         aggType = ATypeTag.DOUBLE;
         int nullBitmapSize = 0;
         int offset1 =
             ARecordSerializerDeserializer.getFieldOffsetById(
                 serBytes, SUM_FIELD_ID, nullBitmapSize, false);
         sum += ADoubleSerializerDeserializer.getDouble(serBytes, offset1);
         int offset2 =
             ARecordSerializerDeserializer.getFieldOffsetById(
                 serBytes, COUNT_FIELD_ID, nullBitmapSize, false);
         count += AInt64SerializerDeserializer.getLong(serBytes, offset2);
         break;
       }
     default:
       {
         throw new AlgebricksException(
             "Global-Avg is not defined for values of type "
                 + EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(serBytes[0]));
       }
   }
 }
 protected void processDataValues(IFrameTupleReference tuple) throws AlgebricksException {
   if (skipStep()) {
     return;
   }
   inputVal.reset();
   eval.evaluate(tuple);
   ATypeTag typeTag =
       EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(inputVal.getByteArray()[0]);
   if (typeTag == ATypeTag.NULL) {
     processNull();
     return;
   } else if (aggType == ATypeTag.SYSTEM_NULL) {
     aggType = typeTag;
   } else if (typeTag != ATypeTag.SYSTEM_NULL && !ATypeHierarchy.isCompatible(typeTag, aggType)) {
     throw new AlgebricksException(
         "Unexpected type "
             + typeTag
             + " in aggregation input stream. Expected type "
             + aggType
             + ".");
   } else if (ATypeHierarchy.canPromote(aggType, typeTag)) {
     aggType = typeTag;
   }
   ++count;
   switch (typeTag) {
     case INT8:
       {
         byte val = AInt8SerializerDeserializer.getByte(inputVal.getByteArray(), 1);
         sum += val;
         break;
       }
     case INT16:
       {
         short val = AInt16SerializerDeserializer.getShort(inputVal.getByteArray(), 1);
         sum += val;
         break;
       }
     case INT32:
       {
         int val = AInt32SerializerDeserializer.getInt(inputVal.getByteArray(), 1);
         sum += val;
         break;
       }
     case INT64:
       {
         long val = AInt64SerializerDeserializer.getLong(inputVal.getByteArray(), 1);
         sum += val;
         break;
       }
     case FLOAT:
       {
         float val = AFloatSerializerDeserializer.getFloat(inputVal.getByteArray(), 1);
         sum += val;
         break;
       }
     case DOUBLE:
       {
         double val = ADoubleSerializerDeserializer.getDouble(inputVal.getByteArray(), 1);
         sum += val;
         break;
       }
     default:
       {
         throw new NotImplementedException("Cannot compute AVG for values of type " + typeTag);
       }
   }
   inputVal.reset();
 }
  @Override
  public void step(IFrameTupleReference tuple) throws AlgebricksException {
    inputVal.reset();
    eval.evaluate(tuple);
    ATypeTag typeTag =
        EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(inputVal.getByteArray()[0]);
    if (typeTag == ATypeTag.NULL) {
      processNull();
      return;
    } else if (aggType == ATypeTag.NULL) {
      return;
    } else if (aggType == ATypeTag.SYSTEM_NULL) {
      if (typeTag == ATypeTag.SYSTEM_NULL) {
        // Ignore.
        return;
      }
      // First value encountered. Set type, comparator, and initial value.
      aggType = typeTag;
      // Set comparator.
      IBinaryComparatorFactory cmpFactory =
          AqlBinaryComparatorFactoryProvider.INSTANCE.getBinaryComparatorFactory(aggType, isMin);
      cmp = cmpFactory.createBinaryComparator();
      // Initialize min value.
      outputVal.assign(inputVal);
    } else if (typeTag != ATypeTag.SYSTEM_NULL && !ATypeHierarchy.isCompatible(typeTag, aggType)) {
      throw new AlgebricksException(
          "Unexpected type "
              + typeTag
              + " in aggregation input stream. Expected type "
              + aggType
              + ".");
    } else {

      // If a system_null is encountered locally, it would be an error; otherwise if it is seen
      // by a global aggregator, it is simple ignored.
      if (typeTag == ATypeTag.SYSTEM_NULL) {
        processSystemNull();
        return;
      }

      if (ATypeHierarchy.canPromote(aggType, typeTag)) {
        tpc = ATypeHierarchy.getTypePromoteComputer(aggType, typeTag);
        aggType = typeTag;
        cmp =
            AqlBinaryComparatorFactoryProvider.INSTANCE
                .getBinaryComparatorFactory(aggType, isMin)
                .createBinaryComparator();
        if (tpc != null) {
          tempValForCasting.reset();
          try {
            tpc.convertType(
                outputVal.getByteArray(),
                outputVal.getStartOffset() + 1,
                outputVal.getLength() - 1,
                tempValForCasting.getDataOutput());
          } catch (IOException e) {
            throw new AlgebricksException(e);
          }
          outputVal.reset();
          outputVal.assign(tempValForCasting);
        }
        try {
          if (cmp.compare(
                  inputVal.getByteArray(),
                  inputVal.getStartOffset(),
                  inputVal.getLength(),
                  outputVal.getByteArray(),
                  outputVal.getStartOffset(),
                  outputVal.getLength())
              < 0) {
            outputVal.assign(inputVal);
          }
        } catch (HyracksDataException e) {
          throw new AlgebricksException(e);
        }

      } else {
        tpc = ATypeHierarchy.getTypePromoteComputer(typeTag, aggType);
        if (tpc != null) {
          tempValForCasting.reset();
          try {
            tpc.convertType(
                inputVal.getByteArray(),
                inputVal.getStartOffset() + 1,
                inputVal.getLength() - 1,
                tempValForCasting.getDataOutput());
          } catch (IOException e) {
            throw new AlgebricksException(e);
          }
          try {
            if (cmp.compare(
                    tempValForCasting.getByteArray(),
                    tempValForCasting.getStartOffset(),
                    tempValForCasting.getLength(),
                    outputVal.getByteArray(),
                    outputVal.getStartOffset(),
                    outputVal.getLength())
                < 0) {
              outputVal.assign(tempValForCasting);
            }
          } catch (HyracksDataException e) {
            throw new AlgebricksException(e);
          }
        } else {
          try {
            if (cmp.compare(
                    inputVal.getByteArray(),
                    inputVal.getStartOffset(),
                    inputVal.getLength(),
                    outputVal.getByteArray(),
                    outputVal.getStartOffset(),
                    outputVal.getLength())
                < 0) {
              outputVal.assign(inputVal);
            }
          } catch (HyracksDataException e) {
            throw new AlgebricksException(e);
          }
        }
      }
    }
  }