blob: f2f54a685039005159a2d8ee1760b1d8b258f62a [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.calcite.sql;
import org.apache.calcite.sql.type.OperandHandlers;
import org.apache.calcite.sql.type.SqlOperandHandler;
import org.apache.calcite.sql.type.SqlOperandTypeChecker;
import org.apache.calcite.sql.type.SqlOperandTypeInference;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
import org.apache.calcite.sql.validate.SqlMonotonicity;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.function.Function;
import static java.util.Objects.requireNonNull;
/**
* Concrete implementation of {@link SqlFunction}.
*
* <p>The class is final, and instances are immutable.
*
* <p>Instances are created only by {@link SqlBasicFunction#create} and are
* "modified" by "wither" methods such as {@link #withName} to create a new
* instance with one property changed. Since the class is final, you can modify
* behavior only by providing strategy objects, not by overriding methods in a
* subclass.
*/
public class SqlBasicFunction extends SqlFunction {
private final SqlSyntax syntax;
private final boolean deterministic;
private final SqlOperandHandler operandHandler;
private final int callValidator;
private final Function<SqlOperatorBinding, SqlMonotonicity> monotonicityInference;
private final boolean dynamic;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new SqlFunction for a call to a built-in function.
*
* @param name Name of built-in function
* @param kind Kind of operator implemented by function
* @param syntax Syntax
* @param deterministic Whether the function is deterministic
* @param returnTypeInference Strategy to use for return type inference
* @param operandTypeInference Strategy to use for parameter type inference
* @param operandHandler Strategy to use for handling operands
* @param operandTypeChecker Strategy to use for parameter type checking
* @param callValidator Strategy to validate calls
* @param category Categorization for function
* @param monotonicityInference Strategy to infer monotonicity of a call
*/
private SqlBasicFunction(String name, SqlKind kind, SqlSyntax syntax,
boolean deterministic, SqlReturnTypeInference returnTypeInference,
@Nullable SqlOperandTypeInference operandTypeInference,
SqlOperandHandler operandHandler,
SqlOperandTypeChecker operandTypeChecker,
Integer callValidator,
SqlFunctionCategory category,
Function<SqlOperatorBinding, SqlMonotonicity> monotonicityInference,
boolean dynamic) {
super(name, kind,
requireNonNull(returnTypeInference, "returnTypeInference"),
operandTypeInference,
requireNonNull(operandTypeChecker, "operandTypeChecker"), category);
this.syntax = requireNonNull(syntax, "syntax");
this.deterministic = deterministic;
this.operandHandler = requireNonNull(operandHandler, "operandHandler");
this.callValidator = requireNonNull(callValidator, "callValidator");
this.monotonicityInference =
requireNonNull(monotonicityInference, "monotonicityInference");
this.dynamic = dynamic;
}
/** Creates a {@code SqlBasicFunction} whose name is the same as its kind
* and whose category {@link SqlFunctionCategory#SYSTEM}. */
public static SqlBasicFunction create(SqlKind kind,
SqlReturnTypeInference returnTypeInference,
SqlOperandTypeChecker operandTypeChecker) {
return new SqlBasicFunction(kind.name(), kind,
SqlSyntax.FUNCTION, true, returnTypeInference, null,
OperandHandlers.DEFAULT, operandTypeChecker, 0,
SqlFunctionCategory.SYSTEM, call -> SqlMonotonicity.NOT_MONOTONIC, false);
}
/** Creates a {@code SqlBasicFunction}
* with kind {@link SqlKind#OTHER_FUNCTION}
* and category {@link SqlFunctionCategory#NUMERIC}. */
public static SqlBasicFunction create(String name,
SqlReturnTypeInference returnTypeInference,
SqlOperandTypeChecker operandTypeChecker) {
return new SqlBasicFunction(name, SqlKind.OTHER_FUNCTION,
SqlSyntax.FUNCTION, true, returnTypeInference, null,
OperandHandlers.DEFAULT, operandTypeChecker, 0,
SqlFunctionCategory.NUMERIC, call -> SqlMonotonicity.NOT_MONOTONIC, false);
}
/** Creates a {@code SqlBasicFunction}
* with kind {@link SqlKind#OTHER_FUNCTION}. */
public static SqlBasicFunction create(String name,
SqlReturnTypeInference returnTypeInference,
SqlOperandTypeChecker operandTypeChecker, SqlFunctionCategory category) {
return new SqlBasicFunction(name, SqlKind.OTHER_FUNCTION,
SqlSyntax.FUNCTION, true, returnTypeInference, null,
OperandHandlers.DEFAULT, operandTypeChecker, 0,
category, call -> SqlMonotonicity.NOT_MONOTONIC, false);
}
//~ Methods ----------------------------------------------------------------
@Override public SqlReturnTypeInference getReturnTypeInference() {
return requireNonNull(super.getReturnTypeInference(), "returnTypeInference");
}
@Override public SqlOperandTypeChecker getOperandTypeChecker() {
return requireNonNull(super.getOperandTypeChecker(), "operandTypeChecker");
}
@Override public SqlSyntax getSyntax() {
return syntax;
}
@Override public boolean isDeterministic() {
return deterministic;
}
@Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
return monotonicityInference.apply(call);
}
@Override public SqlNode rewriteCall(SqlValidator validator, SqlCall call) {
return operandHandler.rewriteCall(validator, call);
}
@Override public void validateCall(SqlCall call, SqlValidator validator,
SqlValidatorScope scope, SqlValidatorScope operandScope) {
super.validateCall(call, validator, scope, operandScope);
}
@Override public boolean isDynamicFunction() {
return dynamic;
}
/** Returns a copy of this function with a given name. */
public SqlBasicFunction withName(String name) {
return new SqlBasicFunction(name, kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given kind. */
public SqlBasicFunction withKind(SqlKind kind) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given category. */
public SqlBasicFunction withFunctionType(SqlFunctionCategory category) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator, category, monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given syntax. */
public SqlBasicFunction withSyntax(SqlSyntax syntax) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given strategy for inferring
* returned type. */
public SqlBasicFunction withReturnTypeInference(
SqlReturnTypeInference returnTypeInference) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
returnTypeInference, getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given strategy for inferring
* the types of its operands. */
public SqlBasicFunction withOperandTypeInference(
SqlOperandTypeInference operandTypeInference) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), operandTypeInference, operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given strategy for handling
* operands. */
public SqlBasicFunction withOperandHandler(SqlOperandHandler operandHandler) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given determinism. */
public SqlBasicFunction withDeterministic(boolean deterministic) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given strategy for inferring
* whether a call is monotonic. */
public SqlBasicFunction withMonotonicityInference(
Function<SqlOperatorBinding, SqlMonotonicity> monotonicityInference) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
public SqlBasicFunction withValidation(int callValidator) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
public SqlBasicFunction withDynamic(boolean dynamic) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
public SqlBasicFunction withOperandTypeChecker(SqlOperandTypeChecker operandTypeChecker) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
operandTypeChecker, callValidator,
getFunctionType(), monotonicityInference, dynamic);
}
}