[Bug] Fix duplicate columns in case when statement (#4693)

Fix #4692
The reason of this bug is case-when statement may produce implicit CastExpr<SlotRef>
as SelectListItem in analyze step.
And these CastExpr<SlotRef> in SelectList will not be re-anlyze after rewrite step,
which will result in the incorrect number of self-incrementing SlotDescriptor ID in resultExprs .

So we need to reset the analysis state of CastExpr<SlotRef> in rewrite step.
This commit is contained in:
xy720
2020-10-10 21:16:00 +08:00
committed by GitHub
parent f3cdf167d1
commit 6ab858bb10
4 changed files with 28 additions and 3 deletions

View File

@ -281,6 +281,18 @@ public class CaseExpr extends Expr {
LiteralExpr caseExpr;
int startIndex = 0;
int endIndex = expr.getChildren().size();
// CastExpr contains SlotRef child should be reset to re-analyze in selectListItem
for (Expr child : expr.getChildren()) {
if (child instanceof CastExpr && (child.contains(SlotRef.class))) {
List<CastExpr> castExprList = Lists.newArrayList();
child.collect(CastExpr.class, castExprList);
for (CastExpr castExpr : castExprList) {
castExpr.resetAnalysisState();
}
}
}
if (expr.hasCaseExpr()) {
// just deal literal here
// and avoid `float compute` in java,float should be dealt in be

View File

@ -207,7 +207,9 @@ public class CastExpr extends Expr {
@Override
public void analyzeImpl(Analyzer analyzer) throws AnalysisException {
Preconditions.checkState(!isImplicit);
if (isImplicit) {
return;
}
// When cast target type is string and it's length is default -1, the result length
// of cast is decided by child.
if (targetTypeDef.getType().isScalarType()) {

View File

@ -93,6 +93,7 @@ public class SlotRef extends Expr {
}
public SlotDescriptor getDesc() {
Preconditions.checkState(isAnalyzed);
Preconditions.checkNotNull(desc);
return desc;
}

View File

@ -917,10 +917,20 @@ public class QueryPlanTest {
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql52),
"OUTPUT EXPRS: `k7`"));
// 5.3 test different in then expr and else expr, and return CastExpr<SlotRef>
// 5.3 test different type in then expr and else expr, and return CastExpr<SlotRef>
String sql53 = "select case when 2 < 1 then 'all' else k1 end as col53 from test.baseall group by col53";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql53),
"OUTPUT EXPRS:<slot 0> `k1`"));
"OUTPUT EXPRS: `k1`"));
// 5.4 test return CastExpr<SlotRef> with other SlotRef in selectListItem
String sql54 = "select k2, case when 2 < 1 then 'all' else k1 end as col54, k7 from test.baseall group by k2, col54, k7";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql54),
"OUTPUT EXPRS:<slot 3> `k2` | <slot 4> `k1` | <slot 5> `k7`"));
// 5.5 test return CastExpr<CastExpr<SlotRef>> with other SlotRef in selectListItem
String sql55 = "select case when 2 < 1 then 'all' else cast(k1 as int) end as col55, k7 from test.baseall group by col55, k7";
Assert.assertTrue(StringUtils.containsIgnoreCase(UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql55),
"OUTPUT EXPRS:<slot 2> CAST(`k1` AS INT) | <slot 3> `k7`"));
}
@Test