diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/NullPolicy.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/NullPolicy.java index 4000f97620b8..06cd896d4aa6 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/NullPolicy.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/NullPolicy.java @@ -38,5 +38,9 @@ public enum NullPolicy { ANY, /** If the first argument is null, return null. */ ARG0, + /** Never returns null no matter the values of the arguments. */ + NEVER, + /** Returns null under certain conditions that depend entirely on the operator/function. + * Operators using this policy have custom rules for when to return null.*/ NONE } diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java index ca8f93feb9fe..508c5c36ad72 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java @@ -1138,9 +1138,9 @@ void populate2() { define(NOT_SUBMULTISET_OF, NotImplementor.of(subMultisetImplementor)); define(COALESCE, new CoalesceImplementor()); - define(CAST, new CastImplementor()); - define(SAFE_CAST, new CastImplementor()); - define(TRY_CAST, new CastImplementor()); + define(CAST, new CastImplementor(NullPolicy.STRICT)); + define(SAFE_CAST, new CastImplementor(NullPolicy.SEMI_STRICT)); + define(TRY_CAST, new CastImplementor(NullPolicy.SEMI_STRICT)); define(REINTERPRET, new ReinterpretImplementor()); define(CONVERT, new ConvertImplementor()); @@ -1539,6 +1539,20 @@ public TableFunctionCallImplementor get(final SqlWindowTableFunction operator) { } } + /** + * Returns the NullPolicy for the specified operator. + * + * @param operator the operator + * @return the NullPolicy for the specified operator, or null if a policy is undefined. + */ + public @Nullable NullPolicy getPolicy(SqlOperator operator) { + final RexCallImplementor implementor = get(operator); + if (implementor instanceof AbstractRexCallImplementor) { + return ((AbstractRexCallImplementor) implementor).nullPolicy; + } + return null; + } + static Expression optimize(Expression expression) { return expression.accept(new OptimizeShuttle()); } @@ -3644,8 +3658,8 @@ private static Expression implementRecurse(RexToLixTranslator translator, /** Implementor for the SQL {@code CAST} operator. */ private static class CastImplementor extends AbstractRexCallImplementor { - CastImplementor() { - super("cast", NullPolicy.STRICT, false); + CastImplementor(NullPolicy nullPolicy) { + super("cast", nullPolicy, false); } @Override Expression implementSafe(final RexToLixTranslator translator, @@ -4392,6 +4406,7 @@ private List unboxIfNecessary(final List argValueList) { switch (nullPolicy) { case STRICT: case SEMI_STRICT: + case NEVER: return Util.transform(argValueList, AbstractRexCallImplementor::unboxExpression); case ARG0: @@ -4544,7 +4559,7 @@ private static class LogicalOrImplementor extends AbstractRexCallImplementor { */ private static class LogicalNotImplementor extends AbstractRexCallImplementor { LogicalNotImplementor() { - super("logical_not", NullPolicy.NONE, true); + super("logical_not", NullPolicy.STRICT, true); } @Override Expression implementSafe(final RexToLixTranslator translator, @@ -4714,7 +4729,7 @@ private static class PiImplementor extends AbstractRexCallImplementor { /** Implementor for the {@code IS FALSE} SQL operator. */ private static class IsFalseImplementor extends AbstractRexCallImplementor { IsFalseImplementor() { - super("is_false", NullPolicy.STRICT, false); + super("is_false", NullPolicy.NEVER, false); } @Override Expression getIfTrue(Type type, final List argValueList) { @@ -4730,7 +4745,7 @@ private static class IsFalseImplementor extends AbstractRexCallImplementor { /** Implementor for the {@code IS NOT FALSE} SQL operator. */ private static class IsNotFalseImplementor extends AbstractRexCallImplementor { IsNotFalseImplementor() { - super("is_not_false", NullPolicy.STRICT, false); + super("is_not_false", NullPolicy.NEVER, false); } @Override Expression getIfTrue(Type type, final List argValueList) { @@ -4746,7 +4761,7 @@ private static class IsNotFalseImplementor extends AbstractRexCallImplementor { /** Implementor for the {@code IS NOT NULL} SQL operator. */ private static class IsNotNullImplementor extends AbstractRexCallImplementor { IsNotNullImplementor() { - super("is_not_null", NullPolicy.STRICT, false); + super("is_not_null", NullPolicy.NEVER, false); } @Override Expression getIfTrue(Type type, final List argValueList) { @@ -4762,7 +4777,7 @@ private static class IsNotNullImplementor extends AbstractRexCallImplementor { /** Implementor for the {@code IS NOT TRUE} SQL operator. */ private static class IsNotTrueImplementor extends AbstractRexCallImplementor { IsNotTrueImplementor() { - super("is_not_true", NullPolicy.STRICT, false); + super("is_not_true", NullPolicy.NEVER, false); } @Override Expression getIfTrue(Type type, final List argValueList) { @@ -4778,7 +4793,7 @@ private static class IsNotTrueImplementor extends AbstractRexCallImplementor { /** Implementor for the {@code IS NULL} SQL operator. */ private static class IsNullImplementor extends AbstractRexCallImplementor { IsNullImplementor() { - super("is_null", NullPolicy.STRICT, false); + super("is_null", NullPolicy.NEVER, false); } @Override Expression getIfTrue(Type type, final List argValueList) { @@ -4794,7 +4809,7 @@ private static class IsNullImplementor extends AbstractRexCallImplementor { /** Implementor for the {@code IS NOT DISTINCT FROM} SQL operator. */ private static class IsNotDistinctFromImplementor extends AbstractRexCallImplementor { IsNotDistinctFromImplementor() { - super("is_not_distinct_from", NullPolicy.NONE, false); + super("is_not_distinct_from", NullPolicy.NEVER, false); } @Override public RexToLixTranslator.Result implement(final RexToLixTranslator translator, @@ -4840,7 +4855,7 @@ private static class IsNotDistinctFromImplementor extends AbstractRexCallImpleme /** Implementor for the {@code IS TRUE} SQL operator. */ private static class IsTrueImplementor extends AbstractRexCallImplementor { IsTrueImplementor() { - super("is_true", NullPolicy.STRICT, false); + super("is_true", NullPolicy.NEVER, false); } @Override Expression getIfTrue(Type type, final List argValueList) { diff --git a/core/src/main/java/org/apache/calcite/plan/Strong.java b/core/src/main/java/org/apache/calcite/plan/Strong.java index b92c98f56086..0c9ea6c7ce77 100644 --- a/core/src/main/java/org/apache/calcite/plan/Strong.java +++ b/core/src/main/java/org/apache/calcite/plan/Strong.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.plan; +import org.apache.calcite.adapter.enumerable.NullPolicy; import org.apache.calcite.rex.RexCall; import org.apache.calcite.rex.RexFieldAccess; import org.apache.calcite.rex.RexInputRef; @@ -35,6 +36,8 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.EnumMap; import java.util.List; @@ -116,6 +119,7 @@ public static Policy policy(SqlKind kind) { * Returns how to deduce whether a particular {@link RexNode} expression is null, * given whether its arguments are null. */ + @Deprecated public static Policy policy(RexNode rexNode) { if (rexNode instanceof RexCall) { return policy(((RexCall) rexNode).getOperator()); @@ -127,6 +131,7 @@ public static Policy policy(RexNode rexNode) { * Returns how to deduce whether a particular {@link SqlOperator} expression is null, * given whether its arguments are null. */ + @Deprecated public static Policy policy(SqlOperator operator) { if (operator.getStrongPolicyInference() != null) { return operator.getStrongPolicyInference().get(); @@ -134,6 +139,20 @@ public static Policy policy(SqlOperator operator) { return MAP.getOrDefault(operator.getKind(), Policy.AS_IS); } + /** + * Returns the {@link NullPolicy} for a given {@link SqlKind}. + * + * @param kind SqlKind + * @return NullPolicy or null if not defined + */ + public static @Nullable NullPolicy nullPolicy(SqlKind kind) { + Policy p = MAP.get(kind); + if (p != null) { + return p.nullPolicy(); + } + return null; + } + /** * Returns whether a given expression is strong. * @@ -207,14 +226,17 @@ private boolean anyNotTrue(List operands) { * expressions, and you may override methods to test hypotheses such as * "if {@code x} is null, is {@code x + y} null? */ public boolean isNull(RexNode node) { - final Policy policy = policy(node); - switch (policy) { - case NOT_NULL: - return false; - case ANY: - return anyNull(((RexCall) node).getOperands()); - default: - break; + if (node instanceof RexCall) { + RexCall call = (RexCall) node; + final NullPolicy policy = call.getOperator().getNullPolicy(); + switch (policy) { + case NEVER: + return false; + case STRICT: + return anyNull(call.getOperands()); + default: + break; + } } switch (node.getKind()) { @@ -383,6 +405,7 @@ private static Map createPolicyMap() { /** How whether an operator's operands are null affects whether a call to * that operator evaluates to null. */ + @Deprecated public enum Policy { /** This kind of expression is never null. No need to look at its arguments, * if it has any. */ @@ -397,6 +420,24 @@ public enum Policy { ANY, /** This kind of expression may be null. There is no way to rewrite. */ - AS_IS, + AS_IS; + + /** + * Returns the corresponding {@link NullPolicy}. + * + * @return the corresponding NullPolicy + */ + NullPolicy nullPolicy() { + switch (this) { + case NOT_NULL: + return NullPolicy.NEVER; + case ANY: + return NullPolicy.STRICT; + case CUSTOM: + case AS_IS: + default: + return NullPolicy.NONE; + } + } } } diff --git a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java index 4a9677c27de9..f607f813f31d 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java +++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.rex; +import org.apache.calcite.adapter.enumerable.NullPolicy; import org.apache.calcite.avatica.util.TimeUnit; import org.apache.calcite.avatica.util.TimeUnitRange; import org.apache.calcite.plan.RelOptPredicateList; @@ -1158,10 +1159,10 @@ private RexNode simplifyIs(RexCall call, RexUnknownAs unknownAs) { if (hasCustomNullabilityRules(a.getKind())) { return null; } - switch (Strong.policy(a)) { - case NOT_NULL: + switch (policy(a)) { + case NEVER: return rexBuilder.makeLiteral(true); - case ANY: + case STRICT: // "f" is a strong operator, so "f(operand0, operand1) IS NOT NULL" // simplifies to "operand0 IS NOT NULL AND operand1 IS NOT NULL" final List operands = new ArrayList<>(); @@ -1177,16 +1178,11 @@ private RexNode simplifyIs(RexCall call, RexUnknownAs unknownAs) { } } return RexUtil.composeConjunction(rexBuilder, operands); - case CUSTOM: + default: switch (a.getKind()) { case LITERAL: return rexBuilder.makeLiteral(!((RexLiteral) a).isNull()); - default: - throw new AssertionError("every CUSTOM policy needs a handler, " - + a.getKind()); } - case AS_IS: - default: return null; } } @@ -1213,10 +1209,10 @@ private RexNode simplifyIs(RexCall call, RexUnknownAs unknownAs) { if (hasCustomNullabilityRules(a.getKind())) { return null; } - switch (Strong.policy(a)) { - case NOT_NULL: + switch (policy(a)) { + case NEVER: return rexBuilder.makeLiteral(false); - case ANY: + case STRICT: // "f" is a strong operator, so "f(operand0, operand1) IS NULL" simplifies // to "operand0 IS NULL OR operand1 IS NULL" final List operands = new ArrayList<>(); @@ -1230,7 +1226,6 @@ private RexNode simplifyIs(RexCall call, RexUnknownAs unknownAs) { } } return RexUtil.composeDisjunction(rexBuilder, operands, false); - case AS_IS: default: return null; } @@ -1246,11 +1241,11 @@ private static void validateStrongPolicy(RexNode rexNode) { if (hasCustomNullabilityRules(rexNode.getKind())) { return; } - switch (Strong.policy(rexNode)) { - case NOT_NULL: + switch (policy(rexNode)) { + case NEVER: assert !rexNode.getType().isNullable(); break; - case ANY: + case STRICT: List operands = ((RexCall) rexNode).getOperands(); if (rexNode.getType().isNullable()) { assert operands.stream() @@ -1267,6 +1262,13 @@ private static void validateStrongPolicy(RexNode rexNode) { } } + private static NullPolicy policy(RexNode node) { + if (node instanceof RexCall) { + return ((RexCall) node).getOperator().getNullPolicy(); + } + return NullPolicy.NONE; + } + /** * Returns {@code true} if specified {@link SqlKind} has custom nullability rules which * depend not only on the nullability of input operands. diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java index dc8f09770997..c53905b5992c 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java @@ -16,6 +16,8 @@ */ package org.apache.calcite.sql; +import org.apache.calcite.adapter.enumerable.NullPolicy; +import org.apache.calcite.adapter.enumerable.RexImpTable; import org.apache.calcite.linq4j.Ord; import org.apache.calcite.plan.Strong; import org.apache.calcite.rel.type.RelDataType; @@ -1033,10 +1035,30 @@ public void acceptCall( * @see Strong */ @Pure + @Deprecated public @Nullable Supplier getStrongPolicyInference() { return null; } + /** + * Returns the null policy for this operator. + * + * @return the null policy for this operator + */ + public NullPolicy getNullPolicy() { + NullPolicy p = RexImpTable.INSTANCE.getPolicy(this); + if (p != null) { + return p; + } + p = Strong.nullPolicy(getKind()); + if (p != null) { + assert p == NullPolicy.NONE + : p + " policy is only defined via SqlKind for " + this.getName(); + return p; + } + return NullPolicy.NONE; + } + /** * Returns whether this is a safe operator. * diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java index 074c3103f299..717908f99414 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.sql.fun; +import org.apache.calcite.adapter.enumerable.NullPolicy; import org.apache.calcite.avatica.util.TimeUnit; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.sql.SqlAggFunction; @@ -415,7 +416,13 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable { true, ReturnTypes.BOOLEAN, InferTypes.FIRST_KNOWN, - OperandTypes.COMPARABLE_UNORDERED_COMPARABLE_UNORDERED); + OperandTypes.COMPARABLE_UNORDERED_COMPARABLE_UNORDERED) { + @Override public NullPolicy getNullPolicy() { + // Missing in RexImpTable mapping but present in Strong.Policy + // Override here till we decide where the mapping will leave. + return NullPolicy.NEVER; + } + }; /** * IS NOT DISTINCT FROM operator. Is equivalent to NOT(x @@ -832,7 +839,13 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable { 28, ReturnTypes.BOOLEAN_NOT_NULL, InferTypes.BOOLEAN, - OperandTypes.BOOLEAN); + OperandTypes.BOOLEAN) { + @Override public NullPolicy getNullPolicy() { + // Missing in RexImpTable mapping but present in Strong.Policy + // Override here till we decide where the mapping will leave. + return NullPolicy.NEVER; + } + }; public static final SqlPostfixOperator IS_UNKNOWN = new SqlPostfixOperator( @@ -841,7 +854,13 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable { 28, ReturnTypes.BOOLEAN_NOT_NULL, InferTypes.BOOLEAN, - OperandTypes.BOOLEAN); + OperandTypes.BOOLEAN) { + @Override public NullPolicy getNullPolicy() { + // Missing in RexImpTable mapping but present in Strong.Policy + // Override here till we decide where the mapping will leave. + return NullPolicy.NEVER; + } + }; public static final SqlPostfixOperator IS_A_SET = new SqlPostfixOperator( diff --git a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java index 558cedcd42ac..273f9b1bf3d6 100644 --- a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java +++ b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.rex; +import org.apache.calcite.adapter.enumerable.NullPolicy; import org.apache.calcite.avatica.util.ByteString; import org.apache.calcite.plan.RelOptPredicateList; import org.apache.calcite.plan.RelOptUtil; @@ -67,7 +68,6 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -import java.util.function.Supplier; import static org.apache.calcite.test.Matchers.isRangeSet; @@ -4170,16 +4170,16 @@ private void checkSarg(String message, Sarg sarg, /** An operator that overrides the {@link #getStrongPolicyInference} * method. */ private static class SqlSpecialOperatorWithPolicy extends SqlSpecialOperator { - private final Strong.Policy policy; + private final NullPolicy policy; private SqlSpecialOperatorWithPolicy(String name, SqlKind kind, int prec, boolean leftAssoc, SqlReturnTypeInference returnTypeInference, SqlOperandTypeInference operandTypeInference, - SqlOperandTypeChecker operandTypeChecker, Strong.Policy policy) { + SqlOperandTypeChecker operandTypeChecker, NullPolicy policy) { super(name, kind, prec, leftAssoc, returnTypeInference, operandTypeInference, operandTypeChecker); this.policy = policy; } - @Override public Supplier getStrongPolicyInference() { - return () -> policy; + @Override public NullPolicy getNullPolicy() { + return policy; } } @@ -4197,7 +4197,7 @@ private SqlSpecialOperatorWithPolicy(String name, SqlKind kind, int prec, boolea final SqlOperator opPolicyAsIs = new SqlSpecialOperatorWithPolicy("OP2", SqlKind.OTHER_FUNCTION, 0, - false, ReturnTypes.BOOLEAN, null, null, Strong.Policy.AS_IS) { + false, ReturnTypes.BOOLEAN, null, null, NullPolicy.NONE) { }; // Operator with Strong.Policy.AS_IS but not safe: no simplification can be made checkSimplifyUnchanged(rexBuilder.makeCall(opPolicyAsIs, vInt())); @@ -4206,7 +4206,7 @@ private SqlSpecialOperatorWithPolicy(String name, SqlKind kind, int prec, boolea final SqlOperator opPolicyAny = new SqlSpecialOperatorWithPolicy("OP3", SqlKind.OTHER_FUNCTION, 0, - false, ReturnTypes.BOOLEAN, null, null, Strong.Policy.ANY) { + false, ReturnTypes.BOOLEAN, null, null, NullPolicy.STRICT) { @Override public Boolean isSafeOperator() { return true; } diff --git a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java index 51e2aca144b9..03e0c5c387ea 100644 --- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java +++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java @@ -1479,25 +1479,25 @@ private LockWrapper exclusiveCleanDb(Connection c) throws SQLException { + "WHERE\n" + " \"content-owner\" IN (?)") .planHasSql("SELECT " - + "\"t2\".\"DNAME\" AS \"content-format-owner\", " - + "\"t2\".\"DNAME0\" || ' ' AS \"content-owner\"\n" - + "FROM (SELECT \"t\".\"DEPTNO\" AS \"DEPTNO\", " + + "\"t3\".\"DNAME\" AS \"content-format-owner\", " + + "\"t3\".\"DNAME0\" || ' ' AS \"content-owner\"\n" + + "FROM (SELECT \"t\".\"DEPTNO\", " + "\"t0\".\"DEPTNO\" AS \"DEPTNO0\", " - + "\"t0\".\"DNAME\" AS \"DNAME\", " - + "\"t1\".\"DEPTNO\" AS \"DEPTNO1\", " - + "\"t1\".\"DNAME\" AS \"DNAME0\"\n" + + "\"t0\".\"DNAME\", " + + "CAST(\"t2\".\"DEPTNO\" AS TINYINT) AS \"DEPTNO1\", " + + "\"t2\".\"DNAME\" AS \"DNAME0\"\n" + "FROM (SELECT \"DEPTNO\"\n" + "FROM \"SCOTT\".\"EMP\") AS \"t\"\n" + "LEFT JOIN (SELECT \"DEPTNO\", \"DNAME\"\n" + "FROM \"SCOTT\".\"DEPT\") AS \"t0\" ON \"t\".\"DEPTNO\" = \"t0\".\"DEPTNO\"\n" - + "LEFT JOIN (SELECT \"DEPTNO\", \"DNAME\"\n" - + "FROM \"SCOTT\".\"DEPT\") AS \"t1\" " - + "ON \"t\".\"DEPTNO\" = \"t1\".\"DEPTNO\"\n" - + "WHERE \"t1\".\"DNAME\" || ' ' = ?) AS \"t2\"\n" + + "INNER JOIN (SELECT \"DEPTNO\", \"DNAME\"\n" + + "FROM \"SCOTT\".\"DEPT\"\n" + + "WHERE \"DNAME\" || ' ' = ?) AS \"t2\" " + + "ON \"t\".\"DEPTNO\" = \"t2\".\"DEPTNO\") AS \"t3\"\n" + "LEFT JOIN (SELECT \"DEPTNO\"\n" - + "FROM \"SCOTT\".\"EMP\") AS \"t3\" " - + "ON \"t2\".\"DEPTNO\" = \"t3\".\"DEPTNO\"\n" - + "GROUP BY \"t2\".\"DNAME\", \"t2\".\"DNAME0\"") + + "FROM \"SCOTT\".\"EMP\") AS \"t4\" " + + "ON \"t3\".\"DEPTNO\" = \"t4\".\"DEPTNO\"\n" + + "GROUP BY \"t3\".\"DNAME\", \"t3\".\"DNAME0\"") .runs(); } diff --git a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java index b11a96845827..c729d5130891 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.test; +import org.apache.calcite.adapter.enumerable.NullPolicy; import org.apache.calcite.avatica.util.ByteString; import org.apache.calcite.avatica.util.DateTimeUtils; import org.apache.calcite.config.CalciteConnectionProperty; @@ -23,7 +24,6 @@ import org.apache.calcite.linq4j.function.Function1; import org.apache.calcite.linq4j.function.Function2; import org.apache.calcite.linq4j.tree.Types; -import org.apache.calcite.plan.Strong; import org.apache.calcite.rel.type.DelegatingTypeSystem; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; @@ -17581,9 +17581,9 @@ void testCastTruncates(CastType castType, SqlOperatorFixture f) { || s.matches("MOD\\(.*, 0\\)")) { continue; } - final Strong.Policy policy = Strong.policy(op); + final NullPolicy policy = op.getNullPolicy(); try { - if (nullCount > 0 && policy == Strong.Policy.ANY) { + if (nullCount > 0 && policy == NullPolicy.STRICT) { f.checkNull(s); } else { final String query;