Skip to content

[CALCITE-3926] CannotPlanException when an empty LogicalValues requires a certain collation#1918

Merged
rubenada merged 1 commit intoapache:masterfrom
rubenada:CALCITE-3926
May 7, 2020
Merged

[CALCITE-3926] CannotPlanException when an empty LogicalValues requires a certain collation#1918
rubenada merged 1 commit intoapache:masterfrom
rubenada:CALCITE-3926

Conversation

@rubenada
Copy link
Contributor

Jira: CALCITE-3926

@rubenada
Copy link
Contributor Author

Maybe the same fix should be applied to PruneEmptyRules.SORT_FETCH_ZERO_INSTANCE ...

emptyValues = emptyValues.copy(
emptyValues.getTraitSet().replace(((Sort) single).getCollation()),
Collections.emptyList());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not only sort, but all the operators can have the same issue.
We should update emptyValues to have the same traits with single. Just collation is not enough, should be all the traits.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should put the trait logic in RelBuilder#empty ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can try. But if only empty() considers the trait logic, the other methods don't, that might look odd.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @hsyuan . This trait replacement is a one-off thing just for PruneEmptyRule. I am not convinced it should be available in RelBuilder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Trait propagation applied to all RemoveEmptySingleRule instances (AGGREGATE, FILTER, PROJECT, SORT) + SORT_FETCH_ZERO_INSTANCE.
What about the rest of PruneEmptyRules (MINUS, UNION, INTERSECT, JOIN_LEFT, JOIN_RIGHT)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused, EmptyValues has no data, so what's the meaning of collation and distribution on it ?

Copy link
Contributor Author

@rubenada rubenada Apr 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collation is required in order to solve this bug, since we are removing the Sort:
Sort + EmptyValues => EmptyValues
if the resulting empty values does not have the sort's collation, we get a CannotPlanException. See https://issues.apache.org/jira/browse/CALCITE-3926 for more details.
Therefore, in order to fix this problem it seems clear that we need to propagate the collation into the EmptyValues. Another discussion would be what about other traits, like distribution....

Copy link
Contributor

@danny0405 danny0405 Apr 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Therefore, in order to fix this problem it seems clear that we need to propagate the collation into the EmptyValues.

Not really from my side, to me, it seems that the traits check should be tweaked for EmptyValues, it should satisfy all the required traits, the EmptyValues itself does nothing wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks an interesting approach @danny0405 . I guess we could tweak EmptyValues to satisfy any collation... will work on that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, I cannot find a clean way of tweaking EmptyValues' collation to satisfy any collation. Since propagating all traits into EmptyValues did not work either, I am going back to the original solution of propagating just collation into EmptyValues if we are removing a Sort from the plan.

.replaceIf(RelDistributionTraitDef.INSTANCE,
() -> RelMdDistribution.values(rowType, tuples));
return new EnumerableValues(cluster, rowType, tuples, traitSet);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing this, can we just modify copy(traitset, inputs) method to just return new EnumerableValues(getCluster(), rowType, tuples, traitSet);?

Collections.emptyList());
}
call.transformTo(emptyValues);
RelNode result = emptyValues.copy(single.getTraitSet(), Collections.emptyList());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you change PruneEmptyRule's autoPruneOld to false, you might be able to see another error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's rigth, in that case I get:

java.lang.AssertionError
	at org.apache.calcite.rel.logical.LogicalValues.copy(LogicalValues.java:95)

Which refers to the following line:

@Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
    assert traitSet.containsIfApplicable(Convention.NONE);  // <--
    ...

Copy link
Contributor Author

@rubenada rubenada Apr 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we can solve the problem with a different approach, and it would take just one line of code, which is returning false in PruneEmptyRule's autoPruneOld (or just remove the method to not override the default SubstitutionRule's behavior):

  protected abstract static class PruneEmptyRule extends RelOptRule
      implements SubstitutionRule {
    ...
    @Override public boolean autoPruneOld() {
      return false; // this solves the problem!
    }
  }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will just hide the issue of the rule. We still get a sort in the plan.

@rubenada
Copy link
Contributor Author

@danny0405 @xndai @hsyuan Do you think we could consider merging the proposed fix? It solves this specific problem by just propagating the Sort's collation into the empty values.


/** Creates an EnumerableValues. */
public static EnumerableValues create(Values input) {
final RelOptCluster cluster = input.getCluster();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we modify the other create to support an explicit traitSet param ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the copy method should be handling that scenario

RelNode emptyValues = call.builder().push(sort).empty().build();
emptyValues = emptyValues.copy(
emptyValues.getTraitSet().replace(sort.getCollation()),
Collections.emptyList());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why only copy the Collation trait ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The (non propagation of) Collation trait is the root cause of this issue. So propagating just the Collation seems the easiest way to fix this bug (but arguably maybe not the "most correct" one).
Previously, I tried to propagate other traits as well, but it did not work as expected:
Propagating all traits does not seem a good solution. [...] there are some tests failing because of the following scenario: we have an enumerable single rel + logical empty values, so we replace the whole thing with an empty values (which in our case is a LogicalValues, as returned by RelBuilder#empty). If we try to propagate all traits it will fail, because we would be trying to propagate the EnumerableConvention towards a LogicalValues. So what should be our strategy here? Should we propagate all traits except the convention? Am I missing something in the trait propagation process?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @rubenada , i have gave a fix in [1] based on your code, hope it helps ~

[1] https://github.com/danny0405/calcite/tree/rubenada-CALCITE-3926

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @danny0405 , I have added a comment in there.

@danny0405
Copy link
Contributor

Thanks @rubenada , i have gave a fix in [1] based on your code, hope it helps ~

[1] https://github.com/danny0405/calcite/tree/rubenada-CALCITE-3926

@hsyuan
Copy link
Member

hsyuan commented May 5, 2020

I am afraid 2970 won't finish soon. @rubenada Can you take a look at my patch and bring useful ideas you think back to your patch? https://github.com/hsyuan/calcite/commit/5365272fdd69fd4ca4d3356e7c640b17e243c6d3

I don't like the fix, which looks hacky, but it should work. The more thorough fix is logical operator should not have traits and drop RelCompositeTrait completely. They are useless, and have caused so many bugs.

@rubenada
Copy link
Contributor Author

rubenada commented May 5, 2020

Thanks @hsyuan , I think your patch should work fine.
I have applied your approach in the current PR, please take a look when you have some time.

@hsyuan
Copy link
Member

hsyuan commented May 5, 2020

LGTM

@rubenada
Copy link
Contributor Author

rubenada commented May 6, 2020

Thanks @hsyuan. I have rebased and I will merge as soon as the checks pass.

@rubenada rubenada added the LGTM-will-merge-soon Overall PR looks OK. Only minor things left. label May 6, 2020
@rubenada rubenada merged commit e3fe745 into apache:master May 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

LGTM-will-merge-soon Overall PR looks OK. Only minor things left. slow-tests-needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants