Vladimir Sitnikov created CALCITE-7850:
------------------------------------------

             Summary: RexSimplify does not simplify "a = CAST(ARRAY[...]) AND a 
= CAST(ARRAY[...])" to FALSE when the arrays differ
                 Key: CALCITE-7850
                 URL: https://issues.apache.org/jira/browse/CALCITE-7850
             Project: Calcite
          Issue Type: Improvement
          Components: core
    Affects Versions: 1.42.0
            Reporter: Vladimir Sitnikov


A filter on a {{VARCHAR ARRAY}} column that compares the column with two 
different array constructors is not simplified to {{FALSE}}:

{code:sql}
select *
from (values (cast(array['a', 'b'] as varchar array))) as t(u)
where u = array['/flink.jpg', '/flink_1.jpg']
  and u = array['/f.jpg', '/f_1.jpg']
{code}

After {{CoreRules.FILTER_REDUCE_EXPRESSIONS}} the plan keeps both conjuncts:

{noformat}
LogicalProject(U=[$0])
  LogicalFilter(condition=[AND(=($0, CAST(ARRAY('/flink.jpg  ', 
'/flink_1.jpg')):VARCHAR NOT NULL ARRAY NOT NULL), =($0, CAST(ARRAY('/f.jpg  ', 
'/f_1.jpg')):VARCHAR NOT NULL ARRAY NOT NULL))])
    LogicalProject(U=[CAST(ARRAY('a', 'b')):VARCHAR NOT NULL ARRAY NOT NULL])
      LogicalValues(tuples=[[{ 0 }]])
{noformat}

Each array constructor is cast to the column type, {{VARCHAR NOT NULL ARRAY NOT 
NULL}}. The trailing spaces come from the {{CHAR(12)}} and {{CHAR(8)}} element 
types of the constructors; the reproducer below uses unpadded literals and 
fails the same way. This is the shape from FLINK-32188, which CALCITE-5733 was 
filed for (see [this 
comment|https://issues.apache.org/jira/browse/CALCITE-5733?focusedCommentId=17727467#comment-17727467]).

When the array constructor already has the column type, no cast is added and 
the filter is simplified: for an {{INTEGER ARRAY}} column, {{where u = 
array[1,2] and u = array[2,3]}} becomes {{LogicalValues(tuples=[[]])}}, and 
{{RexProgramTest.testSimplifyArrayEquality}} covers {{a = ARRAY[1,2] AND a = 
ARRAY[2,3]}} since CALCITE-5733.

*Expected:* the SQL above plans to {{LogicalValues(tuples=[[]])}}, and 
{{RexSimplify}} in unknown-as-false mode simplifies the cast condition in the 
test below to {{false}}, as it does for the uncast {{VARCHAR ARRAY}} 
constructors in the same test.

Add this test to {{RexProgramTest}}; it uses that class's helpers. On 
843f468405 (1.43.0-SNAPSHOT) the first assertion passes and the second fails:

{code:java}
@Test void testSimplifyCastArrayEquality() {
  final RelDataType varcharArray = tArray(tVarchar());
  final RexNode u = input(varcharArray, 0);
  // Control: constructors of the column type, no cast
  final RexNode b1 =
      rexBuilder.makeCall(varcharArray, 
SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR,
          ImmutableList.of(literal("/flink.jpg"), literal("/flink_1.jpg")));
  final RexNode b2 =
      rexBuilder.makeCall(varcharArray, 
SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR,
          ImmutableList.of(literal("/f.jpg"), literal("/f_1.jpg")));
  checkSimplifyFilter(and(eq(u, b1), eq(u, b2)), "false");
  // Fails: constructors cast to the column type
  final RexNode a1 =
      rexBuilder.makeCast(varcharArray,
          rexBuilder.makeCall(SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR,
              literal("/flink.jpg"), literal("/flink_1.jpg")));
  final RexNode a2 =
      rexBuilder.makeCast(varcharArray,
          rexBuilder.makeCall(SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR,
              literal("/f.jpg"), literal("/f_1.jpg")));
  checkSimplifyFilter(and(eq(u, a1), eq(u, a2)), "false");
}
{code}

{noformat}
java.lang.AssertionError: simplify(unknown as FALSE): AND(=($0, 
CAST(ARRAY('/flink.jpg', '/flink_1.jpg')):VARCHAR NOT NULL ARRAY NOT NULL), 
=($0, CAST(ARRAY('/f.jpg', '/f_1.jpg')):VARCHAR NOT NULL ARRAY NOT NULL))
Expected: with toString() is "false"
     but: toString() was "AND(=($0, CAST(ARRAY('/flink.jpg', 
'/flink_1.jpg')):VARCHAR NOT NULL ARRAY NOT NULL), =($0, CAST(ARRAY('/f.jpg', 
'/f_1.jpg')):VARCHAR NOT NULL ARRAY NOT NULL))"
{noformat}

*Possible cause (a guess; the report above stands without it):* 
{{RexSimplify.isConstant}}, added in CALCITE-5733, accepts a literal or an 
{{ARRAY}} or {{MULTISET}} constructor of constants, and rejects a {{CAST}} 
around one. Accepting the cast is not enough by itself: a cast can map 
different constructors to equal values, for example {{CAST(ARRAY[1.1] AS 
INTEGER ARRAY)}} and {{CAST(ARRAY[1.2] AS INTEGER ARRAY)}} both evaluate to 
{{ARRAY[1]}}, so the two constants have to be compared after the cast, not as 
expressions.



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

Reply via email to