@Override
  public Writable serialize(Object obj, ObjectInspector oi) throws SerDeException {
    if (oi.getCategory() != Category.STRUCT) {
      throw new VoltSerdeException(
          getClass().toString()
              + " can only serialize struct types, but we got: "
              + oi.getTypeName());
    }
    VoltRecord vr = new VoltRecord(m_voltConf.getTableName());
    StructObjectInspector soi = (StructObjectInspector) oi;
    List<? extends StructField> structFields = soi.getAllStructFieldRefs();
    List<Object> fieldValues = soi.getStructFieldsDataAsList(obj);

    final int size = m_oig.getColumnTypes().size();

    for (int i = 0; i < size; ++i) {
      ObjectInspector fieldOI = structFields.get(i).getFieldObjectInspector();
      PrimitiveObjectInspector poi = (PrimitiveObjectInspector) fieldOI;

      Object fieldValue = poi.getPrimitiveJavaObject(fieldValues.get(i));
      if (poi.getTypeInfo().equals(TypeInfoFactory.timestampTypeInfo)) {
        fieldValue = fieldValue != null ? new Date(((Timestamp) fieldValue).getTime()) : null;
      }
      vr.add(fieldValue);
    }

    return vr;
  }
  @Test
  public void testDecimalPlusDecimalSameParams() throws HiveException {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
          TypeInfoFactory.getDecimalTypeInfo(5, 2)),
      PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
          TypeInfoFactory.getDecimalTypeInfo(5, 2))
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(TypeInfoFactory.getDecimalTypeInfo(6, 2), oi.getTypeInfo());
  }
  @Test
  public void testDoublePlusLong() throws HiveException {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    // Int
    DoubleWritable left = new DoubleWritable(4.5);
    LongWritable right = new LongWritable(10);
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.writableDoubleObjectInspector,
      PrimitiveObjectInspectorFactory.writableLongObjectInspector
    };
    DeferredObject[] args = {
      new DeferredJavaObject(left), new DeferredJavaObject(right),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(TypeInfoFactory.doubleTypeInfo, oi.getTypeInfo());
    DoubleWritable res = (DoubleWritable) udf.evaluate(args);
    Assert.assertEquals(new Double(14.5), new Double(res.get()));
  }
  @Test
  public void testBytePlusShort() throws HiveException {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    // Byte
    ByteWritable left = new ByteWritable((byte) 4);
    ShortWritable right = new ShortWritable((short) 6);
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.writableByteObjectInspector,
      PrimitiveObjectInspectorFactory.writableShortObjectInspector
    };
    DeferredObject[] args = {
      new DeferredJavaObject(left), new DeferredJavaObject(right),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(oi.getTypeInfo(), TypeInfoFactory.shortTypeInfo);
    ShortWritable res = (ShortWritable) udf.evaluate(args);
    Assert.assertEquals(10, res.get());
  }
  @Test
  public void testTimestampPlusIntervalDayTime() throws Exception {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    TimestampWritable left = new TimestampWritable(Timestamp.valueOf("2001-01-01 00:00:00"));
    HiveIntervalDayTimeWritable right =
        new HiveIntervalDayTimeWritable(HiveIntervalDayTime.valueOf("1 2:3:4.567"));
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.writableTimestampObjectInspector,
      PrimitiveObjectInspectorFactory.writableHiveIntervalDayTimeObjectInspector
    };
    DeferredObject[] args = {
      new DeferredJavaObject(left), new DeferredJavaObject(right),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(TypeInfoFactory.timestampTypeInfo, oi.getTypeInfo());
    TimestampWritable res = (TimestampWritable) udf.evaluate(args);
    Assert.assertEquals(Timestamp.valueOf("2001-01-02 2:3:4.567"), res.getTimestamp());
  }
  @Test
  public void testDatePlusIntervalYearMonth() throws Exception {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    DateWritable left = new DateWritable(Date.valueOf("2001-06-15"));
    HiveIntervalYearMonthWritable right =
        new HiveIntervalYearMonthWritable(HiveIntervalYearMonth.valueOf("2-8"));
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.writableDateObjectInspector,
      PrimitiveObjectInspectorFactory.writableHiveIntervalYearMonthObjectInspector
    };
    DeferredObject[] args = {
      new DeferredJavaObject(left), new DeferredJavaObject(right),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(TypeInfoFactory.dateTypeInfo, oi.getTypeInfo());
    DateWritable res = (DateWritable) udf.evaluate(args);
    Assert.assertEquals(Date.valueOf("2004-02-15"), res.get());
  }
  @Test
  public void testFloatPlusFloat() throws HiveException {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    // Float
    FloatWritable f1 = new FloatWritable(4.5f);
    FloatWritable f2 = new FloatWritable(0.0f);
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.writableFloatObjectInspector,
      PrimitiveObjectInspectorFactory.writableFloatObjectInspector
    };
    DeferredObject[] args = {
      new DeferredJavaObject(f1), new DeferredJavaObject(f2),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(oi.getTypeInfo(), TypeInfoFactory.floatTypeInfo);
    FloatWritable res = (FloatWritable) udf.evaluate(args);
    Assert.assertEquals(new Float(4.5), new Float(res.get()));
  }
  @Test
  public void testVarcharPlusInt() throws HiveException {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    // Short
    HiveVarcharWritable left = new HiveVarcharWritable();
    left.set("123");
    IntWritable right = new IntWritable(456);
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.writableHiveVarcharObjectInspector,
      PrimitiveObjectInspectorFactory.writableIntObjectInspector
    };
    DeferredObject[] args = {
      new DeferredJavaObject(left), new DeferredJavaObject(right),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(oi.getTypeInfo(), TypeInfoFactory.doubleTypeInfo);
    DoubleWritable res = (DoubleWritable) udf.evaluate(args);
    Assert.assertEquals(new Double(579.0), new Double(res.get()));
  }
  @Test
  public void testTimestampPlusIntervalYearMonth() throws Exception {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    TimestampWritable left =
        new TimestampWritable(Timestamp.valueOf("2001-11-15 01:02:03.123456789"));
    HiveIntervalYearMonthWritable right =
        new HiveIntervalYearMonthWritable(HiveIntervalYearMonth.valueOf("2-2"));
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.writableTimestampObjectInspector,
      PrimitiveObjectInspectorFactory.writableHiveIntervalYearMonthObjectInspector
    };
    DeferredObject[] args = {
      new DeferredJavaObject(left), new DeferredJavaObject(right),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(TypeInfoFactory.timestampTypeInfo, oi.getTypeInfo());
    TimestampWritable res = (TimestampWritable) udf.evaluate(args);
    Assert.assertEquals(Timestamp.valueOf("2004-01-15 01:02:03.123456789"), res.getTimestamp());
  }
  @Test
  public void testDoulePlusDecimal() throws HiveException {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    // Double
    DoubleWritable left = new DoubleWritable(74.52);
    HiveDecimalWritable right = new HiveDecimalWritable(HiveDecimal.create("234.97"));
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.writableDoubleObjectInspector,
      PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
          TypeInfoFactory.getDecimalTypeInfo(5, 2))
    };
    DeferredObject[] args = {
      new DeferredJavaObject(left), new DeferredJavaObject(right),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(TypeInfoFactory.doubleTypeInfo, oi.getTypeInfo());
    DoubleWritable res = (DoubleWritable) udf.evaluate(args);
    Assert.assertEquals(new Double(309.49), new Double(res.get()));
  }
  @Test
  public void testLongPlusDecimal() throws HiveException {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    // Long
    LongWritable left = new LongWritable(104);
    HiveDecimalWritable right = new HiveDecimalWritable(HiveDecimal.create("234.97"));
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.writableLongObjectInspector,
      PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
          TypeInfoFactory.getDecimalTypeInfo(9, 4))
    };
    DeferredObject[] args = {
      new DeferredJavaObject(left), new DeferredJavaObject(right),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(TypeInfoFactory.getDecimalTypeInfo(24, 4), oi.getTypeInfo());
    HiveDecimalWritable res = (HiveDecimalWritable) udf.evaluate(args);
    Assert.assertEquals(HiveDecimal.create("338.97"), res.getHiveDecimal());
  }
  @Test
  public void testDecimalPlusDecimal() throws HiveException {
    GenericUDFOPPlus udf = new GenericUDFOPPlus();

    // Decimal
    HiveDecimalWritable left = new HiveDecimalWritable(HiveDecimal.create("14.5"));
    HiveDecimalWritable right = new HiveDecimalWritable(HiveDecimal.create("234.97"));
    ObjectInspector[] inputOIs = {
      PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
          TypeInfoFactory.getDecimalTypeInfo(3, 1)),
      PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
          TypeInfoFactory.getDecimalTypeInfo(5, 2))
    };
    DeferredObject[] args = {
      new DeferredJavaObject(left), new DeferredJavaObject(right),
    };

    PrimitiveObjectInspector oi = (PrimitiveObjectInspector) udf.initialize(inputOIs);
    Assert.assertEquals(TypeInfoFactory.getDecimalTypeInfo(6, 2), oi.getTypeInfo());
    HiveDecimalWritable res = (HiveDecimalWritable) udf.evaluate(args);
    Assert.assertEquals(HiveDecimal.create("249.47"), res.getHiveDecimal());
  }
 private Writable createPrimitive(final Object obj, final PrimitiveObjectInspector inspector)
     throws SerDeException {
   if (obj == null) {
     return null;
   }
   switch (inspector.getPrimitiveCategory()) {
     case VOID:
       return null;
     case BOOLEAN:
       return new BooleanWritable(
           ((BooleanObjectInspector) inspector).get(obj) ? Boolean.TRUE : Boolean.FALSE);
     case BYTE:
       return new ByteWritable(((ByteObjectInspector) inspector).get(obj));
     case DOUBLE:
       return new DoubleWritable(((DoubleObjectInspector) inspector).get(obj));
     case FLOAT:
       return new FloatWritable(((FloatObjectInspector) inspector).get(obj));
     case INT:
       return new IntWritable(((IntObjectInspector) inspector).get(obj));
     case LONG:
       return new LongWritable(((LongObjectInspector) inspector).get(obj));
     case SHORT:
       return new ShortWritable(((ShortObjectInspector) inspector).get(obj));
     case STRING:
       String v = ((StringObjectInspector) inspector).getPrimitiveJavaObject(obj);
       try {
         return new BytesWritable(v.getBytes("UTF-8"));
       } catch (UnsupportedEncodingException e) {
         throw new SerDeException("Failed to encode string in UTF-8", e);
       }
     case DECIMAL:
       HiveDecimal hd = (HiveDecimal) inspector.getPrimitiveJavaObject(obj);
       DecimalTypeInfo decTypeInfo = (DecimalTypeInfo) inspector.getTypeInfo();
       int prec = decTypeInfo.precision();
       int scale = decTypeInfo.scale();
       byte[] src = hd.setScale(scale).unscaledValue().toByteArray();
       // Estimated number of bytes needed.
       int bytes = PRECISION_TO_BYTE_COUNT[prec - 1];
       if (bytes == src.length) {
         // No padding needed.
         return new BytesWritable(src);
       }
       byte[] tgt = new byte[bytes];
       if (hd.signum() == -1) {
         // For negative number, initializing bits to 1
         for (int i = 0; i < bytes; i++) {
           tgt[i] |= 0xFF;
         }
       }
       System.arraycopy(
           src, 0, tgt, bytes - src.length, src.length); // Padding leading zeroes/ones.
       return new BytesWritable(tgt);
     case TIMESTAMP:
       return new TimestampWritable(
           ((TimestampObjectInspector) inspector).getPrimitiveJavaObject(obj));
     case CHAR:
       String strippedValue =
           ((HiveCharObjectInspector) inspector).getPrimitiveJavaObject(obj).getStrippedValue();
       return new BytesWritable(Binary.fromString(strippedValue).getBytes());
     case VARCHAR:
       String value =
           ((HiveVarcharObjectInspector) inspector).getPrimitiveJavaObject(obj).getValue();
       return new BytesWritable(Binary.fromString(value).getBytes());
     case BINARY:
       return new BytesWritable(((BinaryObjectInspector) inspector).getPrimitiveJavaObject(obj));
     default:
       throw new SerDeException("Unknown primitive : " + inspector.getPrimitiveCategory());
   }
 }