Skip to content

Commit

Permalink
[fix](nereids) count in correlated subquery shoud not output null val…
Browse files Browse the repository at this point in the history
…ue (apache#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
  • Loading branch information
starocean999 authored and superdiaodiao committed Nov 21, 2023
1 parent be11c68 commit c42b9f2
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,11 @@
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;
Expand Down Expand Up @@ -167,7 +170,21 @@ public Expression visitUnboundFunction(UnboundFunction unboundFunction, Expressi
// 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;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ suite("test_subquery") {
contains("VAGGREGATE")
}

explain {
sql """SELECT * FROM table_1000_undef_undef t1 WHERE t1.pk <= (SELECT COUNT(t2.pk) FROM table_1000_undef_undef2 t2 WHERE (t1.col_bigint_undef_signed = t2.col_bigint_undef_signed)); """
contains("ifnull")
}

sql """DROP TABLE IF EXISTS table_1000_undef_undef"""
sql """DROP TABLE IF EXISTS table_1000_undef_undef2"""

Expand Down

0 comments on commit c42b9f2

Please sign in to comment.