public static int compare(Object o1, ObjectInspector oi1, Object o2,
      ObjectInspector oi2, MapEqualComparer mapEqualComparer, NullValueOption nullValueOpt) {
    if (oi1.getCategory() != oi2.getCategory()) {
      return oi1.getCategory().compareTo(oi2.getCategory());
    }

    if (o1 == null) {
      return o2 == null ? 0 : nullValueOpt.getCmpReturnValue();
    } else if (o2 == null) {
      return -nullValueOpt.getCmpReturnValue();
    }

    switch (oi1.getCategory()) {
    case PRIMITIVE: {
      PrimitiveObjectInspector poi1 = ((PrimitiveObjectInspector) oi1);
      PrimitiveObjectInspector poi2 = ((PrimitiveObjectInspector) oi2);
      if (poi1.getPrimitiveCategory() != poi2.getPrimitiveCategory()) {
        return poi1.getPrimitiveCategory().compareTo(
            poi2.getPrimitiveCategory());
      }
      switch (poi1.getPrimitiveCategory()) {
      case VOID:
        return 0;
      case BOOLEAN: {
        int v1 = ((BooleanObjectInspector) poi1).get(o1) ? 1 : 0;
        int v2 = ((BooleanObjectInspector) poi2).get(o2) ? 1 : 0;
        return v1 - v2;
      }
      case BYTE: {
        int v1 = ((ByteObjectInspector) poi1).get(o1);
        int v2 = ((ByteObjectInspector) poi2).get(o2);
        return v1 - v2;
      }
      case SHORT: {
        int v1 = ((ShortObjectInspector) poi1).get(o1);
        int v2 = ((ShortObjectInspector) poi2).get(o2);
        return v1 - v2;
      }
      case INT: {
        int v1 = ((IntObjectInspector) poi1).get(o1);
        int v2 = ((IntObjectInspector) poi2).get(o2);
        return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
      }
      case LONG: {
        long v1 = ((LongObjectInspector) poi1).get(o1);
        long v2 = ((LongObjectInspector) poi2).get(o2);
        return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
      }
      case FLOAT: {
        float v1 = ((FloatObjectInspector) poi1).get(o1);
        float v2 = ((FloatObjectInspector) poi2).get(o2);

        // The IEEE 754 floating point spec specifies that signed -0.0 and 0.0 should be treated as equal.
        if (v1 == 0.0f && v2 == 0.0f) {
          return 0;
        } else {
          // Float.compare() treats -0.0 and 0.0 as different
          return Float.compare(v1, v2);
        }
      }
      case DOUBLE: {
        double v1 = ((DoubleObjectInspector) poi1).get(o1);
        double v2 = ((DoubleObjectInspector) poi2).get(o2);

        // The IEEE 754 floating point spec specifies that signed -0.0 and 0.0 should be treated as equal.
        if (v1 == 0.0d && v2 == 0.0d) {
          return 0;
        } else {
          // Double.compare() treats -0.0 and 0.0 as different
          return Double.compare(v1, v2);
        }
      }
      case STRING: {
        if (poi1.preferWritable() || poi2.preferWritable()) {
          Text t1 = (Text) poi1.getPrimitiveWritableObject(o1);
          Text t2 = (Text) poi2.getPrimitiveWritableObject(o2);
          return t1 == null ? (t2 == null ? 0 : -1) : (t2 == null ? 1
              : t1.compareTo(t2));
        } else {
          String s1 = (String) poi1.getPrimitiveJavaObject(o1);
          String s2 = (String) poi2.getPrimitiveJavaObject(o2);
          return s1 == null ? (s2 == null ? 0 : -1) : (s2 == null ? 1 : s1
              .compareTo(s2));
        }
      }
      case CHAR: {
        HiveCharWritable t1 = ((HiveCharObjectInspector)poi1).getPrimitiveWritableObject(o1);
        HiveCharWritable t2 = ((HiveCharObjectInspector)poi2).getPrimitiveWritableObject(o2);
        return t1.compareTo(t2);
      }
      case VARCHAR: {
        HiveVarcharWritable t1 = ((HiveVarcharObjectInspector)poi1).getPrimitiveWritableObject(o1);
        HiveVarcharWritable t2 = ((HiveVarcharObjectInspector)poi2).getPrimitiveWritableObject(o2);
        return t1.compareTo(t2);
      }
      case BINARY: {
        BytesWritable bw1 = ((BinaryObjectInspector) poi1).getPrimitiveWritableObject(o1);
        BytesWritable bw2 = ((BinaryObjectInspector) poi2).getPrimitiveWritableObject(o2);
        return bw1.compareTo(bw2);
      }

      case DATE: {
        DateWritableV2 d1 = ((DateObjectInspector) poi1)
            .getPrimitiveWritableObject(o1);
        DateWritableV2 d2 = ((DateObjectInspector) poi2)
            .getPrimitiveWritableObject(o2);
        return d1.compareTo(d2);
      }
      case TIMESTAMP: {
        TimestampWritableV2 t1 = ((TimestampObjectInspector) poi1)
            .getPrimitiveWritableObject(o1);
        TimestampWritableV2 t2 = ((TimestampObjectInspector) poi2)
            .getPrimitiveWritableObject(o2);
        return t1.compareTo(t2);
      }
      case TIMESTAMPLOCALTZ: {
        TimestampLocalTZWritable tstz1 = ((TimestampLocalTZObjectInspector) poi1).
            getPrimitiveWritableObject(o1);
        TimestampLocalTZWritable tstz2 = ((TimestampLocalTZObjectInspector) poi2).
            getPrimitiveWritableObject(o2);
        return tstz1.compareTo(tstz2);
      }
      case INTERVAL_YEAR_MONTH: {
        HiveIntervalYearMonthWritable i1 = ((HiveIntervalYearMonthObjectInspector) poi1)
            .getPrimitiveWritableObject(o1);
        HiveIntervalYearMonthWritable i2 = ((HiveIntervalYearMonthObjectInspector) poi2)
            .getPrimitiveWritableObject(o2);
        return i1.compareTo(i2);
      }
      case INTERVAL_DAY_TIME: {
        HiveIntervalDayTimeWritable i1 = ((HiveIntervalDayTimeObjectInspector) poi1)
            .getPrimitiveWritableObject(o1);
        HiveIntervalDayTimeWritable i2 = ((HiveIntervalDayTimeObjectInspector) poi2)
            .getPrimitiveWritableObject(o2);
        return i1.compareTo(i2);
      }
      case DECIMAL: {
        HiveDecimalWritable t1 = ((HiveDecimalObjectInspector) poi1)
            .getPrimitiveWritableObject(o1);
        HiveDecimalWritable t2 = ((HiveDecimalObjectInspector) poi2)
            .getPrimitiveWritableObject(o2);
        return t1.compareTo(t2);
      }
      default: {
        throw new RuntimeException("Unknown type: "
            + poi1.getPrimitiveCategory());
      }
      }
    }
    case STRUCT: {
      StructObjectInspector soi1 = (StructObjectInspector) oi1;
      StructObjectInspector soi2 = (StructObjectInspector) oi2;
      List<? extends StructField> fields1 = soi1.getAllStructFieldRefs();
      List<? extends StructField> fields2 = soi2.getAllStructFieldRefs();
      int minimum = Math.min(fields1.size(), fields2.size());
      Object data1 =
              soi1 instanceof ConstantObjectInspector
              ? ((ConstantObjectInspector) soi1).getWritableConstantValue()
              : o1;
      Object data2 =
              soi2 instanceof ConstantObjectInspector
              ? ((ConstantObjectInspector) soi2).getWritableConstantValue()
              : o2;
      for (int i = 0; i < minimum; i++) {
        int r = compare(soi1.getStructFieldData(data1, fields1.get(i)), fields1
            .get(i).getFieldObjectInspector(), soi2.getStructFieldData(data2,
            fields2.get(i)), fields2.get(i).getFieldObjectInspector(),
            mapEqualComparer, nullValueOpt);
        if (r != 0) {
          return r;
        }
      }
      return fields1.size() - fields2.size();
    }
    case LIST: {
      ListObjectInspector loi1 = (ListObjectInspector) oi1;
      ListObjectInspector loi2 = (ListObjectInspector) oi2;
      int minimum = Math.min(loi1.getListLength(o1), loi2.getListLength(o2));
      for (int i = 0; i < minimum; i++) {
        int r = compare(loi1.getListElement(o1, i), loi1
            .getListElementObjectInspector(), loi2.getListElement(o2, i), loi2
            .getListElementObjectInspector(),
            mapEqualComparer, nullValueOpt);
        if (r != 0) {
          return r;
        }
      }
      return loi1.getListLength(o1) - loi2.getListLength(o2);
    }
    case MAP: {
      if (mapEqualComparer == null) {
        throw new RuntimeException("Compare on map type not supported!");
      } else {
        return mapEqualComparer.compare(o1, (MapObjectInspector)oi1, o2, (MapObjectInspector)oi2);
      }
    }
    case UNION: {
      UnionObjectInspector uoi1 = (UnionObjectInspector) oi1;
      UnionObjectInspector uoi2 = (UnionObjectInspector) oi2;
      byte tag1 = uoi1.getTag(o1);
      byte tag2 = uoi2.getTag(o2);
      if (tag1 != tag2) {
        return tag1 - tag2;
      }
      return compare(uoi1.getField(o1),
          uoi1.getObjectInspectors().get(tag1),
          uoi2.getField(o2), uoi2.getObjectInspectors().get(tag2),
          mapEqualComparer, nullValueOpt);
    }
    default:
      throw new RuntimeException("Compare on unknown type: "
          + oi1.getCategory());
    }
  }
Compare two objects with their respective ObjectInspectors.
if nullValueOpt is MAXVALUE, treat null as maximum value.
if nullValueOpt is MINVALUE, treat null as minimum value.
serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/ObjectInspectorUtils.java