com.hazelcast.shaded.org.apache.calcite.sql.SqlCallBinding 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.shaded.org.apache.calcite.sql;
import com.hazelcast.shaded.org.apache.calcite.avatica.util.TimeUnit;
import com.hazelcast.shaded.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.shaded.org.apache.calcite.rel.type.TimeFrame;
import com.hazelcast.shaded.org.apache.calcite.rel.type.TimeFrameSet;
import com.hazelcast.shaded.org.apache.calcite.runtime.CalciteException;
import com.hazelcast.shaded.org.apache.calcite.runtime.Resources;
import com.hazelcast.shaded.org.apache.calcite.sql.fun.SqlLiteralChainOperator;
import com.hazelcast.shaded.org.apache.calcite.sql.fun.SqlStdOperatorTable;
import com.hazelcast.shaded.org.apache.calcite.sql.parser.SqlParserPos;
import com.hazelcast.shaded.org.apache.calcite.sql.type.SqlOperandMetadata;
import com.hazelcast.shaded.org.apache.calcite.sql.type.SqlOperandTypeChecker;
import com.hazelcast.shaded.org.apache.calcite.sql.type.SqlTypeName;
import com.hazelcast.shaded.org.apache.calcite.sql.type.SqlTypeUtil;
import com.hazelcast.shaded.org.apache.calcite.sql.validate.SelectScope;
import com.hazelcast.shaded.org.apache.calcite.sql.validate.SqlMonotonicity;
import com.hazelcast.shaded.org.apache.calcite.sql.validate.SqlNameMatcher;
import com.hazelcast.shaded.org.apache.calcite.sql.validate.SqlValidator;
import com.hazelcast.shaded.org.apache.calcite.sql.validate.SqlValidatorException;
import com.hazelcast.shaded.org.apache.calcite.sql.validate.SqlValidatorNamespace;
import com.hazelcast.shaded.org.apache.calcite.sql.validate.SqlValidatorScope;
import com.hazelcast.shaded.org.apache.calcite.sql.validate.SqlValidatorUtil;
import com.hazelcast.shaded.org.apache.calcite.util.ImmutableNullableList;
import com.hazelcast.shaded.org.apache.calcite.util.NlsString;
import com.hazelcast.shaded.org.apache.calcite.util.Pair;
import com.hazelcast.shaded.com.google.common.collect.ImmutableMap;
import com.hazelcast.shaded.com.google.common.collect.Lists;
import com.hazelcast.shaded.org.checkerframework.checker.nullness.qual.Nullable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import static com.hazelcast.shaded.org.apache.calcite.util.Static.RESOURCE;
import static java.util.Objects.requireNonNull;
/**
* SqlCallBinding
implements {@link SqlOperatorBinding} by
* analyzing to the operands of a {@link SqlCall} with a {@link SqlValidator}.
*/
public class SqlCallBinding extends SqlOperatorBinding {
/** Static nested class required due to
* [CALCITE-4393]
* ExceptionInInitializerError due to NPE in SqlCallBinding caused by circular dependency.
* The static field inside it cannot be part of the outer class: it must be defined
* within a nested class in order to break the cycle during class loading. */
private static class DefaultCallHolder {
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 = requireNonNull(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();
final SqlOperandTypeChecker checker =
call.getOperator().getOperandTypeChecker();
if (checker == null) {
return operandList;
}
final SqlOperandCountRange range = checker.getOperandCountRange();
final List list = Lists.newArrayList(operandList);
while (list.size() < range.getMax()
&& checker.isOptional(list.size())
&& checker.isFixedParameters()) {
list.add(DefaultCallHolder.DEFAULT_CALL);
}
return list;
}
}
/** 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 SqlOperator operator = call.getOperator();
final SqlOperandMetadata operandMetadata =
requireNonNull((SqlOperandMetadata) operator.getOperandTypeChecker(),
() -> "operandTypeChecker is null for " + call
+ ", operator " + operator);
final List paramNames = operandMetadata.paramNames();
final List permuted = new ArrayList<>();
final SqlNameMatcher nameMatcher =
validator.getCatalogReader().nameMatcher();
for (final String paramName : paramNames) {
Pair args = null;
for (int j = 0; j < call.getOperandList().size(); j++) {
final SqlCall call2 = call.operand(j);
assert call2.getKind() == SqlKind.ARGUMENT_ASSIGNMENT;
final SqlIdentifier operandID = call2.operand(1);
final String operandName = operandID.getSimple();
if (nameMatcher.matches(operandName, paramName)) {
permuted.add(call2.operand(0));
break;
} else if (args == null
&& nameMatcher.isCaseSensitive()
&& operandName.equalsIgnoreCase(paramName)) {
args = Pair.of(paramName, operandID);
}
// the last operand, there is still no match.
if (j == call.getOperandList().size() - 1) {
if (args != null) {
throw SqlUtil.newContextException(args.right.getParserPosition(),
RESOURCE.paramNotFoundInFunctionDidYouMean(args.right.getSimple(),
operator.getName(), args.left));
}
if (operandMetadata.isFixedParameters()) {
// Not like user defined functions, we do not patch up the operands
// with DEFAULT and then convert to nulls during sql-to-rel conversion.
// Thus, there is no need to show the optional operands in the plan and
// decide if the optional operand is null when code generation.
permuted.add(DefaultCallHolder.DEFAULT_CALL);
}
}
}
}
return permuted;
}
/**
* 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);
}
@Override public SqlMonotonicity getOperandMonotonicity(int ordinal) {
return call.getOperandList().get(ordinal).getMonotonicity(scope);
}
@SuppressWarnings("deprecation")
@Override public @Nullable 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 @Nullable T getOperandLiteralValue(int ordinal,
Class clazz) {
final SqlNode node = operand(ordinal);
return valueAs(node, clazz);
}
private @Nullable T valueAs(SqlNode node, Class clazz) {
final SqlLiteral literal;
switch (node.getKind()) {
case ARRAY_VALUE_CONSTRUCTOR:
final List<@Nullable Object> list = new ArrayList<>();
for (SqlNode o : ((SqlCall) node).getOperandList()) {
list.add(valueAs(o, Object.class));
}
return clazz.cast(ImmutableNullableList.copyOf(list));
case MAP_VALUE_CONSTRUCTOR:
final ImmutableMap.Builder
© 2015 - 2024 Weber Informatics LLC | Privacy Policy