org.apache.calcite.sql.SqlCallBinding Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of calcite-core Show documentation
Show all versions of calcite-core Show documentation
Core Calcite APIs and engine.
/*
* 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.rel.type.RelDataType;
import org.apache.calcite.runtime.CalciteException;
import org.apache.calcite.runtime.Resources;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.validate.SelectScope;
import org.apache.calcite.sql.validate.SqlMonotonicity;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql.validate.SqlValidatorException;
import org.apache.calcite.sql.validate.SqlValidatorNamespace;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.calcite.sql.validate.SqlValidatorUtil;
import org.apache.calcite.util.NlsString;
import com.google.common.collect.Lists;
import java.math.BigDecimal;
import java.util.List;
import static org.apache.calcite.util.Static.RESOURCE;
/**
* SqlCallBinding
implements {@link SqlOperatorBinding} by
* analyzing to the operands of a {@link SqlCall} with a {@link SqlValidator}.
*/
public class SqlCallBinding extends SqlOperatorBinding {
private static final SqlCall DEFAULT_CALL =
SqlStdOperatorTable.DEFAULT.createCall(SqlParserPos.ZERO);
//~ Instance fields --------------------------------------------------------
private final SqlValidator validator;
private final SqlValidatorScope scope;
private final SqlCall call;
//~ Constructors -----------------------------------------------------------
/**
* Creates a call binding.
*
* @param validator Validator
* @param scope Scope of call
* @param call Call node
*/
public SqlCallBinding(
SqlValidator validator,
SqlValidatorScope scope,
SqlCall call) {
super(
validator.getTypeFactory(),
call.getOperator());
this.validator = validator;
this.scope = scope;
this.call = call;
}
//~ Methods ----------------------------------------------------------------
@Override public int getGroupCount() {
final SelectScope selectScope =
SqlValidatorUtil.getEnclosingSelectScope(scope);
if (selectScope == null) {
// Probably "VALUES expr". Treat same as "SELECT expr GROUP BY ()"
return 0;
}
final SqlSelect select = selectScope.getNode();
final SqlNodeList group = select.getGroup();
if (group != null) {
int n = 0;
for (SqlNode groupItem : group) {
if (!(groupItem instanceof SqlNodeList)
|| ((SqlNodeList) groupItem).size() != 0) {
++n;
}
}
return n;
}
return validator.isAggregate(select) ? 0 : -1;
}
/**
* Returns the validator.
*/
public SqlValidator getValidator() {
return validator;
}
/**
* Returns the scope of the call.
*/
public SqlValidatorScope getScope() {
return scope;
}
/**
* Returns the call node.
*/
public SqlCall getCall() {
return call;
}
/** Returns the operands to a call permuted into the same order as the
* formal parameters of the function. */
public List operands() {
if (hasAssignment() && !(call.getOperator() instanceof SqlUnresolvedFunction)) {
return permutedOperands(call);
} else {
final List operandList = call.getOperandList();
if (call.getOperator() instanceof SqlFunction) {
final List paramTypes =
((SqlFunction) call.getOperator()).getParamTypes();
if (paramTypes != null && operandList.size() < paramTypes.size()) {
final List list = Lists.newArrayList(operandList);
while (list.size() < paramTypes.size()) {
list.add(DEFAULT_CALL);
}
return list;
}
}
return operandList;
}
}
/** Returns whether arguments have name assignment. */
private boolean hasAssignment() {
for (SqlNode operand : call.getOperandList()) {
if (operand != null
&& operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
return true;
}
}
return false;
}
/** Returns the operands to a call permuted into the same order as the
* formal parameters of the function. */
private List permutedOperands(final SqlCall call) {
final SqlFunction operator = (SqlFunction) call.getOperator();
return Lists.transform(operator.getParamNames(), paramName -> {
for (SqlNode operand2 : call.getOperandList()) {
final SqlCall call2 = (SqlCall) operand2;
assert operand2.getKind() == SqlKind.ARGUMENT_ASSIGNMENT;
final SqlIdentifier id = call2.operand(1);
if (id.getSimple().equals(paramName)) {
return call2.operand(0);
}
}
return DEFAULT_CALL;
});
}
/**
* Returns a particular operand.
*/
public SqlNode operand(int i) {
return operands().get(i);
}
/** Returns a call that is equivalent except that arguments have been
* permuted into the logical order. Any arguments whose default value is being
* used are null. */
public SqlCall permutedCall() {
final List operandList = operands();
if (operandList.equals(call.getOperandList())) {
return call;
}
return call.getOperator().createCall(call.pos, operandList);
}
public SqlMonotonicity getOperandMonotonicity(int ordinal) {
return call.getOperandList().get(ordinal).getMonotonicity(scope);
}
@SuppressWarnings("deprecation")
@Override public String getStringLiteralOperand(int ordinal) {
SqlNode node = call.operand(ordinal);
final Object o = SqlLiteral.value(node);
return o instanceof NlsString ? ((NlsString) o).getValue() : null;
}
@SuppressWarnings("deprecation")
@Override public int getIntLiteralOperand(int ordinal) {
SqlNode node = call.operand(ordinal);
final Object o = SqlLiteral.value(node);
if (o instanceof BigDecimal) {
BigDecimal bd = (BigDecimal) o;
try {
return bd.intValueExact();
} catch (ArithmeticException e) {
throw SqlUtil.newContextException(node.pos,
RESOURCE.numberLiteralOutOfRange(bd.toString()));
}
}
throw new AssertionError();
}
@Override public T getOperandLiteralValue(int ordinal, Class clazz) {
try {
final SqlNode node = call.operand(ordinal);
return SqlLiteral.unchain(node).getValueAs(clazz);
} catch (AssertionError e) {
return null;
}
}
@Override public boolean isOperandNull(int ordinal, boolean allowCast) {
return SqlUtil.isNullLiteral(call.operand(ordinal), allowCast);
}
@Override public boolean isOperandLiteral(int ordinal, boolean allowCast) {
return SqlUtil.isLiteral(call.operand(ordinal), allowCast);
}
@Override public int getOperandCount() {
return call.getOperandList().size();
}
@Override public RelDataType getOperandType(int ordinal) {
final SqlNode operand = call.operand(ordinal);
final RelDataType type = validator.deriveType(scope, operand);
final SqlValidatorNamespace namespace = validator.getNamespace(operand);
if (namespace != null) {
return namespace.getType();
}
return type;
}
@Override public RelDataType getCursorOperand(int ordinal) {
final SqlNode operand = call.operand(ordinal);
if (!SqlUtil.isCallTo(operand, SqlStdOperatorTable.CURSOR)) {
return null;
}
final SqlCall cursorCall = (SqlCall) operand;
final SqlNode query = cursorCall.operand(0);
return validator.deriveType(scope, query);
}
@Override public String getColumnListParamInfo(
int ordinal,
String paramName,
List columnList) {
final SqlNode operand = call.operand(ordinal);
if (!SqlUtil.isCallTo(operand, SqlStdOperatorTable.ROW)) {
return null;
}
for (SqlNode id : ((SqlCall) operand).getOperandList()) {
columnList.add(((SqlIdentifier) id).getSimple());
}
return validator.getParentCursor(paramName);
}
public CalciteException newError(
Resources.ExInst e) {
return validator.newValidationError(call, e);
}
/**
* Constructs a new validation signature error for the call.
*
* @return signature exception
*/
public CalciteException newValidationSignatureError() {
return validator.newValidationError(call,
RESOURCE.canNotApplyOp2Type(getOperator().getName(),
call.getCallSignature(validator, scope),
getOperator().getAllowedSignatures()));
}
/**
* Constructs a new validation error for the call. (Do not use this to
* construct a validation error for other nodes such as an operands.)
*
* @param ex underlying exception
* @return wrapped exception
*/
public CalciteException newValidationError(
Resources.ExInst ex) {
return validator.newValidationError(call, ex);
}
}
// End SqlCallBinding.java
© 2015 - 2024 Weber Informatics LLC | Privacy Policy