[fix](nereids) count in correlated subquery shoud not output null value (#27064)

consider sql: 

SELECT * FROM t1 WHERE t1.a <= (SELECT COUNT(t2.a) FROM t2 WHERE (t1.b = t2.b));

when unnest correlated subquery, we create a left join node.
Assume outer query is left table and subquery is right one.
If there is no match, the row from right table is filled with nulls.
But COUNT function is always not nullable. 
So wrap COUNT with Nvl to ensure it's result is 0 instead of null to get the correct result
This commit is contained in:
starocean999
2023-11-17 12:31:42 +08:00
committed by GitHub
parent 4ac460af28
commit 06f0c10c8b
2 changed files with 23 additions and 1 deletions

View File

@ -49,8 +49,11 @@ import org.apache.doris.nereids.trees.expressions.TimestampArithmetic;
import org.apache.doris.nereids.trees.expressions.WhenClause;
import org.apache.doris.nereids.trees.expressions.functions.BoundFunction;
import org.apache.doris.nereids.trees.expressions.functions.FunctionBuilder;
import org.apache.doris.nereids.trees.expressions.functions.agg.Count;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Lambda;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Nvl;
import org.apache.doris.nereids.trees.expressions.functions.udf.AliasUdfBuilder;
import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
import org.apache.doris.nereids.trees.expressions.typecoercion.ImplicitCastInputTypes;
import org.apache.doris.nereids.types.ArrayType;
import org.apache.doris.nereids.types.BigIntType;
@ -167,7 +170,21 @@ public class FunctionBinder extends AbstractExpressionRewriteRule {
// we do type coercion in build function in alias function, so it's ok to return directly.
return builder.build(functionName, arguments);
} else {
return TypeCoercionUtils.processBoundFunction((BoundFunction) builder.build(functionName, arguments));
Expression boundFunction = TypeCoercionUtils
.processBoundFunction((BoundFunction) builder.build(functionName, arguments));
if (boundFunction instanceof Count
&& context.cascadesContext.getOuterScope().isPresent()
&& !context.cascadesContext.getOuterScope().get().getCorrelatedSlots()
.isEmpty()) {
// consider sql: SELECT * FROM t1 WHERE t1.a <= (SELECT COUNT(t2.a) FROM t2 WHERE (t1.b = t2.b));
// when unnest correlated subquery, we create a left join node.
// outer query is left table and subquery is right one
// if there is no match, the row from right table is filled with nulls
// but COUNT function is always not nullable.
// so wrap COUNT with Nvl to ensure it's result is 0 instead of null to get the correct result
boundFunction = new Nvl(boundFunction, new BigIntLiteral(0));
}
return boundFunction;
}
}