SQL: Fix issue with folding of CASE/IIF (#49449)
Add extra checks to prevent ConstantFolding rule to try to fold the CASE/IIF functions early before the SimplifyCase rule gets applied. Fixes: #49387 (cherry picked from commit f35c9725350e35985d8dd3001870084e1784a5ca)
This commit is contained in:
parent
49bb5fb642
commit
0c4491964b
|
@ -116,12 +116,21 @@ public class Case extends ConditionalFunction {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All foldable conditions that fold to FALSE should have
|
* All foldable conditions that fold to FALSE should have
|
||||||
* been removed by the {@link Optimizer}.
|
* been removed by the {@link Optimizer}#SimplifyCase.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean foldable() {
|
public boolean foldable() {
|
||||||
return (conditions.isEmpty() && elseResult.foldable()) ||
|
if (conditions.isEmpty() && elseResult.foldable()) {
|
||||||
(conditions.size() == 1 && conditions.get(0).condition().foldable() && conditions.get(0).result().foldable());
|
return true;
|
||||||
|
}
|
||||||
|
if (conditions.size() == 1 && conditions.get(0).condition().foldable()) {
|
||||||
|
if (conditions.get(0).condition().fold() == Boolean.TRUE) {
|
||||||
|
return conditions().get(0).result().foldable();
|
||||||
|
} else {
|
||||||
|
return elseResult().foldable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -671,6 +671,8 @@ public class OptimizerTests extends ESTestCase {
|
||||||
new IfConditional(EMPTY, new Equals(EMPTY, TWO, ONE), Literal.of(EMPTY, "bar2")),
|
new IfConditional(EMPTY, new Equals(EMPTY, TWO, ONE), Literal.of(EMPTY, "bar2")),
|
||||||
new IfConditional(EMPTY, new GreaterThan(EMPTY, getFieldAttribute(), ONE), Literal.of(EMPTY, "foo2")),
|
new IfConditional(EMPTY, new GreaterThan(EMPTY, getFieldAttribute(), ONE), Literal.of(EMPTY, "foo2")),
|
||||||
Literal.of(EMPTY, "default")));
|
Literal.of(EMPTY, "default")));
|
||||||
|
assertFalse(c.foldable());
|
||||||
|
|
||||||
Expression e = new SimplifyCase().rule(c);
|
Expression e = new SimplifyCase().rule(c);
|
||||||
assertEquals(Case.class, e.getClass());
|
assertEquals(Case.class, e.getClass());
|
||||||
c = (Case) e;
|
c = (Case) e;
|
||||||
|
@ -696,13 +698,15 @@ public class OptimizerTests extends ESTestCase {
|
||||||
// ELSE 'default'
|
// ELSE 'default'
|
||||||
// END
|
// END
|
||||||
|
|
||||||
SimplifyCase rule = new SimplifyCase();
|
|
||||||
Case c = new Case(EMPTY, Arrays.asList(
|
Case c = new Case(EMPTY, Arrays.asList(
|
||||||
new IfConditional(EMPTY, new Equals(EMPTY, getFieldAttribute(), ONE), Literal.of(EMPTY, "foo1")),
|
new IfConditional(EMPTY, new Equals(EMPTY, getFieldAttribute(), ONE), Literal.of(EMPTY, "foo1")),
|
||||||
new IfConditional(EMPTY, new Equals(EMPTY, ONE, ONE), Literal.of(EMPTY, "bar1")),
|
new IfConditional(EMPTY, new Equals(EMPTY, ONE, ONE), Literal.of(EMPTY, "bar1")),
|
||||||
new IfConditional(EMPTY, new Equals(EMPTY, TWO, ONE), Literal.of(EMPTY, "bar2")),
|
new IfConditional(EMPTY, new Equals(EMPTY, TWO, ONE), Literal.of(EMPTY, "bar2")),
|
||||||
new IfConditional(EMPTY, new GreaterThan(EMPTY, getFieldAttribute(), ONE), Literal.of(EMPTY, "foo2")),
|
new IfConditional(EMPTY, new GreaterThan(EMPTY, getFieldAttribute(), ONE), Literal.of(EMPTY, "foo2")),
|
||||||
Literal.of(EMPTY, "default")));
|
Literal.of(EMPTY, "default")));
|
||||||
|
assertFalse(c.foldable());
|
||||||
|
|
||||||
|
SimplifyCase rule = new SimplifyCase();
|
||||||
Expression e = rule.rule(c);
|
Expression e = rule.rule(c);
|
||||||
assertEquals(Case.class, e.getClass());
|
assertEquals(Case.class, e.getClass());
|
||||||
c = (Case) e;
|
c = (Case) e;
|
||||||
|
@ -713,7 +717,7 @@ public class OptimizerTests extends ESTestCase {
|
||||||
assertEquals(TypeResolution.TYPE_RESOLVED, c.typeResolved());
|
assertEquals(TypeResolution.TYPE_RESOLVED, c.typeResolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSimplifyCaseConditionsFoldCompletely() {
|
public void testSimplifyCaseConditionsFoldCompletely_FoldableElse() {
|
||||||
// CASE WHEN 1 = 2 THEN 'foo1'
|
// CASE WHEN 1 = 2 THEN 'foo1'
|
||||||
// WHEN 1 = 1 THEN 'foo2'
|
// WHEN 1 = 1 THEN 'foo2'
|
||||||
// ELSE 'default'
|
// ELSE 'default'
|
||||||
|
@ -723,11 +727,13 @@ public class OptimizerTests extends ESTestCase {
|
||||||
//
|
//
|
||||||
// 'foo2'
|
// 'foo2'
|
||||||
|
|
||||||
SimplifyCase rule = new SimplifyCase();
|
|
||||||
Case c = new Case(EMPTY, Arrays.asList(
|
Case c = new Case(EMPTY, Arrays.asList(
|
||||||
new IfConditional(EMPTY, new Equals(EMPTY, ONE, TWO), Literal.of(EMPTY, "foo1")),
|
new IfConditional(EMPTY, new Equals(EMPTY, ONE, TWO), Literal.of(EMPTY, "foo1")),
|
||||||
new IfConditional(EMPTY, new Equals(EMPTY, ONE, ONE), Literal.of(EMPTY, "foo2")),
|
new IfConditional(EMPTY, new Equals(EMPTY, ONE, ONE), Literal.of(EMPTY, "foo2")),
|
||||||
Literal.of(EMPTY, "default")));
|
Literal.of(EMPTY, "default")));
|
||||||
|
assertFalse(c.foldable());
|
||||||
|
|
||||||
|
SimplifyCase rule = new SimplifyCase();
|
||||||
Expression e = rule.rule(c);
|
Expression e = rule.rule(c);
|
||||||
assertEquals(Case.class, e.getClass());
|
assertEquals(Case.class, e.getClass());
|
||||||
c = (Case) e;
|
c = (Case) e;
|
||||||
|
@ -738,9 +744,34 @@ public class OptimizerTests extends ESTestCase {
|
||||||
assertEquals(TypeResolution.TYPE_RESOLVED, c.typeResolved());
|
assertEquals(TypeResolution.TYPE_RESOLVED, c.typeResolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSimplifyIif_ConditionTrue() {
|
public void testSimplifyCaseConditionsFoldCompletely_NonFoldableElse() {
|
||||||
|
// CASE WHEN 1 = 2 THEN 'foo1'
|
||||||
|
// ELSE myField
|
||||||
|
// END
|
||||||
|
//
|
||||||
|
// ==>
|
||||||
|
//
|
||||||
|
// myField (non-foldable)
|
||||||
|
|
||||||
|
Case c = new Case(EMPTY, Arrays.asList(
|
||||||
|
new IfConditional(EMPTY, new Equals(EMPTY, ONE, TWO), Literal.of(EMPTY, "foo1")),
|
||||||
|
getFieldAttribute("myField")));
|
||||||
|
assertFalse(c.foldable());
|
||||||
|
|
||||||
|
SimplifyCase rule = new SimplifyCase();
|
||||||
|
Expression e = rule.rule(c);
|
||||||
|
assertEquals(Case.class, e.getClass());
|
||||||
|
c = (Case) e;
|
||||||
|
assertEquals(0, c.conditions().size());
|
||||||
|
assertFalse(c.foldable());
|
||||||
|
assertEquals("myField", Expressions.name(c.elseResult()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimplifyIif_ConditionTrue_FoldableResult() {
|
||||||
SimplifyCase rule = new SimplifyCase();
|
SimplifyCase rule = new SimplifyCase();
|
||||||
Iif iif = new Iif(EMPTY, new Equals(EMPTY, ONE, ONE), Literal.of(EMPTY, "foo"), Literal.of(EMPTY, "bar"));
|
Iif iif = new Iif(EMPTY, new Equals(EMPTY, ONE, ONE), Literal.of(EMPTY, "foo"), Literal.of(EMPTY, "bar"));
|
||||||
|
assertTrue(iif.foldable());
|
||||||
|
|
||||||
Expression e = rule.rule(iif);
|
Expression e = rule.rule(iif);
|
||||||
assertEquals(Iif.class, e.getClass());
|
assertEquals(Iif.class, e.getClass());
|
||||||
iif = (Iif) e;
|
iif = (Iif) e;
|
||||||
|
@ -750,9 +781,26 @@ public class OptimizerTests extends ESTestCase {
|
||||||
assertEquals(TypeResolution.TYPE_RESOLVED, iif.typeResolved());
|
assertEquals(TypeResolution.TYPE_RESOLVED, iif.typeResolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSimplifyIif_ConditionFalse() {
|
public void testSimplifyIif_ConditionTrue_NonFoldableResult() {
|
||||||
|
SimplifyCase rule = new SimplifyCase();
|
||||||
|
Iif iif = new Iif(EMPTY, new Equals(EMPTY, ONE, ONE), getFieldAttribute("myField"), Literal.of(EMPTY, "bar"));
|
||||||
|
assertFalse(iif.foldable());
|
||||||
|
|
||||||
|
Expression e = rule.rule(iif);
|
||||||
|
assertEquals(Iif.class, e.getClass());
|
||||||
|
iif = (Iif) e;
|
||||||
|
assertEquals(1, iif.conditions().size());
|
||||||
|
assertFalse(iif.foldable());
|
||||||
|
assertTrue(iif.conditions().get(0).condition().foldable());
|
||||||
|
assertEquals(Boolean.TRUE, iif.conditions().get(0).condition().fold());
|
||||||
|
assertEquals("myField", Expressions.name(iif.conditions().get(0).result()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimplifyIif_ConditionFalse_FoldableResult() {
|
||||||
SimplifyCase rule = new SimplifyCase();
|
SimplifyCase rule = new SimplifyCase();
|
||||||
Iif iif = new Iif(EMPTY, new Equals(EMPTY, ONE, TWO), Literal.of(EMPTY, "foo"), Literal.of(EMPTY, "bar"));
|
Iif iif = new Iif(EMPTY, new Equals(EMPTY, ONE, TWO), Literal.of(EMPTY, "foo"), Literal.of(EMPTY, "bar"));
|
||||||
|
assertTrue(iif.foldable());
|
||||||
|
|
||||||
Expression e = rule.rule(iif);
|
Expression e = rule.rule(iif);
|
||||||
assertEquals(Iif.class, e.getClass());
|
assertEquals(Iif.class, e.getClass());
|
||||||
iif = (Iif) e;
|
iif = (Iif) e;
|
||||||
|
@ -762,6 +810,19 @@ public class OptimizerTests extends ESTestCase {
|
||||||
assertEquals(TypeResolution.TYPE_RESOLVED, iif.typeResolved());
|
assertEquals(TypeResolution.TYPE_RESOLVED, iif.typeResolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testSimplifyIif_ConditionFalse_NonFoldableResult() {
|
||||||
|
SimplifyCase rule = new SimplifyCase();
|
||||||
|
Iif iif = new Iif(EMPTY, new Equals(EMPTY, ONE, TWO), Literal.of(EMPTY, "foo"), getFieldAttribute("myField"));
|
||||||
|
assertFalse(iif.foldable());
|
||||||
|
|
||||||
|
Expression e = rule.rule(iif);
|
||||||
|
assertEquals(Iif.class, e.getClass());
|
||||||
|
iif = (Iif) e;
|
||||||
|
assertEquals(0, iif.conditions().size());
|
||||||
|
assertFalse(iif.foldable());
|
||||||
|
assertEquals("myField", Expressions.name(iif.elseResult()));
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Logical simplifications
|
// Logical simplifications
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue