| /* |
| * 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.ql.udf.generic; |
| |
| import org.apache.hadoop.hive.ql.exec.Description; |
| import org.apache.hadoop.hive.ql.exec.UDFArgumentException; |
| import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException; |
| import org.apache.hadoop.hive.ql.metadata.HiveException; |
| import org.apache.hadoop.hive.ql.udf.UDFLike; |
| import org.apache.hadoop.hive.serde2.objectinspector.ConstantObjectInspector; |
| import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; |
| import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters; |
| import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters.Converter; |
| import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector; |
| import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector.PrimitiveCategory; |
| import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; |
| import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils.PrimitiveGrouping; |
| import org.apache.hadoop.io.BooleanWritable; |
| import org.apache.hadoop.io.Text; |
| |
| |
| /** |
| * GenericUDFLikeAll is return true if a text(column value) matches to any patterns |
| * |
| * Example usage: SELECT key FROM src WHERE key like any ('%ab%', 'a%','b%','abc'); |
| * |
| * like ANY returns true if test matches any patterns patternN. |
| * Returns NULL if the expression on the left hand side is NULL or if one of the patterns in the list is NULL. |
| */ |
| |
| @Description( |
| name = "like any", |
| value = "test _FUNC_(pattern1, pattern2...) - returns true if test matches any patterns patternN." |
| + " Returns NULL if the expression on the left hand side is NULL or if one of the patterns in the list is NULL. ") |
| public class GenericUDFLikeAny extends GenericUDF { |
| private transient PrimitiveCategory[] inputTypes; |
| private transient Converter[] converters; |
| private transient boolean isConstantNullPatternContain; |
| private boolean isAllPatternsConstant = true; |
| private final BooleanWritable bw = new BooleanWritable(); |
| |
| @Override |
| public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException { |
| if (arguments.length < 2) { |
| throw new UDFArgumentLengthException("The like any operator requires at least one pattern for matching, got " |
| + (arguments.length - 1)); |
| } |
| inputTypes = new PrimitiveCategory[arguments.length]; |
| converters = new Converter[arguments.length]; |
| |
| /**expects string and null arguments */ |
| for (int idx = 0; idx < arguments.length; idx++) { |
| checkArgPrimitive(arguments, idx); |
| checkArgGroups(arguments, idx, inputTypes, PrimitiveGrouping.STRING_GROUP, PrimitiveGrouping.VOID_GROUP); |
| PrimitiveCategory inputType = ((PrimitiveObjectInspector) arguments[idx]).getPrimitiveCategory(); |
| if (arguments[idx] instanceof ConstantObjectInspector && idx != 0) { |
| Object constValue = ((ConstantObjectInspector) arguments[idx]).getWritableConstantValue(); |
| if (!isConstantNullPatternContain && constValue == null) { |
| isConstantNullPatternContain = true; |
| } |
| } else if (idx != 0 && isAllPatternsConstant) { |
| isAllPatternsConstant = false; |
| } |
| converters[idx] = ObjectInspectorConverters.getConverter(arguments[idx], getOutputOI(inputType)); |
| inputTypes[idx] = inputType; |
| } |
| return PrimitiveObjectInspectorFactory.writableBooleanObjectInspector; |
| } |
| |
| @Override |
| public Object evaluate(DeferredObject[] arguments) throws HiveException { |
| bw.set(false); |
| |
| /**If field value or any constant string pattern value is null then return null*/ |
| if (arguments[0].get() == null || isConstantNullPatternContain) { |
| return null; |
| } |
| |
| /**If all patterns are constant string and no pattern have null value the do short circuit boolean check |
| * Else evaluate all patterns if any pattern contains null value then return null otherwise at last return matching result |
| * */ |
| Text columnValue = (Text) converters[0].convert(arguments[0].get()); |
| Text pattern = new Text(); |
| UDFLike likeUdf = new UDFLike(); |
| for (int idx = 1; idx < arguments.length; idx++) { |
| if (arguments[idx].get() == null) { |
| return null; |
| } |
| pattern.set(converters[idx].convert(arguments[idx].get()).toString()); |
| if (likeUdf.evaluate(columnValue, pattern).get() && !bw.get()) { |
| bw.set(true); |
| if (isAllPatternsConstant) { |
| return bw; |
| } |
| } |
| } |
| return bw; |
| } |
| |
| @Override |
| public String getDisplayString(String[] children) { |
| return getStandardDisplayString("likeany", children); |
| } |
| |
| private ObjectInspector getOutputOI(PrimitiveCategory inputType) { |
| switch (inputType) { |
| case CHAR: |
| case STRING: |
| case VARCHAR: |
| return PrimitiveObjectInspectorFactory.writableStringObjectInspector; |
| case VOID: |
| return PrimitiveObjectInspectorFactory.writableVoidObjectInspector; |
| default: |
| break; |
| } |
| return null; |
| } |
| } |