/** * 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.hadoop.hive.serde2.objectinspector; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters.Converter; import org.apache.hadoop.hive.serde2.objectinspector.primitive.BooleanObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.ByteObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.IntObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.LongObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils; /** * Compare two list of objects. * Two lists are expected to have same types. Type information for every object is * passed when calling Constructor to avoid the step of figuring out types from * ObjectInspetor and determine how to compare the types when comparing. * Also, for string and text elements, it performs slightly better than * using ObjectInspectorUtils.compare() == 0, which instead of calling .compare() * calls .equalTo(), which compares size before byte by byte comparison. * */ public class ListObjectsEqualComparer { enum CompareType { // Now only string, text, int, long, byte and boolean comparisons // are treated as special cases. // For other types, we reuse ObjectInspectorUtils.compare() COMPARE_STRING, COMPARE_TEXT, COMPARE_INT, COMPARE_LONG, COMPARE_BYTE, COMPARE_BOOL, OTHER } class FieldComparer { protected ObjectInspector oi0, oi1; protected ObjectInspector compareOI; protected CompareType compareType; protected Converter converter0, converter1; protected StringObjectInspector soi0, soi1; protected IntObjectInspector ioi0, ioi1; protected LongObjectInspector loi0, loi1; protected ByteObjectInspector byoi0, byoi1; protected BooleanObjectInspector boi0, boi1; public FieldComparer(ObjectInspector oi0, ObjectInspector oi1) { this.oi0 = oi0; this.oi1 = oi1; TypeInfo type0 = TypeInfoUtils.getTypeInfoFromObjectInspector(oi0); TypeInfo type1 = TypeInfoUtils.getTypeInfoFromObjectInspector(oi1); if (type0.equals(TypeInfoFactory.stringTypeInfo) && type1.equals(TypeInfoFactory.stringTypeInfo)) { soi0 = (StringObjectInspector) oi0; soi1 = (StringObjectInspector) oi1; if (soi0.preferWritable() || soi1.preferWritable()) { compareType = CompareType.COMPARE_TEXT; } else { compareType = CompareType.COMPARE_STRING; } } else if (type0.equals(TypeInfoFactory.intTypeInfo) && type1.equals(TypeInfoFactory.intTypeInfo)) { compareType = CompareType.COMPARE_INT; ioi0 = (IntObjectInspector) oi0; ioi1 = (IntObjectInspector) oi1; } else if (type0.equals(TypeInfoFactory.longTypeInfo) && type1.equals(TypeInfoFactory.longTypeInfo)) { compareType = CompareType.COMPARE_LONG; loi0 = (LongObjectInspector) oi0; loi1 = (LongObjectInspector) oi1; } else if (type0.equals(TypeInfoFactory.byteTypeInfo) && type1.equals(TypeInfoFactory.byteTypeInfo)) { compareType = CompareType.COMPARE_BYTE; byoi0 = (ByteObjectInspector) oi0; byoi1 = (ByteObjectInspector) oi1; } else if (type0.equals(TypeInfoFactory.booleanTypeInfo) && type1.equals(TypeInfoFactory.booleanTypeInfo)) { compareType = CompareType.COMPARE_BOOL; boi0 = (BooleanObjectInspector) oi0; boi1 = (BooleanObjectInspector) oi1; } else { // We don't check compatibility of two object inspectors, but directly // pass them into ObjectInspectorUtils.compare(), users of this class // should make sure ObjectInspectorUtils.compare() doesn't throw exceptions // and returns correct results. compareType = CompareType.OTHER; } } public boolean areEqual(Object o0, Object o1) { if (o0 == null && o1 == null) { return true; } else if (o0 == null || o1 == null) { return false; } switch (compareType) { case COMPARE_TEXT: return (soi0.getPrimitiveWritableObject(o0).equals( soi1.getPrimitiveWritableObject(o1))); case COMPARE_INT: return (ioi0.get(o0) == ioi1.get(o1)); case COMPARE_LONG: return (loi0.get(o0) == loi1.get(o1)); case COMPARE_BYTE: return (byoi0.get(o0) == byoi1.get(o1)); case COMPARE_BOOL: return (boi0.get(o0) == boi1.get(o1)); case COMPARE_STRING: return (soi0.getPrimitiveJavaObject(o0).equals( soi1.getPrimitiveJavaObject(o1))); default: return (ObjectInspectorUtils.compare( o0, oi0, o1, oi1) == 0); } } } FieldComparer[] fieldComparers; int numFields; public ListObjectsEqualComparer(ObjectInspector[] oi0, ObjectInspector[] oi1) { if (oi0.length != oi1.length) { throw new RuntimeException("Sizes of two lists of object inspectors don't match."); } numFields = oi0.length; fieldComparers = new FieldComparer[numFields]; for (int i = 0; i < oi0.length; i++) { fieldComparers[i] = new FieldComparer(oi0[i], oi1[i]); } } /** * ol0, ol1 should have equal or less number of elements than objectinspectors * passed in constructor. * * @param ol0 * @param ol1 * @return True if object in ol0 and ol1 are all identical */ public boolean areEqual(Object[] ol0, Object[] ol1) { if (ol0.length != numFields || ol1.length != numFields) { if (ol0.length != ol1.length) { return false; } assert (ol0.length <= numFields); assert (ol1.length <= numFields); for (int i = 0; i < Math.min(ol0.length, ol1.length); i++) { if (!fieldComparers[i].areEqual(ol0[i], ol1[i])) { return false; } } return true; } for (int i = numFields - 1; i >= 0; i--) { if (!fieldComparers[i].areEqual(ol0[i], ol1[i])) { return false; } } return true; } }