com.hazelcast.org.apache.calcite.sql.SqlOperator Maven / Gradle / Ivy
/*
* 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 com.hazelcast.org.apache.calcite.sql;
import com.hazelcast.org.apache.calcite.linq4j.Ord;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeFactory;
import com.hazelcast.org.apache.calcite.sql.fun.SqlStdOperatorTable;
import com.hazelcast.org.apache.calcite.sql.parser.SqlParserPos;
import com.hazelcast.org.apache.calcite.sql.type.SqlOperandTypeChecker;
import com.hazelcast.org.apache.calcite.sql.type.SqlOperandTypeInference;
import com.hazelcast.org.apache.calcite.sql.type.SqlReturnTypeInference;
import com.hazelcast.org.apache.calcite.sql.type.SqlTypeName;
import com.hazelcast.org.apache.calcite.sql.util.SqlBasicVisitor;
import com.hazelcast.org.apache.calcite.sql.util.SqlVisitor;
import com.hazelcast.org.apache.calcite.sql.validate.SqlMonotonicity;
import com.hazelcast.org.apache.calcite.sql.validate.SqlValidator;
import com.hazelcast.org.apache.calcite.sql.validate.SqlValidatorImpl;
import com.hazelcast.org.apache.calcite.sql.validate.SqlValidatorScope;
import com.hazelcast.org.apache.calcite.sql.validate.SqlValidatorUtil;
import com.hazelcast.org.apache.calcite.util.Litmus;
import com.hazelcast.org.apache.calcite.util.Util;
import com.hazelcast.com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import static com.hazelcast.org.apache.calcite.util.Static.RESOURCE;
/**
* A SqlOperator
is a type of node in a SQL parse tree (it is NOT a
* node in a SQL parse tree). It includes functions, operators such as '=', and
* syntactic constructs such as 'case' statements. Operators may represent
* query-level expressions (e.g. {@link SqlSelectOperator} or row-level
* expressions (e.g. {@link com.hazelcast.org.apache.calcite.sql.fun.SqlBetweenOperator}.
*
* Operators have formal operands, meaning ordered (and optionally
* named) placeholders for the values they operate on. For example, the division
* operator takes two operands; the first is the numerator and the second is the
* denominator. In the context of subclass {@link SqlFunction}, formal operands
* are referred to as parameters.
*
*
When an operator is instantiated via a {@link SqlCall}, it is supplied
* with actual operands. For example, in the expression 3 /
* 5
, the literal expression 3
is the actual operand
* corresponding to the numerator, and 5
is the actual operand
* corresponding to the denominator. In the context of SqlFunction, actual
* operands are referred to as arguments
*
*
In many cases, the formal/actual distinction is clear from context, in
* which case we drop these qualifiers.
*/
public abstract class SqlOperator {
//~ Static fields/initializers ---------------------------------------------
public static final String NL = System.getProperty("line.separator");
/**
* Maximum precedence.
*/
public static final int MDX_PRECEDENCE = 200;
//~ Instance fields --------------------------------------------------------
/**
* The name of the operator/function. Ex. "OVERLAY" or "TRIM"
*/
private final String name;
/**
* See {@link SqlKind}. It's possible to have a name that doesn't match the
* kind
*/
public final SqlKind kind;
/**
* The precedence with which this operator binds to the expression to the
* left. This is less than the right precedence if the operator is
* left-associative.
*/
private final int leftPrec;
/**
* The precedence with which this operator binds to the expression to the
* right. This is more than the left precedence if the operator is
* left-associative.
*/
private final int rightPrec;
/**
* used to infer the return type of a call to this operator
*/
private final SqlReturnTypeInference returnTypeInference;
/**
* used to infer types of unknown operands
*/
private final SqlOperandTypeInference operandTypeInference;
/**
* used to validate operand types
*/
private final SqlOperandTypeChecker operandTypeChecker;
//~ Constructors -----------------------------------------------------------
/**
* Creates an operator.
*/
protected SqlOperator(
String name,
SqlKind kind,
int leftPrecedence,
int rightPrecedence,
SqlReturnTypeInference returnTypeInference,
SqlOperandTypeInference operandTypeInference,
SqlOperandTypeChecker operandTypeChecker) {
assert kind != null;
this.name = name;
this.kind = kind;
this.leftPrec = leftPrecedence;
this.rightPrec = rightPrecedence;
this.returnTypeInference = returnTypeInference;
this.operandTypeInference = operandTypeInference;
this.operandTypeChecker = operandTypeChecker;
}
/**
* Creates an operator specifying left/right associativity.
*/
protected SqlOperator(
String name,
SqlKind kind,
int prec,
boolean leftAssoc,
SqlReturnTypeInference returnTypeInference,
SqlOperandTypeInference operandTypeInference,
SqlOperandTypeChecker operandTypeChecker) {
this(
name,
kind,
leftPrec(prec, leftAssoc),
rightPrec(prec, leftAssoc),
returnTypeInference,
operandTypeInference,
operandTypeChecker);
}
//~ Methods ----------------------------------------------------------------
protected static int leftPrec(int prec, boolean leftAssoc) {
assert (prec % 2) == 0;
if (!leftAssoc) {
++prec;
}
return prec;
}
protected static int rightPrec(int prec, boolean leftAssoc) {
assert (prec % 2) == 0;
if (leftAssoc) {
++prec;
}
return prec;
}
public SqlOperandTypeChecker getOperandTypeChecker() {
return operandTypeChecker;
}
/**
* Returns a constraint on the number of operands expected by this operator.
* Subclasses may override this method; when they don't, the range is
* derived from the {@link SqlOperandTypeChecker} associated with this
* operator.
*
* @return acceptable range
*/
public SqlOperandCountRange getOperandCountRange() {
if (operandTypeChecker != null) {
return operandTypeChecker.getOperandCountRange();
}
// If you see this error you need to override this method
// or give operandTypeChecker a value.
throw Util.needToImplement(this);
}
public String getName() {
return name;
}
/**
* Returns the fully-qualified name of this operator.
*/
public SqlIdentifier getNameAsId() {
return new SqlIdentifier(getName(), SqlParserPos.ZERO);
}
public SqlKind getKind() {
return kind;
}
public String toString() {
return name;
}
public int getLeftPrec() {
return leftPrec;
}
public int getRightPrec() {
return rightPrec;
}
/**
* Returns the syntactic type of this operator, never null.
*/
public abstract SqlSyntax getSyntax();
/**
* Creates a call to this operand with an array of operands.
*
*
The position of the resulting call is the union of the
* pos
and the positions of all of the operands.
*
* @param functionQualifier function qualifier (e.g. "DISTINCT"), may be
* @param pos parser position of the identifier of the call
* @param operands array of operands
*/
public SqlCall createCall(
SqlLiteral functionQualifier,
SqlParserPos pos,
SqlNode... operands) {
pos = pos.plusAll(Arrays.asList(operands));
return new SqlBasicCall(this, operands, pos, false, functionQualifier);
}
/**
* Creates a call to this operand with an array of operands.
*
*
The position of the resulting call is the union of the
* pos
and the positions of all of the operands.
*
* @param pos Parser position
* @param operands List of arguments
* @return call to this operator
*/
public final SqlCall createCall(
SqlParserPos pos,
SqlNode... operands) {
return createCall(null, pos, operands);
}
/**
* Creates a call to this operand with a list of operands contained in a
* {@link SqlNodeList}.
*
*
The position of the resulting call inferred from the SqlNodeList.
*
* @param nodeList List of arguments
* @return call to this operator
*/
public final SqlCall createCall(
SqlNodeList nodeList) {
return createCall(
null,
nodeList.getParserPosition(),
nodeList.toArray());
}
/**
* Creates a call to this operand with a list of operands.
*
*
The position of the resulting call is the union of the
* pos
and the positions of all of the operands.
*/
public final SqlCall createCall(
SqlParserPos pos,
List extends SqlNode> operandList) {
return createCall(
null,
pos,
operandList.toArray(new SqlNode[0]));
}
/**
* Rewrites a call to this operator. Some operators are implemented as
* trivial rewrites (e.g. NULLIF becomes CASE). However, we don't do this at
* createCall time because we want to preserve the original SQL syntax as
* much as possible; instead, we do this before the call is validated (so
* the trivial operator doesn't need its own implementation of type
* derivation methods). The default implementation is to just return the
* original call without any rewrite.
*
* @param validator Validator
* @param call Call to be rewritten
* @return rewritten call
*/
public SqlNode rewriteCall(SqlValidator validator, SqlCall call) {
return call;
}
/**
* Writes a SQL representation of a call to this operator to a writer,
* including parentheses if the operators on either side are of greater
* precedence.
*
*
The default implementation of this method delegates to
* {@link SqlSyntax#unparse}.
*/
public void unparse(
SqlWriter writer,
SqlCall call,
int leftPrec,
int rightPrec) {
getSyntax().unparse(writer, this, call, leftPrec, rightPrec);
}
@Deprecated // to be removed before 2.0
protected void unparseListClause(SqlWriter writer, SqlNode clause) {
final SqlNodeList nodeList =
clause instanceof SqlNodeList
? (SqlNodeList) clause
: SqlNodeList.of(clause);
writer.list(SqlWriter.FrameTypeEnum.SIMPLE, SqlWriter.COMMA, nodeList);
}
@Deprecated // to be removed before 2.0
protected void unparseListClause(
SqlWriter writer,
SqlNode clause,
SqlKind sepKind) {
final SqlNodeList nodeList =
clause instanceof SqlNodeList
? (SqlNodeList) clause
: SqlNodeList.of(clause);
final SqlBinaryOperator sepOp;
if (sepKind == null) {
sepOp = SqlWriter.COMMA;
} else {
switch (sepKind) {
case AND:
sepOp = SqlStdOperatorTable.AND;
break;
case OR:
sepOp = SqlStdOperatorTable.OR;
break;
default:
throw new AssertionError();
}
}
writer.list(SqlWriter.FrameTypeEnum.SIMPLE, sepOp, nodeList);
}
// override Object
public boolean equals(Object obj) {
if (!(obj instanceof SqlOperator)) {
return false;
}
if (!obj.getClass().equals(this.getClass())) {
return false;
}
SqlOperator other = (SqlOperator) obj;
return name.equals(other.name) && kind == other.kind;
}
public boolean isName(String testName, boolean caseSensitive) {
return caseSensitive ? name.equals(testName) : name.equalsIgnoreCase(testName);
}
@Override public int hashCode() {
return Objects.hash(kind, name);
}
/**
* Validates a call to this operator.
*
*
This method should not perform type-derivation or perform validation
* related related to types. That is done later, by
* {@link #deriveType(SqlValidator, SqlValidatorScope, SqlCall)}. This method
* should focus on structural validation.
*
*
A typical implementation of this method first validates the operands,
* then performs some operator-specific logic. The default implementation
* just validates the operands.
*
*
This method is the default implementation of {@link SqlCall#validate};
* but note that some sub-classes of {@link SqlCall} never call this method.
*
* @param call the call to this operator
* @param validator the active validator
* @param scope validator scope
* @param operandScope validator scope in which to validate operands to this
* call; usually equal to scope, but not always because
* some operators introduce new scopes
* @see SqlNode#validateExpr(SqlValidator, SqlValidatorScope)
* @see #deriveType(SqlValidator, SqlValidatorScope, SqlCall)
*/
public void validateCall(
SqlCall call,
SqlValidator validator,
SqlValidatorScope scope,
SqlValidatorScope operandScope) {
assert call.getOperator() == this;
for (SqlNode operand : call.getOperandList()) {
operand.validateExpr(validator, operandScope);
}
}
/**
* Validates the operands of a call, inferring the return type in the
* process.
*
* @param validator active validator
* @param scope validation scope
* @param call call to be validated
* @return inferred type
*/
public final RelDataType validateOperands(
SqlValidator validator,
SqlValidatorScope scope,
SqlCall call) {
// Let subclasses know what's up.
preValidateCall(validator, scope, call);
// Check the number of operands
checkOperandCount(validator, operandTypeChecker, call);
SqlCallBinding opBinding = new SqlCallBinding(validator, scope, call);
checkOperandTypes(
opBinding,
true);
// Now infer the result type.
RelDataType ret = inferReturnType(opBinding);
((SqlValidatorImpl) validator).setValidatedNodeType(call, ret);
return ret;
}
/**
* Receives notification that validation of a call to this operator is
* beginning. Subclasses can supply custom behavior; default implementation
* does nothing.
*
* @param validator invoking validator
* @param scope validation scope
* @param call the call being validated
*/
protected void preValidateCall(
SqlValidator validator,
SqlValidatorScope scope,
SqlCall call) {
}
/**
* Infers the return type of an invocation of this operator; only called
* after the number and types of operands have already been validated.
* Subclasses must either override this method or supply an instance of
* {@link SqlReturnTypeInference} to the constructor.
*
* @param opBinding description of invocation (not necessarily a
* {@link SqlCall})
* @return inferred return type
*/
public RelDataType inferReturnType(
SqlOperatorBinding opBinding) {
if (returnTypeInference != null) {
RelDataType returnType = returnTypeInference.inferReturnType(opBinding);
if (returnType == null) {
throw new IllegalArgumentException("Cannot infer return type for "
+ opBinding.getOperator() + "; operand types: "
+ opBinding.collectOperandTypes());
}
return returnType;
}
// Derived type should have overridden this method, since it didn't
// supply a type inference rule.
throw Util.needToImplement(this);
}
/**
* Derives the type of a call to this operator.
*
*
This method is an intrinsic part of the validation process so, unlike
* {@link #inferReturnType}, specific operators would not typically override
* this method.
*
* @param validator Validator
* @param scope Scope of validation
* @param call Call to this operator
* @return Type of call
*/
public RelDataType deriveType(
SqlValidator validator,
SqlValidatorScope scope,
SqlCall call) {
for (SqlNode operand : call.getOperandList()) {
RelDataType nodeType = validator.deriveType(scope, operand);
assert nodeType != null;
}
final List args = constructOperandList(validator, call, null);
final List argTypes = constructArgTypeList(validator, scope,
call, args, false);
// Always disable type coercion for builtin operator operands,
// they are handled by the TypeCoercion specifically.
final SqlOperator sqlOperator =
SqlUtil.lookupRoutine(validator.getOperatorTable(), getNameAsId(),
argTypes, null, null, getSyntax(), getKind(),
validator.getCatalogReader().nameMatcher(), false);
((SqlBasicCall) call).setOperator(sqlOperator);
RelDataType type = call.getOperator().validateOperands(validator, scope, call);
// Validate and determine coercibility and resulting collation
// name of binary operator if needed.
type = adjustType(validator, call, type);
SqlValidatorUtil.checkCharsetAndCollateConsistentIfCharType(type);
return type;
}
protected List constructArgNameList(SqlCall call) {
// If any arguments are named, construct a map.
final ImmutableList.Builder nameBuilder = ImmutableList.builder();
for (SqlNode operand : call.getOperandList()) {
if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
final List operandList = ((SqlCall) operand).getOperandList();
nameBuilder.add(((SqlIdentifier) operandList.get(1)).getSimple());
}
}
ImmutableList argNames = nameBuilder.build();
if (argNames.isEmpty()) {
return null;
} else {
return argNames;
}
}
protected List constructOperandList(
SqlValidator validator,
SqlCall call,
List argNames) {
if (argNames == null) {
return call.getOperandList();
}
if (argNames.size() < call.getOperandList().size()) {
throw validator.newValidationError(call,
RESOURCE.someButNotAllArgumentsAreNamed());
}
final int duplicate = Util.firstDuplicate(argNames);
if (duplicate >= 0) {
throw validator.newValidationError(call,
RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
}
final ImmutableList.Builder argBuilder = ImmutableList.builder();
for (SqlNode operand : call.getOperandList()) {
if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
final List operandList = ((SqlCall) operand).getOperandList();
argBuilder.add(operandList.get(0));
}
}
return argBuilder.build();
}
protected List constructArgTypeList(
SqlValidator validator,
SqlValidatorScope scope,
SqlCall call,
List args,
boolean convertRowArgToColumnList) {
// Scope for operands. Usually the same as 'scope'.
final SqlValidatorScope operandScope = scope.getOperandScope(call);
final ImmutableList.Builder argTypeBuilder =
ImmutableList.builder();
for (SqlNode operand : args) {
RelDataType nodeType;
// for row arguments that should be converted to ColumnList
// types, set the nodeType to a ColumnList type but defer
// validating the arguments of the row constructor until we know
// for sure that the row argument maps to a ColumnList type
if (operand.getKind() == SqlKind.ROW && convertRowArgToColumnList) {
RelDataTypeFactory typeFactory = validator.getTypeFactory();
nodeType = typeFactory.createSqlType(SqlTypeName.COLUMN_LIST);
((SqlValidatorImpl) validator).setValidatedNodeType(operand, nodeType);
} else {
nodeType = validator.deriveType(operandScope, operand);
}
argTypeBuilder.add(nodeType);
}
return argTypeBuilder.build();
}
/**
* Returns whether this operator should be surrounded by space when
* unparsed.
*
* @return whether this operator should be surrounded by space
*/
boolean needsSpace() {
return true;
}
/**
* Validates and determines coercibility and resulting collation name of
* binary operator if needed.
*/
protected RelDataType adjustType(
SqlValidator validator,
final SqlCall call,
RelDataType type) {
return type;
}
/**
* Infers the type of a call to this operator with a given set of operand
* types. Shorthand for {@link #inferReturnType(SqlOperatorBinding)}.
*/
public final RelDataType inferReturnType(
RelDataTypeFactory typeFactory,
List operandTypes) {
return inferReturnType(
new ExplicitOperatorBinding(
typeFactory,
this,
operandTypes));
}
/**
* Checks that the operand values in a {@link SqlCall} to this operator are
* valid. Subclasses must either override this method or supply an instance
* of {@link SqlOperandTypeChecker} to the constructor.
*
* @param callBinding description of call
* @param throwOnFailure whether to throw an exception if check fails
* (otherwise returns false in that case)
* @return whether check succeeded
*/
public boolean checkOperandTypes(
SqlCallBinding callBinding,
boolean throwOnFailure) {
// Check that all of the operands are of the right type.
if (null == operandTypeChecker) {
// If you see this you must either give operandTypeChecker a value
// or override this method.
throw Util.needToImplement(this);
}
if (kind != SqlKind.ARGUMENT_ASSIGNMENT) {
for (Ord operand : Ord.zip(callBinding.operands())) {
if (operand.e != null
&& operand.e.getKind() == SqlKind.DEFAULT
&& !operandTypeChecker.isOptional(operand.i)) {
throw callBinding.newValidationError(RESOURCE.defaultForOptionalParameter());
}
}
}
return operandTypeChecker.checkOperandTypes(
callBinding,
throwOnFailure);
}
protected void checkOperandCount(
SqlValidator validator,
SqlOperandTypeChecker argType,
SqlCall call) {
SqlOperandCountRange od = call.getOperator().getOperandCountRange();
if (od.isValidCount(call.operandCount())) {
return;
}
if (od.getMin() == od.getMax()) {
throw validator.newValidationError(call,
RESOURCE.invalidArgCount(call.getOperator().getName(), od.getMin()));
} else {
throw validator.newValidationError(call, RESOURCE.wrongNumOfArguments());
}
}
/**
* Returns whether the given operands are valid. If not valid and
* {@code fail}, throws an assertion error.
*
* Similar to {@link #checkOperandCount}, but some operators may have
* different valid operands in {@link SqlNode} and {@code RexNode} formats
* (some examples are CAST and AND), and this method throws internal errors,
* not user errors.
*/
public boolean validRexOperands(int count, Litmus litmus) {
return true;
}
/**
* Returns a template describing how the operator signature is to be built.
* E.g for the binary + operator the template looks like "{1} {0} {2}" {0}
* is the operator, subsequent numbers are operands.
*
* @param operandsCount is used with functions that can take a variable
* number of operands
* @return signature template, or null to indicate that a default template
* will suffice
*/
public String getSignatureTemplate(final int operandsCount) {
return null;
}
/**
* Returns a string describing the expected operand types of a call, e.g.
* "SUBSTR(VARCHAR, INTEGER, INTEGER)".
*/
public final String getAllowedSignatures() {
return getAllowedSignatures(name);
}
/**
* Returns a string describing the expected operand types of a call, e.g.
* "SUBSTRING(VARCHAR, INTEGER, INTEGER)" where the name (SUBSTRING in this
* example) can be replaced by a specified name.
*/
public String getAllowedSignatures(String opNameToUse) {
assert operandTypeChecker != null
: "If you see this, assign operandTypeChecker a value "
+ "or override this function";
return operandTypeChecker.getAllowedSignatures(this, opNameToUse)
.trim();
}
public SqlOperandTypeInference getOperandTypeInference() {
return operandTypeInference;
}
/**
* Returns whether this operator is an aggregate function. By default,
* subclass type is used (an instance of SqlAggFunction is assumed to be an
* aggregator; anything else is not).
*
* Per SQL:2011, there are aggregate functions and
* window functions.
* Every aggregate function (e.g. SUM) is also a window function.
* There are window functions that are not aggregate functions, e.g. RANK,
* NTILE, LEAD, FIRST_VALUE.
*
* Collectively, aggregate and window functions are called analytic
* functions. Despite its name, this method returns true for every
* analytic function.
*
* @see #requiresOrder()
*
* @return whether this operator is an analytic function (aggregate function
* or window function)
*/
public boolean isAggregator() {
return false;
}
/** Returns whether this is a window function that requires an OVER clause.
*
* For example, returns true for {@code RANK}, {@code DENSE_RANK} and
* other ranking functions; returns false for {@code SUM}, {@code COUNT},
* {@code MIN}, {@code MAX}, {@code AVG} (they can be used as non-window
* aggregate functions).
*
*
If {@code requiresOver} returns true, then {@link #isAggregator()} must
* also return true.
*
* @see #allowsFraming()
* @see #requiresOrder()
*/
public boolean requiresOver() {
return false;
}
/**
* Returns whether this is a window function that requires ordering.
*
*
Per SQL:2011, 2, 6.10: "If <ntile function>, <lead or lag
* function>, RANK or DENSE_RANK is specified, then the window ordering
* clause shall be present."
*
* @see #isAggregator()
*/
public boolean requiresOrder() {
return false;
}
/**
* Returns whether this is a window function that allows framing (i.e. a
* ROWS or RANGE clause in the window specification).
*/
public boolean allowsFraming() {
return true;
}
/**
* Returns whether this is a group function.
*
* Group functions can only appear in the GROUP BY clause.
*
*
Examples are {@code HOP}, {@code TUMBLE}, {@code SESSION}.
*
*
Group functions have auxiliary functions, e.g. {@code HOP_START}, but
* these are not group functions.
*/
public boolean isGroup() {
return false;
}
/**
* Returns whether this is an group auxiliary function.
*
*
Examples are {@code HOP_START} and {@code HOP_END} (both auxiliary to
* {@code HOP}).
*
* @see #isGroup()
*/
public boolean isGroupAuxiliary() {
return false;
}
/**
* Accepts a {@link SqlVisitor}, visiting each operand of a call. Returns
* null.
*
* @param visitor Visitor
* @param call Call to visit
*/
public R acceptCall(SqlVisitor visitor, SqlCall call) {
for (SqlNode operand : call.getOperandList()) {
if (operand == null) {
continue;
}
operand.accept(visitor);
}
return null;
}
/**
* Accepts a {@link SqlVisitor}, directing an
* {@link com.hazelcast.org.apache.calcite.sql.util.SqlBasicVisitor.ArgHandler}
* to visit an operand of a call.
*
* The argument handler allows fine control about how the operands are
* visited, and how the results are combined.
*
* @param visitor Visitor
* @param call Call to visit
* @param onlyExpressions If true, ignores operands which are not
* expressions. For example, in the call to the
* AS
operator
* @param argHandler Called for each operand
*/
public void acceptCall(
SqlVisitor visitor,
SqlCall call,
boolean onlyExpressions,
SqlBasicVisitor.ArgHandler argHandler) {
List operands = call.getOperandList();
for (int i = 0; i < operands.size(); i++) {
argHandler.visitChild(visitor, call, i, operands.get(i));
}
}
/**
* @return the return type inference strategy for this operator, or null if
* return type inference is implemented by a subclass override
*/
public SqlReturnTypeInference getReturnTypeInference() {
return returnTypeInference;
}
/**
* Returns whether this operator is monotonic.
*
* Default implementation returns {@link SqlMonotonicity#NOT_MONOTONIC}.
*
* @param call Call to this operator
* @param scope Scope in which the call occurs
*
* @deprecated Use {@link #getMonotonicity(SqlOperatorBinding)}
*/
@Deprecated // to be removed before 2.0
public SqlMonotonicity getMonotonicity(
SqlCall call,
SqlValidatorScope scope) {
return getMonotonicity(
new SqlCallBinding(scope.getValidator(), scope, call));
}
/**
* Returns whether a call to this operator is monotonic.
*
*
Default implementation returns {@link SqlMonotonicity#NOT_MONOTONIC}.
*
* @param call Call to this operator with particular arguments and information
* about the monotonicity of the arguments
*/
public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
return SqlMonotonicity.NOT_MONOTONIC;
}
/**
* Returns whether a call to this operator is guaranteed to always return
* the same result given the same operands; true is assumed by default
*/
public boolean isDeterministic() {
return true;
}
/**
* Returns whether it is unsafe to cache query plans referencing this
* operator; false is assumed by default
*/
public boolean isDynamicFunction() {
return false;
}
/**
* Method to check if call requires expansion when it has decimal operands.
* The default implementation is to return true.
*/
public boolean requiresDecimalExpansion() {
return true;
}
/**
* Returns whether the ordinal
th argument to this operator must
* be scalar (as opposed to a query).
*
*
If true (the default), the validator will attempt to convert the
* argument into a scalar sub-query, which must have one column and return at
* most one row.
*
*
Operators such as SELECT
and EXISTS
override
* this method.
*/
public boolean argumentMustBeScalar(int ordinal) {
return true;
}
}