[ 
https://issues.apache.org/jira/browse/CALCITE-4414?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Ruben Q L updated CALCITE-4414:
-------------------------------
    Description: 
{{RelMdSelectivity#getSelectivity(Calc rel, RelMetadataQuery mq, RexNode 
predicate)}} method:
{code}
  public Double getSelectivity(Calc rel, RelMetadataQuery mq, RexNode 
predicate) {
    final RexProgram rexProgram = rel.getProgram();
    final RexLocalRef programCondition = rexProgram.getCondition();
    if (programCondition == null) {
      return getSelectivity(rel.getInput(), mq, predicate); // [2]
    } else {
      // [1]
      return mq.getSelectivity(rel.getInput(),
          RelMdUtil.minusPreds(
              rel.getCluster().getRexBuilder(),
              predicate,
              rexProgram.expandLocalRef(programCondition)));
    }
  }
{code}
currently passes down the predicate to its input [1] without considering any 
possible translation, since the predicate might include expressions generated 
by the Calc's projections; hence when the Calc's input analyzes the predicate, 
it can end up trying to access fields that do not exist on its rowType.

This can lead to unforeseeable consequences, like the test attached to the 
first comment, where after {{RelMdSelectivity#getSelectivity(Calc)}} we reach 
{{RelMdSelectivity#getSelectivity(Union)}} and this method ends up in an 
{{ArrayIndexOutOfBoundsException}} because it tries to access a field ($1) that 
does not exists on its rowType (which only has $0). This $1 is actually 
projected by the Calc which is on top of the Union.

Notice in the code snipped above that in our test example the issue only 
happens in line [1], and not in [2] because the "if" block calls 
{{getSelectivity}} instead of {{mq.getSelectivity}}, although I find this a bit 
questionable and maybe {{mq.getSelectivity}} should be called here as well.


  was:
{{RelMdSelectivity#getSelectivity(Calc rel, RelMetadataQuery mq, RexNode 
predicate)}} method:
{code}
  public Double getSelectivity(Calc rel, RelMetadataQuery mq, RexNode 
predicate) {
    final RexProgram rexProgram = rel.getProgram();
    final RexLocalRef programCondition = rexProgram.getCondition();
    if (programCondition == null) {
      return getSelectivity(rel.getInput(), mq, predicate); // [2]
    } else {
      // [1]
      return mq.getSelectivity(rel.getInput(),
          RelMdUtil.minusPreds(
              rel.getCluster().getRexBuilder(),
              predicate,
              rexProgram.expandLocalRef(programCondition)));
    }
  }
{code}
currently passes down the predicate to its input [1] without considering any 
possible translation, since the predicate might include expressions generated 
by the Calc's projections; hence when the Calc's input analyzes the predicate, 
it can end up trying to access fields that do not exist on its rowType.

This can lead to unforeseeable consequences, like the test attached to the 
first comment, where after {{RelMdSelectivity#getSelectivity(Calc)}} we reach 
{{RelMdSelectivity#getSelectivity(Union)}} and this method ends up in an 
{{ArrayIndexOutOfBoundsException}} becaus it tries to access a field ($1) that 
does not exists on its rowType (which only has $0). This $1 is actually 
projected by the Calc which is on top of the Union.

Notice in the code snipped above that in our test example the issue only 
happens in line [1], and not in [2] because the "if" block calls 
{{getSelectivity}} instead of {{mq.getSelectivity}}, although I find this a bit 
questionable and maybe {{mq.getSelectivity}} should be called here as well.



> RelMdSelectivity#getSelectivity for Calc can propagate a predicate with wrong 
> references
> ----------------------------------------------------------------------------------------
>
>                 Key: CALCITE-4414
>                 URL: https://issues.apache.org/jira/browse/CALCITE-4414
>             Project: Calcite
>          Issue Type: Bug
>          Components: core
>            Reporter: Ruben Q L
>            Assignee: Ruben Q L
>            Priority: Major
>             Fix For: 1.27.0
>
>
> {{RelMdSelectivity#getSelectivity(Calc rel, RelMetadataQuery mq, RexNode 
> predicate)}} method:
> {code}
>   public Double getSelectivity(Calc rel, RelMetadataQuery mq, RexNode 
> predicate) {
>     final RexProgram rexProgram = rel.getProgram();
>     final RexLocalRef programCondition = rexProgram.getCondition();
>     if (programCondition == null) {
>       return getSelectivity(rel.getInput(), mq, predicate); // [2]
>     } else {
>       // [1]
>       return mq.getSelectivity(rel.getInput(),
>           RelMdUtil.minusPreds(
>               rel.getCluster().getRexBuilder(),
>               predicate,
>               rexProgram.expandLocalRef(programCondition)));
>     }
>   }
> {code}
> currently passes down the predicate to its input [1] without considering any 
> possible translation, since the predicate might include expressions generated 
> by the Calc's projections; hence when the Calc's input analyzes the 
> predicate, it can end up trying to access fields that do not exist on its 
> rowType.
> This can lead to unforeseeable consequences, like the test attached to the 
> first comment, where after {{RelMdSelectivity#getSelectivity(Calc)}} we reach 
> {{RelMdSelectivity#getSelectivity(Union)}} and this method ends up in an 
> {{ArrayIndexOutOfBoundsException}} because it tries to access a field ($1) 
> that does not exists on its rowType (which only has $0). This $1 is actually 
> projected by the Calc which is on top of the Union.
> Notice in the code snipped above that in our test example the issue only 
> happens in line [1], and not in [2] because the "if" block calls 
> {{getSelectivity}} instead of {{mq.getSelectivity}}, although I find this a 
> bit questionable and maybe {{mq.getSelectivity}} should be called here as 
> well.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to