/**
* 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;
}
}