[CALCITE-3747] Constructing BETWEEN with RelBuilder throws class cast exception

Return type inference of BETWEEN should not assume that the operator
binding is always SqlCallBinding(should be RexCallBinding if it is
constrcuted from RelBuilder).
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
index 643a150..859bcf6 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
@@ -20,7 +20,6 @@
 import org.apache.calcite.rel.type.RelDataTypeComparability;
 import org.apache.calcite.sql.ExplicitOperatorBinding;
 import org.apache.calcite.sql.SqlCall;
-import org.apache.calcite.sql.SqlCallBinding;
 import org.apache.calcite.sql.SqlInfixOperator;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlNode;
@@ -34,15 +33,9 @@
 import org.apache.calcite.sql.type.InferTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
-import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.util.SqlBasicVisitor;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
-import org.apache.calcite.util.ImmutableNullableList;
 import org.apache.calcite.util.Util;
 
-import java.util.List;
-
 import static org.apache.calcite.util.Static.RESOURCE;
 
 /**
@@ -121,29 +114,12 @@
     return negated;
   }
 
-  private List<RelDataType> collectOperandTypes(
-      SqlValidator validator,
-      SqlValidatorScope scope,
-      SqlCall call) {
-    List<RelDataType> argTypes =
-        SqlTypeUtil.deriveAndCollectTypes(
-            validator, scope, call.getOperandList());
-    return ImmutableNullableList.of(
-        argTypes.get(VALUE_OPERAND),
-        argTypes.get(LOWER_OPERAND),
-        argTypes.get(UPPER_OPERAND));
-  }
-
   public RelDataType inferReturnType(
       SqlOperatorBinding opBinding) {
-    SqlCallBinding callBinding = (SqlCallBinding) opBinding;
     ExplicitOperatorBinding newOpBinding =
         new ExplicitOperatorBinding(
             opBinding,
-            collectOperandTypes(
-                callBinding.getValidator(),
-                callBinding.getScope(),
-                callBinding.getCall()));
+            opBinding.collectOperandTypes());
     return ReturnTypes.BOOLEAN_NULLABLE.inferReturnType(
         newOpBinding);
   }
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 471152e..c91d3c1 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -3140,4 +3140,18 @@
     assertThat(error1.getMessage(),
         containsString("The top relational expression is not a Hintable"));
   }
+
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-3747">[CALCITE-3747]
+   * Constructing BETWEEN with RelBuilder throws class cast exception</a>. */
+  @Test public void testCallBetweenOperator() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RexNode call = builder.scan("EMP")
+        .call(
+            SqlStdOperatorTable.BETWEEN,
+            builder.field("EMPNO"),
+            builder.literal(1),
+            builder.literal(5));
+    assertThat(call.toStringRaw(), is("BETWEEN ASYMMETRIC($0, 1, 5)"));
+  }
 }