org.apache.hadoop.hive.ql.plan.ExprNodeGenericFuncDesc.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hive.ql.plan.ExprNodeGenericFuncDesc.java

Source

/*
 * 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.plan;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.collections.Bag;
import org.apache.commons.collections.bag.TreeBag;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ImmutableSortedMultiset;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.conf.HiveConf.StrictChecks;
import org.apache.hadoop.hive.ql.exec.FunctionRegistry;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.Utilities;
import org.apache.hadoop.hive.ql.session.SessionState;
import org.apache.hadoop.hive.ql.session.SessionState.LogHelper;
import org.apache.hadoop.hive.ql.udf.UDFType;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDFBaseCompare;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDFBridge;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDFMacro;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils;

/**
 * Describes a GenericFunc node.
 */
public class ExprNodeGenericFuncDesc extends ExprNodeDesc implements Serializable {

    private static final long serialVersionUID = 1L;

    private static final Logger LOG = LoggerFactory.getLogger(ExprNodeGenericFuncDesc.class.getName());

    /**
     * In case genericUDF is Serializable, we will serialize the object.
     *
     * In case genericUDF does not implement Serializable, Java will remember the
     * class of genericUDF and creates a new instance when deserialized. This is
     * exactly what we want.
     */
    private GenericUDF genericUDF;
    private List<ExprNodeDesc> chidren;
    private transient String funcText;
    /**
     * This class uses a writableObjectInspector rather than a TypeInfo to store
     * the canonical type information for this NodeDesc.
     */
    private transient ObjectInspector writableObjectInspector;
    //Is this an expression that should perform a comparison for sorted searches
    private boolean isSortedExpr;

    public ExprNodeGenericFuncDesc() {
        ;
    }

    /* If the function has an explicit name like func(args) then call a
     * constructor that explicitly provides the function name in the
     * funcText argument.
     */
    public ExprNodeGenericFuncDesc(TypeInfo typeInfo, GenericUDF genericUDF, String funcText,
            List<ExprNodeDesc> children) {
        this(TypeInfoUtils.getStandardWritableObjectInspectorFromTypeInfo(typeInfo), genericUDF, funcText,
                children);
    }

    public ExprNodeGenericFuncDesc(ObjectInspector oi, GenericUDF genericUDF, String funcText,
            List<ExprNodeDesc> children) {
        super(TypeInfoUtils.getTypeInfoFromObjectInspector(oi));
        this.writableObjectInspector = ObjectInspectorUtils.getWritableObjectInspector(oi);
        assert (genericUDF != null);
        this.genericUDF = genericUDF;
        this.chidren = children;
        this.funcText = funcText;
    }

    // Backward-compatibility interfaces for functions without a user-visible name.
    public ExprNodeGenericFuncDesc(TypeInfo typeInfo, GenericUDF genericUDF, List<ExprNodeDesc> children) {
        this(typeInfo, genericUDF, null, children);
    }

    public ExprNodeGenericFuncDesc(ObjectInspector oi, GenericUDF genericUDF, List<ExprNodeDesc> children) {
        this(oi, genericUDF, null, children);
    }

    @Override
    public ObjectInspector getWritableObjectInspector() {
        return writableObjectInspector;
    }

    public GenericUDF getGenericUDF() {
        return genericUDF;
    }

    public void setGenericUDF(GenericUDF genericUDF) {
        this.genericUDF = genericUDF;
    }

    public void setChildren(List<ExprNodeDesc> children) {
        chidren = children;
    }

    @Override
    public List<ExprNodeDesc> getChildren() {
        return chidren;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(genericUDF.getClass().getSimpleName());
        if (genericUDF instanceof GenericUDFBridge) {
            GenericUDFBridge genericUDFBridge = (GenericUDFBridge) genericUDF;
            sb.append(" ==> ");
            String udfName = genericUDFBridge.getUdfName();
            Class<? extends UDF> udfClass = genericUDFBridge.getUdfClass();
            sb.append(udfName != null ? udfName : (udfClass != null ? udfClass.getSimpleName() : "null"));
            sb.append(" ");
        }
        sb.append("(");
        if (chidren != null) {
            for (int i = 0; i < chidren.size(); i++) {
                if (i > 0) {
                    sb.append(", ");
                }
                sb.append(chidren.get(i));
            }
        }
        sb.append(")");
        return sb.toString();
    }

    @Override
    public String getExprString() {
        // Get the children expr strings
        String[] childrenExprStrings = new String[chidren.size()];
        for (int i = 0; i < childrenExprStrings.length; i++) {
            childrenExprStrings[i] = chidren.get(i).getExprString();
        }

        return genericUDF.getDisplayString(childrenExprStrings);
    }

    @Override
    public String getExprString(boolean sortChildren) {
        if (sortChildren) {
            UDFType udfType = genericUDF.getClass().getAnnotation(UDFType.class);
            if (udfType.commutative()) {
                // Get the sorted children expr strings
                String[] childrenExprStrings = new String[chidren.size()];
                for (int i = 0; i < childrenExprStrings.length; i++) {
                    childrenExprStrings[i] = chidren.get(i).getExprString();
                }
                return genericUDF.getDisplayString(ImmutableSortedMultiset.copyOf(childrenExprStrings)
                        .toArray(new String[childrenExprStrings.length]));
            }
        }
        return getExprString();
    }

    @Override
    public List<String> getCols() {
        List<String> colList = new ArrayList<String>();
        if (chidren != null) {
            int pos = 0;
            while (pos < chidren.size()) {
                List<String> colCh = chidren.get(pos).getCols();
                colList = Utilities.mergeUniqElems(colList, colCh);
                pos++;
            }
        }

        return colList;
    }

    @Override
    public ExprNodeDesc clone() {
        List<ExprNodeDesc> cloneCh = new ArrayList<ExprNodeDesc>(chidren.size());
        for (ExprNodeDesc ch : chidren) {
            cloneCh.add(ch.clone());
        }
        ExprNodeGenericFuncDesc clone = new ExprNodeGenericFuncDesc(typeInfo,
                FunctionRegistry.cloneGenericUDF(genericUDF), funcText, cloneCh);
        return clone;
    }

    /**
     * Create a ExprNodeGenericFuncDesc based on the genericUDFClass and the
     * children parameters. If the function has an explicit name, the
     * newInstance method should be passed the function name in the funcText
     * argument.
     *
     * @throws UDFArgumentException
     */
    public static ExprNodeGenericFuncDesc newInstance(GenericUDF genericUDF, String funcText,
            List<ExprNodeDesc> children) throws UDFArgumentException {
        ObjectInspector[] childrenOIs = new ObjectInspector[children.size()];
        for (int i = 0; i < childrenOIs.length; i++) {
            childrenOIs[i] = children.get(i).getWritableObjectInspector();
        }

        // Check if a bigint is implicitely cast to a double as part of a comparison
        // Perform the check here instead of in GenericUDFBaseCompare to guarantee it is only run once per operator
        if (genericUDF instanceof GenericUDFBaseCompare && children.size() == 2) {

            TypeInfo oiTypeInfo0 = children.get(0).getTypeInfo();
            TypeInfo oiTypeInfo1 = children.get(1).getTypeInfo();

            SessionState ss = SessionState.get();
            Configuration conf = (ss != null) ? ss.getConf() : new Configuration();

            LogHelper console = new LogHelper(LOG);

            // For now, if a bigint is going to be cast to a double throw an error or warning
            if ((oiTypeInfo0.equals(TypeInfoFactory.stringTypeInfo)
                    && oiTypeInfo1.equals(TypeInfoFactory.longTypeInfo))
                    || (oiTypeInfo0.equals(TypeInfoFactory.longTypeInfo)
                            && oiTypeInfo1.equals(TypeInfoFactory.stringTypeInfo))) {
                String error = StrictChecks.checkTypeSafety(conf);
                if (error != null)
                    throw new UDFArgumentException(error);
                console.printError("WARNING: Comparing a bigint and a string may result in a loss of precision.");
            } else if ((oiTypeInfo0.equals(TypeInfoFactory.doubleTypeInfo)
                    && oiTypeInfo1.equals(TypeInfoFactory.longTypeInfo))
                    || (oiTypeInfo0.equals(TypeInfoFactory.longTypeInfo)
                            && oiTypeInfo1.equals(TypeInfoFactory.doubleTypeInfo))) {
                console.printError("WARNING: Comparing a bigint and a double may result in a loss of precision.");
            }
        }

        ObjectInspector oi = genericUDF.initializeAndFoldConstants(childrenOIs);

        String[] requiredJars = genericUDF.getRequiredJars();
        String[] requiredFiles = genericUDF.getRequiredFiles();
        SessionState ss = SessionState.get();

        if (requiredJars != null) {
            SessionState.ResourceType t = SessionState.find_resource_type("JAR");
            try {
                ss.add_resources(t, Arrays.asList(requiredJars));
            } catch (Exception e) {
                throw new UDFArgumentException(e);
            }
        }

        if (requiredFiles != null) {
            SessionState.ResourceType t = SessionState.find_resource_type("FILE");
            try {
                ss.add_resources(t, Arrays.asList(requiredFiles));
            } catch (Exception e) {
                throw new UDFArgumentException(e);
            }
        }

        return new ExprNodeGenericFuncDesc(oi, genericUDF, funcText, children);
    }

    /* Backward-compatibility interface for the case where there is no explicit
     * name for the function.
     */
    public static ExprNodeGenericFuncDesc newInstance(GenericUDF genericUDF, List<ExprNodeDesc> children)
            throws UDFArgumentException {
        return newInstance(genericUDF, null, children);
    }

    @Override
    public boolean isSame(Object o) {
        if (!(o instanceof ExprNodeGenericFuncDesc)) {
            return false;
        }
        ExprNodeGenericFuncDesc dest = (ExprNodeGenericFuncDesc) o;
        if (!typeInfo.equals(dest.getTypeInfo())
                || !genericUDF.getClass().equals(dest.getGenericUDF().getClass())) {
            return false;
        }

        if (genericUDF instanceof GenericUDFBridge) {
            GenericUDFBridge bridge = (GenericUDFBridge) genericUDF;
            GenericUDFBridge bridge2 = (GenericUDFBridge) dest.getGenericUDF();
            if (!bridge.getUdfClassName().equals(bridge2.getUdfClassName())
                    || !bridge.getUdfName().equals(bridge2.getUdfName())
                    || bridge.isOperator() != bridge2.isOperator()) {
                return false;
            }
        }

        if (genericUDF instanceof GenericUDFMacro) {
            // if getMacroName is null, we always treat it different from others.
            if (((GenericUDFMacro) genericUDF).getMacroName() == null || !(((GenericUDFMacro) genericUDF)
                    .getMacroName().equals(((GenericUDFMacro) dest.genericUDF).getMacroName()))) {
                return false;
            }
        }

        if (chidren.size() != dest.getChildren().size()) {
            return false;
        }

        for (int pos = 0; pos < chidren.size(); pos++) {
            if (!chidren.get(pos).isSame(dest.getChildren().get(pos))) {
                return false;
            }
        }

        return true;
    }

    @Override
    public int hashCode() {
        int superHashCode = super.hashCode();
        HashCodeBuilder builder = new HashCodeBuilder();
        builder.appendSuper(superHashCode);
        builder.append(chidren);
        return builder.toHashCode();
    }

    public boolean isSortedExpr() {
        return isSortedExpr;
    }

    public void setSortedExpr(boolean isSortedExpr) {
        this.isSortedExpr = isSortedExpr;
    }

    public String getFuncText() {
        return this.funcText;
    }
}