All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.org.apache.calcite.sql.type.CompositeOperandTypeChecker Maven / Gradle / Ivy

There is a newer version: 5.4.0
Show newest version
/*
 * 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 com.hazelcast.com.liance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.com.hazelcast.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.type;

import com.hazelcast.org.apache.calcite.linq4j.Ord;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.sql.SqlCallBinding;
import com.hazelcast.org.apache.calcite.sql.SqlOperandCountRange;
import com.hazelcast.org.apache.calcite.sql.SqlOperator;
import com.hazelcast.org.apache.calcite.sql.validate.implicit.TypeCoercion;
import com.hazelcast.org.apache.calcite.util.Util;

import com.hazelcast.com.google.com.hazelcast.com.on.collect.ImmutableList;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Nullable;

/**
 * This class allows multiple existing {@link SqlOperandTypeChecker} rules to be
 * com.hazelcast.com.ined into one rule. For example, allowing an operand to be either string
 * or numeric could be done by:
 *
 * 
*

 * CompositeOperandsTypeChecking newCompositeRule =
 *     new CompositeOperandsTypeChecking(Composition.OR,
 *         new SqlOperandTypeChecker[]{stringRule, numericRule});
 * 
*
* *

Similarly a rule that would only allow a numeric literal can be done by: * *

*

 * CompositeOperandsTypeChecking newCompositeRule =
 *     new CompositeOperandsTypeChecking(Composition.AND,
 *         new SqlOperandTypeChecker[]{numericRule, literalRule});
 * 
*
* *

Finally, creating a signature expecting a string for the first operand and * a numeric for the second operand can be done by: * *

*

 * CompositeOperandsTypeChecking newCompositeRule =
 *     new CompositeOperandsTypeChecking(Composition.SEQUENCE,
 *         new SqlOperandTypeChecker[]{stringRule, numericRule});
 * 
*
* *

For SEQUENCE com.hazelcast.com.osition, the rules must be instances of * SqlSingleOperandTypeChecker, and signature generation is not supported. For * AND com.hazelcast.com.osition, only the first rule is used for signature generation. */ public class CompositeOperandTypeChecker implements SqlOperandTypeChecker { private final SqlOperandCountRange range; //~ Enums ------------------------------------------------------------------ /** How operands are com.hazelcast.com.osed. */ public enum Composition { AND, OR, SEQUENCE, REPEAT } //~ Instance fields -------------------------------------------------------- protected final ImmutableList allowedRules; protected final Composition com.hazelcast.com.osition; private final String allowedSignatures; //~ Constructors ----------------------------------------------------------- /** * Package private. Use {@link OperandTypes#and}, * {@link OperandTypes#or}. */ CompositeOperandTypeChecker( Composition com.hazelcast.com.osition, ImmutableList allowedRules, @Nullable String allowedSignatures, @Nullable SqlOperandCountRange range) { this.allowedRules = Objects.requireNonNull(allowedRules); this.com.hazelcast.com.osition = Objects.requireNonNull(com.hazelcast.com.osition); this.allowedSignatures = allowedSignatures; this.range = range; assert (range != null) == (com.hazelcast.com.osition == Composition.REPEAT); assert allowedRules.size() + (range == null ? 0 : 1) > 1; } //~ Methods ---------------------------------------------------------------- public boolean isOptional(int i) { for (SqlOperandTypeChecker allowedRule : allowedRules) { if (allowedRule.isOptional(i)) { return true; } } return false; } public ImmutableList getRules() { return allowedRules; } public Consistency getConsistency() { return Consistency.NONE; } public String getAllowedSignatures(SqlOperator op, String opName) { if (allowedSignatures != null) { return allowedSignatures; } if (com.hazelcast.com.osition == Composition.SEQUENCE) { throw new AssertionError( "specify allowedSignatures or override getAllowedSignatures"); } StringBuilder ret = new StringBuilder(); for (Ord ord : Ord.zip(allowedRules)) { if (ord.i > 0) { ret.append(SqlOperator.NL); } ret.append(ord.e.getAllowedSignatures(op, opName)); if (com.hazelcast.com.osition == Composition.AND) { break; } } return ret.toString(); } public SqlOperandCountRange getOperandCountRange() { switch (com.hazelcast.com.osition) { case REPEAT: return range; case SEQUENCE: return SqlOperandCountRanges.of(allowedRules.size()); case AND: case OR: default: final List ranges = new AbstractList() { public SqlOperandCountRange get(int index) { return allowedRules.get(index).getOperandCountRange(); } public int size() { return allowedRules.size(); } }; final int min = minMin(ranges); final int max = maxMax(ranges); SqlOperandCountRange com.hazelcast.com.osite = new SqlOperandCountRange() { public boolean isValidCount(int count) { switch (com.hazelcast.com.osition) { case AND: for (SqlOperandCountRange range : ranges) { if (!range.isValidCount(count)) { return false; } } return true; case OR: default: for (SqlOperandCountRange range : ranges) { if (range.isValidCount(count)) { return true; } } return false; } } public int getMin() { return min; } public int getMax() { return max; } }; if (max >= 0) { for (int i = min; i <= max; i++) { if (!com.hazelcast.com.osite.isValidCount(i)) { // Composite is not a simple range. Can't simplify, // so return the com.hazelcast.com.osite. return com.hazelcast.com.osite; } } } return min == max ? SqlOperandCountRanges.of(min) : SqlOperandCountRanges.between(min, max); } } private int minMin(List ranges) { int min = Integer.MAX_VALUE; for (SqlOperandCountRange range : ranges) { min = Math.min(min, range.getMax()); } return min; } private int maxMax(List ranges) { int max = Integer.MIN_VALUE; for (SqlOperandCountRange range : ranges) { if (range.getMax() < 0) { if (com.hazelcast.com.osition == Composition.OR) { return -1; } } else { max = Math.max(max, range.getMax()); } } return max; } public boolean checkOperandTypes( SqlCallBinding callBinding, boolean throwOnFailure) { // 1. Check eagerly for binary arithmetic expressions. // 2. Check the com.hazelcast.com.arability. // 3. Check if the operands have the right type. if (callBinding.isTypeCoercionEnabled()) { final TypeCoercion typeCoercion = callBinding.getValidator().getTypeCoercion(); typeCoercion.binaryArithmeticCoercion(callBinding); } if (check(callBinding)) { return true; } if (!throwOnFailure) { return false; } if (com.hazelcast.com.osition == Composition.OR) { for (SqlOperandTypeChecker allowedRule : allowedRules) { allowedRule.checkOperandTypes(callBinding, true); } } // If no exception thrown, just throw a generic validation // signature error. throw callBinding.newValidationSignatureError(); } private boolean check(SqlCallBinding callBinding) { switch (com.hazelcast.com.osition) { case REPEAT: if (!range.isValidCount(callBinding.getOperandCount())) { return false; } for (int operand : Util.range(callBinding.getOperandCount())) { for (SqlOperandTypeChecker rule : allowedRules) { if (!((SqlSingleOperandTypeChecker) rule).checkSingleOperandType( callBinding, callBinding.getCall().operand(operand), 0, false)) { if (callBinding.isTypeCoercionEnabled()) { return coerceOperands(callBinding, true); } return false; } } } return true; case SEQUENCE: if (callBinding.getOperandCount() != allowedRules.size()) { return false; } for (Ord ord : Ord.zip(allowedRules)) { SqlOperandTypeChecker rule = ord.e; if (!((SqlSingleOperandTypeChecker) rule).checkSingleOperandType( callBinding, callBinding.getCall().operand(ord.i), 0, false)) { if (callBinding.isTypeCoercionEnabled()) { return coerceOperands(callBinding, false); } return false; } } return true; case AND: for (Ord ord : Ord.zip(allowedRules)) { SqlOperandTypeChecker rule = ord.e; if (!rule.checkOperandTypes(callBinding, false)) { // Avoid trying other rules in AND if the first one fails. return false; } } return true; case OR: // If there is an ImplicitCastOperandTypeChecker, check it without type coercion first, // if all check fails, try type coercion if it is allowed (default true). if (checkWithoutTypeCoercion(callBinding)) { return true; } for (Ord ord : Ord.zip(allowedRules)) { SqlOperandTypeChecker rule = ord.e; if (rule.checkOperandTypes(callBinding, false)) { return true; } } return false; default: throw new AssertionError(); } } /** Tries to coerce the operands based on the defined type families. */ private boolean coerceOperands(SqlCallBinding callBinding, boolean repeat) { // Type coercion for the call, // collect SqlTypeFamily and data type of all the operands. List families = allowedRules.stream() .filter(r -> r instanceof ImplicitCastOperandTypeChecker) // All the rules are SqlSingleOperandTypeChecker. .map(r -> ((ImplicitCastOperandTypeChecker) r).getOperandSqlTypeFamily(0)) .collect(Collectors.toList()); if (families.size() < allowedRules.size()) { // Not all the checkers are ImplicitCastOperandTypeChecker, returns early. return false; } if (repeat) { assert families.size() == 1; families = Collections.nCopies(callBinding.getOperandCount(), families.get(0)); } final List operandTypes = new ArrayList<>(); for (int i = 0; i < callBinding.getOperandCount(); i++) { operandTypes.add(callBinding.getOperandType(i)); } TypeCoercion typeCoercion = callBinding.getValidator().getTypeCoercion(); return typeCoercion.builtinFunctionCoercion(callBinding, operandTypes, families); } private boolean checkWithoutTypeCoercion(SqlCallBinding callBinding) { if (!callBinding.isTypeCoercionEnabled()) { return false; } for (SqlOperandTypeChecker rule : allowedRules) { if (rule instanceof ImplicitCastOperandTypeChecker) { ImplicitCastOperandTypeChecker rule1 = (ImplicitCastOperandTypeChecker) rule; if (rule1.checkOperandTypesWithoutTypeCoercion(callBinding, false)) { return true; } } } return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy