blob: a488ed083daadeb75655ddbd19fe10c8ce20a040 [file] [log] [blame]
// 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);
}
}