You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@calcite.apache.org by "Ruben Q L (Jira)" <ji...@apache.org> on 2020/11/27 07:55:00 UTC

[jira] [Resolved] (CALCITE-4414) RelMdSelectivity#getSelectivity for Calc can propagate a predicate with wrong references

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

Ruben Q L resolved CALCITE-4414.
--------------------------------
    Resolution: Fixed

Fixed via https://github.com/apache/calcite/commit/b4e399cb35224d8c8d55f02b7cf2b9649a3b28a4

> 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
>              Labels: pull-request-available
>             Fix For: 1.27.0
>
>          Time Spent: 40m
>  Remaining Estimate: 0h
>
> {{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.
> Note I: in a similar situation, RelM uses{{ RelOptUtil.pushPastProject}} (which "Converts an expression that is based on the output fields of a Project to an equivalent expression on the Project's input fields.") to convert the predicate before passing it to the Project's input.
> Note II: 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)