This is an automated email from the ASF dual-hosted git repository.

vladimirsitnikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new 14d5e3b  [CALCITE-4288] Create SqlTypeUtil#deriveType(SqlCallBinding) 
to make type computation simpler
14d5e3b is described below

commit 14d5e3b0dfdba70a24cb5486275a1c973efa347c
Author: Vladimir Sitnikov <[email protected]>
AuthorDate: Sun Sep 27 21:45:26 2020 +0300

    [CALCITE-4288] Create SqlTypeUtil#deriveType(SqlCallBinding) to make type 
computation simpler
---
 .../org/apache/calcite/sql/SqlCallBinding.java     | 12 ++--
 .../apache/calcite/sql/fun/SqlCaseOperator.java    | 14 ++---
 .../apache/calcite/sql/fun/SqlCastFunction.java    |  3 +-
 .../org/apache/calcite/sql/fun/SqlDotOperator.java |  4 +-
 .../calcite/sql/fun/SqlLiteralChainOperator.java   |  5 +-
 .../calcite/sql/fun/SqlMapValueConstructor.java    |  6 +-
 .../sql/fun/SqlMultisetMemberOfOperator.java       | 10 +---
 .../sql/fun/SqlMultisetQueryConstructor.java       |  6 +-
 .../sql/fun/SqlMultisetValueConstructor.java       |  5 +-
 .../calcite/sql/fun/SqlSubstringFunction.java      |  6 +-
 .../sql/type/AssignableOperandTypeChecker.java     |  5 +-
 .../calcite/sql/type/FamilyOperandTypeChecker.java |  8 +--
 .../org/apache/calcite/sql/type/InferTypes.java    |  3 +-
 .../sql/type/MultisetOperandTypeChecker.java       |  6 +-
 .../org/apache/calcite/sql/type/OperandTypes.java  | 13 +----
 .../org/apache/calcite/sql/type/SqlTypeUtil.java   | 64 ++++++++++++++++------
 16 files changed, 79 insertions(+), 91 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java 
b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
index 5ab0bac..c0bda8d 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
@@ -27,6 +27,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlOperandMetadata;
 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SelectScope;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlNameMatcher;
@@ -45,10 +46,11 @@ import com.google.common.collect.Lists;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 
 import static org.apache.calcite.util.Static.RESOURCE;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * <code>SqlCallBinding</code> implements {@link SqlOperatorBinding} by
  * analyzing to the operands of a {@link SqlCall} with a {@link SqlValidator}.
@@ -290,8 +292,8 @@ public class SqlCallBinding extends SqlOperatorBinding {
       for (int i = 0; i < operands.size(); i += 2) {
         final SqlNode key = operands.get(i);
         final SqlNode value = operands.get(i + 1);
-        builder2.put(Objects.requireNonNull(valueAs(key, Object.class)),
-            Objects.requireNonNull(valueAs(value, Object.class)));
+        builder2.put(requireNonNull(valueAs(key, Object.class), "key"),
+            requireNonNull(valueAs(value, Object.class), "value"));
       }
       return clazz.cast(builder2.build());
 
@@ -341,7 +343,7 @@ public class SqlCallBinding extends SqlOperatorBinding {
 
   @Override public RelDataType getOperandType(int ordinal) {
     final SqlNode operand = call.operand(ordinal);
-    final RelDataType type = validator.deriveType(scope, operand);
+    final RelDataType type = SqlTypeUtil.deriveType(this, operand);
     final SqlValidatorNamespace namespace = validator.getNamespace(operand);
     if (namespace != null) {
       return namespace.getType();
@@ -356,7 +358,7 @@ public class SqlCallBinding extends SqlOperatorBinding {
     }
     final SqlCall cursorCall = (SqlCall) operand;
     final SqlNode query = cursorCall.operand(0);
-    return validator.deriveType(scope, query);
+    return SqlTypeUtil.deriveType(this, query);
   }
 
   @Override public String getColumnListParamInfo(
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java
index 7d5c567..73868aa 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java
@@ -179,10 +179,7 @@ public class SqlCaseOperator extends SqlOperator {
     // checking that search conditions are ok...
     for (SqlNode node : whenList) {
       // should throw validation error if something wrong...
-      RelDataType type =
-          callBinding.getValidator().deriveType(
-              callBinding.getScope(),
-              node);
+      RelDataType type = SqlTypeUtil.deriveType(callBinding, node);
       if (!SqlTypeUtil.inBooleanFamily(type)) {
         if (throwOnFailure) {
           throw callBinding.newError(RESOURCE.expectedBoolean());
@@ -237,8 +234,7 @@ public class SqlCaseOperator extends SqlOperator {
     final int size = thenList.getList().size();
     for (int i = 0; i < size; i++) {
       SqlNode node = thenList.get(i);
-      RelDataType type = callBinding.getValidator().deriveType(
-          callBinding.getScope(), node);
+      RelDataType type = SqlTypeUtil.deriveType(callBinding, node);
       SqlNode operand = whenOperands.get(i);
       if (operand.getKind() == SqlKind.IS_NOT_NULL && type.isNullable()) {
         SqlBasicCall call = (SqlBasicCall) operand;
@@ -255,8 +251,7 @@ public class SqlCaseOperator extends SqlOperator {
 
     SqlNode elseOp = caseCall.getElseOperand();
     argTypes.add(
-        callBinding.getValidator().deriveType(
-            callBinding.getScope(), caseCall.getElseOperand()));
+        SqlTypeUtil.deriveType(callBinding, elseOp));
     if (SqlUtil.isNullLiteral(elseOp, false)) {
       nullList.add(elseOp);
     }
@@ -274,8 +269,7 @@ public class SqlCaseOperator extends SqlOperator {
         if (null != commonType) {
           coerced = typeCoercion.caseWhenCoercion(callBinding);
           if (coerced) {
-            ret = callBinding.getValidator()
-                .deriveType(callBinding.getScope(), callBinding.getCall());
+            ret = SqlTypeUtil.deriveType(callBinding);
           }
         }
       }
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
index 76e7422..28d856e 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
@@ -145,8 +145,7 @@ public class SqlCastFunction extends SqlFunction {
     }
     RelDataType validatedNodeType =
         callBinding.getValidator().getValidatedNodeType(left);
-    RelDataType returnType =
-        callBinding.getValidator().deriveType(callBinding.getScope(), right);
+    RelDataType returnType = SqlTypeUtil.deriveType(callBinding, right);
     if (!SqlTypeUtil.canCastFrom(returnType, validatedNodeType, true)) {
       if (throwOnFailure) {
         throw callBinding.newError(
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlDotOperator.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlDotOperator.java
index 7e7af24..874707c 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlDotOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlDotOperator.java
@@ -34,6 +34,7 @@ import org.apache.calcite.sql.type.SqlOperandCountRanges;
 import org.apache.calcite.sql.type.SqlSingleOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.util.SqlBasicVisitor;
 import org.apache.calcite.sql.util.SqlVisitor;
 import org.apache.calcite.sql.validate.SqlValidator;
@@ -137,8 +138,7 @@ public class SqlDotOperator extends SqlSpecialOperator {
       boolean throwOnFailure) {
     final SqlNode left = callBinding.operand(0);
     final SqlNode right = callBinding.operand(1);
-    final RelDataType type =
-        callBinding.getValidator().deriveType(callBinding.getScope(), left);
+    final RelDataType type = SqlTypeUtil.deriveType(callBinding, left);
     if (type.getSqlTypeName() != SqlTypeName.ROW) {
       return false;
     } else if (type.getSqlIdentifier().isStar()) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
index 61a9978..8b2d96d 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
@@ -81,10 +81,7 @@ public class SqlLiteralChainOperator extends 
SqlSpecialOperator {
     }
     RelDataType firstType = null;
     for (Ord<SqlNode> operand : Ord.zip(callBinding.operands())) {
-      RelDataType type =
-          callBinding.getValidator().deriveType(
-              callBinding.getScope(),
-              operand.e);
+      RelDataType type = SqlTypeUtil.deriveType(callBinding, operand.e);
       if (operand.i == 0) {
         firstType = type;
       } else {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
index 3b4323c..7fe4db7 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
@@ -57,11 +57,7 @@ public class SqlMapValueConstructor extends 
SqlMultisetValueConstructor {
   public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
-    final List<RelDataType> argTypes =
-        SqlTypeUtil.deriveAndCollectTypes(
-            callBinding.getValidator(),
-            callBinding.getScope(),
-            callBinding.operands());
+    final List<RelDataType> argTypes = SqlTypeUtil.deriveType(callBinding, 
callBinding.operands());
     if (argTypes.size() == 0) {
       throw 
callBinding.newValidationError(RESOURCE.mapRequiresTwoOrMoreArgs());
     }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetMemberOfOperator.java
 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetMemberOfOperator.java
index 4b288d0..ebff588 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetMemberOfOperator.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetMemberOfOperator.java
@@ -62,15 +62,9 @@ public class SqlMultisetMemberOfOperator extends 
SqlBinaryOperator {
       return false;
     }
 
-    MultisetSqlType mt =
-        (MultisetSqlType) callBinding.getValidator().deriveType(
-            callBinding.getScope(),
-            callBinding.operand(1));
+    MultisetSqlType mt = (MultisetSqlType) callBinding.getOperandType(1);
 
-    RelDataType t0 =
-        callBinding.getValidator().deriveType(
-            callBinding.getScope(),
-            callBinding.operand(0));
+    RelDataType t0 = callBinding.getOperandType(0);
     RelDataType t1 = mt.getComponentType();
 
     if (t0.getFamily() != t1.getFamily()) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java
 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java
index d3e26fe..72a76df 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java
@@ -85,11 +85,7 @@ public class SqlMultisetQueryConstructor extends 
SqlSpecialOperator {
   public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
-    final List<RelDataType> argTypes =
-        SqlTypeUtil.deriveAndCollectTypes(
-            callBinding.getValidator(),
-            callBinding.getScope(),
-            callBinding.operands());
+    final List<RelDataType> argTypes = SqlTypeUtil.deriveType(callBinding, 
callBinding.operands());
     final RelDataType componentType =
         getComponentType(
             callBinding.getTypeFactory(),
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
index 73ecd34..b4604b9 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
@@ -86,10 +86,7 @@ public class SqlMultisetValueConstructor extends 
SqlSpecialOperator {
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
     final List<RelDataType> argTypes =
-        SqlTypeUtil.deriveAndCollectTypes(
-            callBinding.getValidator(),
-            callBinding.getScope(),
-            callBinding.operands());
+        SqlTypeUtil.deriveType(callBinding, callBinding.operands());
     if (argTypes.size() == 0) {
       throw callBinding.newValidationError(RESOURCE.requireAtLeastOneArg());
     }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
index 114be7f..3366d70 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
@@ -36,7 +36,6 @@ import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidator;
 
 import com.google.common.collect.ImmutableList;
 
@@ -117,9 +116,8 @@ public class SqlSubstringFunction extends SqlFunction {
       // Reset the operands because they may be coerced during
       // implicit type coercion.
       operands = callBinding.getCall().getOperandList();
-      final SqlValidator validator = callBinding.getValidator();
-      final RelDataType t1 = validator.deriveType(callBinding.getScope(), 
operands.get(1));
-      final RelDataType t2 = validator.deriveType(callBinding.getScope(), 
operands.get(2));
+      final RelDataType t1 = callBinding.getOperandType(1);
+      final RelDataType t2 = callBinding.getOperandType(2);
       if (SqlTypeUtil.inCharFamily(t1)) {
         if (!SqlTypeUtil.isCharTypeComparable(callBinding, operands,
             throwOnFailure)) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/type/AssignableOperandTypeChecker.java
 
b/core/src/main/java/org/apache/calcite/sql/type/AssignableOperandTypeChecker.java
index 6d27dc0..5db711f 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/type/AssignableOperandTypeChecker.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/type/AssignableOperandTypeChecker.java
@@ -72,10 +72,7 @@ public class AssignableOperandTypeChecker implements 
SqlOperandTypeChecker {
     // yet, therefore we do not know the ordered parameter names.
     final List<SqlNode> operands = callBinding.getCall().getOperandList();
     for (Pair<RelDataType, SqlNode> pair : Pair.zip(paramTypes, operands)) {
-      RelDataType argType =
-          callBinding.getValidator().deriveType(
-              callBinding.getScope(),
-              pair.right);
+      RelDataType argType = SqlTypeUtil.deriveType(callBinding, pair.right);
       if (!SqlTypeUtil.canAssignFrom(pair.left, argType)) {
         // TODO: add in unresolved function type cast.
         if (throwOnFailure) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java 
b/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
index de9e186..3910e30 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
@@ -68,8 +68,7 @@ public class FamilyOperandTypeChecker implements 
SqlSingleOperandTypeChecker,
     final SqlTypeFamily family = families.get(iFormalOperand);
     switch (family) {
     case ANY:
-      final RelDataType type = callBinding.getValidator()
-          .deriveType(callBinding.getScope(), node);
+      final RelDataType type = SqlTypeUtil.deriveType(callBinding, node);
       SqlTypeName typeName = type.getSqlTypeName();
 
       if (typeName == SqlTypeName.CURSOR) {
@@ -94,10 +93,7 @@ public class FamilyOperandTypeChecker implements 
SqlSingleOperandTypeChecker,
         return false;
       }
     }
-    RelDataType type =
-        callBinding.getValidator().deriveType(
-            callBinding.getScope(),
-            node);
+    RelDataType type = SqlTypeUtil.deriveType(callBinding, node);
     SqlTypeName typeName = type.getSqlTypeName();
 
     // Pass type checking for operators if it's of type 'ANY'.
diff --git a/core/src/main/java/org/apache/calcite/sql/type/InferTypes.java 
b/core/src/main/java/org/apache/calcite/sql/type/InferTypes.java
index 5983447..0d340cc 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/InferTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/InferTypes.java
@@ -44,8 +44,7 @@ public abstract class InferTypes {
             callBinding.getValidator().getUnknownType();
         RelDataType knownType = unknownType;
         for (SqlNode operand : callBinding.operands()) {
-          knownType = callBinding.getValidator().deriveType(
-              callBinding.getScope(), operand);
+          knownType = SqlTypeUtil.deriveType(callBinding, operand);
           if (!knownType.equals(unknownType)) {
             break;
           }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/type/MultisetOperandTypeChecker.java
 
b/core/src/main/java/org/apache/calcite/sql/type/MultisetOperandTypeChecker.java
index 4f97633..0e728c8 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/type/MultisetOperandTypeChecker.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/type/MultisetOperandTypeChecker.java
@@ -65,11 +65,9 @@ public class MultisetOperandTypeChecker implements 
SqlOperandTypeChecker {
     RelDataType biggest =
         callBinding.getTypeFactory().leastRestrictive(
             ImmutableList.of(
-                callBinding.getValidator()
-                    .deriveType(callBinding.getScope(), op0)
+                SqlTypeUtil.deriveType(callBinding, op0)
                     .getComponentType(),
-                callBinding.getValidator()
-                    .deriveType(callBinding.getScope(), op1)
+                SqlTypeUtil.deriveType(callBinding, op1)
                     .getComponentType()));
     if (null == biggest) {
       if (throwOnFailure) {
diff --git a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java 
b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
index 9e4181b..abb6fb8 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
@@ -581,10 +581,7 @@ public abstract class OperandTypes {
         int iFormalOperand,
         boolean throwOnFailure) {
       assert 0 == iFormalOperand;
-      RelDataType type =
-          callBinding.getValidator().deriveType(
-              callBinding.getScope(),
-              node);
+      RelDataType type = SqlTypeUtil.deriveType(callBinding, node);
       boolean validationError = false;
       if (!type.isStruct()) {
         validationError = true;
@@ -663,10 +660,7 @@ public abstract class OperandTypes {
             int iFormalOperand,
             boolean throwOnFailure) {
           assert 0 == iFormalOperand;
-          RelDataType type =
-              callBinding.getValidator().deriveType(
-                  callBinding.getScope(),
-                  node);
+          RelDataType type = SqlTypeUtil.deriveType(callBinding, node);
           boolean validationError = false;
           if (!type.isStruct()) {
             validationError = true;
@@ -721,8 +715,7 @@ public abstract class OperandTypes {
     public boolean checkSingleOperandType(SqlCallBinding callBinding,
         SqlNode node, int iFormalOperand, boolean throwOnFailure) {
       assert 0 == iFormalOperand;
-      RelDataType type =
-          callBinding.getValidator().deriveType(callBinding.getScope(), node);
+      RelDataType type = SqlTypeUtil.deriveType(callBinding, node);
       boolean valid = false;
       if (type.isStruct() && type.getFieldList().size() == 2) {
         final RelDataType t0 = type.getFieldList().get(0).getType();
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java 
b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
index fce8b7b..04818fc 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
@@ -46,6 +46,8 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
 
+import org.apiguardian.api.API;
+
 import java.math.BigDecimal;
 import java.nio.charset.Charset;
 import java.util.AbstractList;
@@ -53,12 +55,13 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import static org.apache.calcite.util.Static.RESOURCE;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * Contains utility methods used during SQL validation or type derivation.
  */
@@ -123,21 +126,13 @@ public abstract class SqlTypeUtil {
       SqlCallBinding binding,
       List<SqlNode> operands,
       boolean throwOnFailure) {
-    final SqlValidator validator = binding.getValidator();
-    final SqlValidatorScope scope = binding.getScope();
-    assert operands != null;
-    assert operands.size() >= 2;
+    requireNonNull(operands, "operands");
+    assert operands.size() >= 2
+        : "operands.size() should be 2 or greater, actual: " + operands.size();
 
-    if (!isCharTypeComparable(
-        deriveAndCollectTypes(validator, scope, operands))) {
+    if (!isCharTypeComparable(SqlTypeUtil.deriveType(binding, operands))) {
       if (throwOnFailure) {
-        String msg = "";
-        for (int i = 0; i < operands.size(); i++) {
-          if (i > 0) {
-            msg += ", ";
-          }
-          msg += operands.get(i).toString();
-        }
+        String msg = String.join(", ", Util.transform(operands, 
String::valueOf));
         throw binding.newError(RESOURCE.operandNotComparable(msg));
       }
       return false;
@@ -152,7 +147,7 @@ public abstract class SqlTypeUtil {
   public static List<RelDataType> deriveAndCollectTypes(
       SqlValidator validator,
       SqlValidatorScope scope,
-      List<SqlNode> operands) {
+      List<? extends SqlNode> operands) {
     // NOTE: Do not use an AbstractList. Don't want to be lazy. We want
     // errors.
     List<RelDataType> types = new ArrayList<>();
@@ -163,6 +158,43 @@ public abstract class SqlTypeUtil {
   }
 
   /**
+   * Derives type of the call via its binding.
+   * @param binding binding to derive the type from
+   * @return datatype of the call
+   */
+  @API(since = "1.26", status = API.Status.EXPERIMENTAL)
+  public static RelDataType deriveType(SqlCallBinding binding) {
+    return deriveType(binding, binding.getCall());
+  }
+
+  /**
+   * Derives type of the given call under given binding.
+   * @param binding binding to derive the type from
+   * @param node node type to derive
+   * @return datatype of the given node
+   */
+  @API(since = "1.26", status = API.Status.EXPERIMENTAL)
+  public static RelDataType deriveType(SqlCallBinding binding, SqlNode node) {
+    return binding.getValidator().deriveType(
+        requireNonNull(binding.getScope(), () -> "scope of " + binding), node);
+  }
+
+  /**
+   * Derives types for the list of nodes.
+   * @param binding binding to derive the type from
+   * @param nodes the list of nodes to derive types from
+   * @return the list of types of the given nodes
+   */
+  @API(since = "1.26", status = API.Status.EXPERIMENTAL)
+  public static List<RelDataType> deriveType(SqlCallBinding binding,
+      List<? extends SqlNode> nodes) {
+    return deriveAndCollectTypes(
+        binding.getValidator(),
+        requireNonNull(binding.getScope(), () -> "scope of " + binding),
+        nodes);
+  }
+
+  /**
    * Promotes a type to a row type (does nothing if it already is one).
    *
    * @param type      type to be promoted
@@ -212,7 +244,7 @@ public abstract class SqlTypeUtil {
       final RelDataTypeFactory typeFactory,
       final List<RelDataType> argTypes,
       RelDataType type) {
-    Objects.requireNonNull(type);
+    requireNonNull(type, "type");
     if (containsNullable(argTypes)) {
       type = typeFactory.createTypeWithNullability(type, true);
     }

Reply via email to