[ 
https://issues.apache.org/jira/browse/CALCITE-6976?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17947114#comment-17947114
 ] 

Mihai Budiu commented on CALCITE-6976:
--------------------------------------

It turns out that the operand type checking for SUBSTR never validates the 
operands at all!
As an example, the following SQL is accepted by the validator: SUBSTR('x', 'x') 
and fails at runtime.

This may be a deep bug, which may affect lots of functions which have 
"optional" arguments.

Consider this stack:

{code}
checkOperandTypes:147, FamilyOperandTypeChecker (org.apache.calcite.sql.type)
checkOperandTypes:784, SqlOperator (org.apache.calcite.sql)
validateOperands:526, SqlOperator (org.apache.calcite.sql)
deriveType:350, SqlFunction (org.apache.calcite.sql)
deriveType:232, SqlFunction (org.apache.calcite.sql)
{code}

The code reads as follows:

{code:java}
  @Override public boolean checkOperandTypes(
      SqlCallBinding callBinding,
      boolean throwOnFailure) {
    if (families.size() != callBinding.getOperandCount()) {
      // assume this is an inapplicable sub-rule of a composite rule;
      // don't throw
      return false;
    }
{code}

In this case families.size() = 3, and operandCount = 2. So no check is made, 
and nothing is thrown.
There is no code which backtracks here if this is part of a composite rule.

The 'false' result returned is ignored two levels up the stack trace:

{code}
  public final RelDataType validateOperands(SqlValidator validator,
      SqlValidatorScope scope, SqlCall call) {
    // Let subclasses know what's up.
    preValidateCall(validator, scope, call);

    // Check the number of operands
    checkOperandCount(validator, operandTypeChecker, call);

    SqlCallBinding opBinding = new SqlCallBinding(validator, scope, call);

    checkOperandTypes( 
        opBinding,
        true);

    // Now infer the result type.
    RelDataType ret = inferReturnType(opBinding);
{code}

Notice that checkOperandTypes assumes that errors have thrown, but they haven't 
in this case.





> Assertion failure while typechecking SUBSTR(TIMESTAMP, ...)
> -----------------------------------------------------------
>
>                 Key: CALCITE-6976
>                 URL: https://issues.apache.org/jira/browse/CALCITE-6976
>             Project: Calcite
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 1.39.0
>            Reporter: Mihai Budiu
>            Priority: Minor
>
> The following SqlOperatorTest will cause an assertion failure:
> {code:java}
>     final SqlOperatorFixture f = fixture()
>         .withLibrary(SqlLibrary.BIG_QUERY);
>     f.checkScalar("SUBSTR(TIMESTAMP '2020-01-01 10:00:00', 10)", "", "VARCHAR 
> NOT NULL");
> {code}
> Here is the stack trace:
> {code:java}
> java.lang.AssertionError: Was not expecting value 'TIMESTAMP' for enumeration 
> 'org.apache.calcite.sql.type.SqlTypeName' in this context
>       at org.apache.calcite.util.Util.unexpected(Util.java:1937)
>       at 
> org.apache.calcite.sql.type.SqlTypeTransforms$1.toVar(SqlTypeTransforms.java:207)
>       at 
> org.apache.calcite.sql.type.SqlTypeTransforms$1.transformType(SqlTypeTransforms.java:174)
>       at 
> org.apache.calcite.sql.type.SqlTypeTransformCascade.inferReturnType(SqlTypeTransformCascade.java:66)
>       at 
> org.apache.calcite.sql.SqlOperator.inferReturnType(SqlOperator.java:562)
>       at 
> org.apache.calcite.sql.SqlOperator.validateOperands(SqlOperator.java:531)
>       at org.apache.calcite.sql.SqlFunction.deriveType(SqlFunction.java:350)
>       at org.apache.calcite.sql.SqlFunction.deriveType(SqlFunction.java:232)
>       at 
> org.apache.calcite.sql.validate.SqlValidatorImpl$DeriveTypeVisitor.visit(SqlValidatorImpl.java:7092)
>       at 
> org.apache.calcite.sql.validate.SqlValidatorImpl$DeriveTypeVisitor.visit(SqlValidatorImpl.java:7079)
>       at org.apache.calcite.sql.SqlCall.accept(SqlCall.java:175)
>       at 
> org.apache.calcite.sql.validate.SqlValidatorImpl.deriveTypeImpl(SqlValidatorImpl.java:2028)
>       at 
> org.apache.calcite.sql.validate.SqlValidatorImpl.deriveType(SqlValidatorImpl.java:2015)
>       at org.apache.calcite.sql.SqlNode.validateExpr(SqlNode.java:277)
>       at org.apache.calcite.sql.SqlOperator.validateCall(SqlOperator.java:503)
> {code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to