| // 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.impala.analysis; |
| |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.impala.catalog.Function; |
| import org.apache.impala.catalog.PrimitiveType; |
| import org.apache.impala.catalog.ScalarFunction; |
| import org.apache.impala.catalog.Type; |
| import org.apache.impala.common.AnalysisException; |
| import org.apache.impala.hive.executor.UdfExecutor.JavaUdfDataType; |
| import org.apache.impala.thrift.TFunctionBinaryType; |
| import org.apache.impala.thrift.TSymbolType; |
| |
| import com.google.common.base.Preconditions; |
| |
| /** |
| * Represents a CREATE FUNCTION statement. |
| */ |
| public class CreateUdfStmt extends CreateFunctionStmtBase { |
| /** |
| * Builds a CREATE FUNCTION statement |
| * @param fnName - Name of the function |
| * @param fnArgs - List of types for the arguments to this function |
| * @param retType - The type this function returns. |
| * @param location - Path in HDFS containing the UDA. |
| * @param ifNotExists - If true, no errors are thrown if the function already exists |
| * @param additionalArgs - Key/Value pairs for additional arguments. The keys are |
| * validated in analyze() |
| */ |
| public CreateUdfStmt(FunctionName fnName, FunctionArgs args, |
| TypeDef retTypeDef, HdfsUri location, boolean ifNotExists, |
| Map<CreateFunctionStmtBase.OptArg, String> optArgs) { |
| super(fnName, args, retTypeDef, location, ifNotExists, optArgs); |
| } |
| |
| @Override |
| public void analyze(Analyzer analyzer) throws AnalysisException { |
| super.analyze(analyzer); |
| Preconditions.checkNotNull(fn_); |
| Preconditions.checkState(fn_ instanceof ScalarFunction); |
| ScalarFunction udf = (ScalarFunction) fn_; |
| |
| if (hasSignature()) { |
| if (udf.getBinaryType() == TFunctionBinaryType.JAVA) { |
| if (!JavaUdfDataType.isSupported(udf.getReturnType())) { |
| throw new AnalysisException( |
| "Type " + udf.getReturnType().toSql() + " is not supported for Java UDFs."); |
| } |
| for (int i = 0; i < udf.getNumArgs(); ++i) { |
| if (!JavaUdfDataType.isSupported(udf.getArgs()[i])) { |
| throw new AnalysisException( |
| "Type " + udf.getArgs()[i].toSql() + " is not supported for Java UDFs."); |
| } |
| } |
| } |
| |
| if (udf.getReturnType().getPrimitiveType() == PrimitiveType.CHAR) { |
| throw new AnalysisException("UDFs that use CHAR are not yet supported."); |
| } |
| if (udf.getReturnType().getPrimitiveType() == PrimitiveType.VARCHAR) { |
| throw new AnalysisException("UDFs that use VARCHAR are not yet supported."); |
| } |
| for (int i = 0; i < udf.getNumArgs(); ++i) { |
| if (udf.getArgs()[i].getPrimitiveType() == PrimitiveType.CHAR) { |
| throw new AnalysisException("UDFs that use CHAR are not yet supported."); |
| } |
| if (udf.getArgs()[i].getPrimitiveType() == PrimitiveType.VARCHAR) { |
| throw new AnalysisException("UDFs that use VARCHAR are not yet supported."); |
| } |
| } |
| } |
| |
| // Check the user provided symbol exists |
| udf.setSymbolName(udf.lookupSymbol( |
| checkAndGetOptArg(OptArg.SYMBOL), TSymbolType.UDF_EVALUATE, null, |
| udf.hasVarArgs(), udf.getArgs())); |
| |
| // Set optional Prepare/Close functions |
| String prepareFn = optArgs_.get(OptArg.PREPARE_FN); |
| if (prepareFn != null) { |
| udf.setPrepareFnSymbol(udf.lookupSymbol(prepareFn, TSymbolType.UDF_PREPARE)); |
| } |
| String closeFn = optArgs_.get(OptArg.CLOSE_FN); |
| if (closeFn != null) { |
| udf.setCloseFnSymbol(udf.lookupSymbol(closeFn, TSymbolType.UDF_CLOSE)); |
| } |
| |
| // Udfs should not set any of these |
| checkOptArgNotSet(OptArg.UPDATE_FN); |
| checkOptArgNotSet(OptArg.INIT_FN); |
| checkOptArgNotSet(OptArg.SERIALIZE_FN); |
| checkOptArgNotSet(OptArg.MERGE_FN); |
| checkOptArgNotSet(OptArg.FINALIZE_FN); |
| |
| sqlString_ = udf.toSql(ifNotExists_); |
| |
| // Check that there is no function with the same name and isPersistent field not |
| // the same as udf.isPersistent_. For example we don't allow two JAVA udfs with |
| // same name and opposite persistence values set. This only applies for JAVA udfs |
| // as all the native udfs are persisted. Additionally we don't throw exceptions |
| // if "IF NOT EXISTS" is specified in the query. |
| if (udf.getBinaryType() != TFunctionBinaryType.JAVA || ifNotExists_) return; |
| |
| Preconditions.checkNotNull(db_); |
| for (Function fn: db_.getFunctions(udf.functionName())) { |
| if (!hasSignature() || (hasSignature() && fn.isPersistent())) { |
| throw new AnalysisException( |
| String.format(Analyzer.FN_ALREADY_EXISTS_ERROR_MSG + |
| fn.signatureString())); |
| } |
| } |
| } |
| |
| @Override |
| protected Function createFunction(FunctionName fnName, List<Type> argTypes, |
| Type retType, boolean hasVarArgs) { |
| return new ScalarFunction(fnName, argTypes, retType, hasVarArgs); |
| } |
| } |