[BugFix] Lead/Lag with specified default value can not adopt low-cardinality optimization (#63554)

Signed-off-by: satanson <ranpanf@gmail.com>
This commit is contained in:
satanson 2025-09-25 18:34:32 +08:00 committed by GitHub
parent 03c31659c2
commit aec060a697
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 1 deletions

View File

@ -586,12 +586,23 @@ public class DecodeCollector extends OptExpressionVisitor<DecodeInfo, DecodeInfo
ColumnRefSet disableColumns = new ColumnRefSet();
for (ColumnRefOperator key : windowOp.getAnalyticCall().keySet()) {
CallOperator windowCallOp = windowOp.getAnalyticCall().get(key);
if (!LOW_CARD_WINDOW_FUNCTIONS.contains(windowCallOp.getFnName())) {
String fnName = windowCallOp.getFnName();
if (!LOW_CARD_WINDOW_FUNCTIONS.contains(fnName)) {
disableColumns.union(windowCallOp.getUsedColumns());
disableColumns.union(key);
continue;
}
// LEAD/LAG with specified default value can not adopt low-cardinality optimization
if ((fnName.equals(FunctionSet.LEAD) || fnName.equals(FunctionSet.LAG))) {
ScalarOperator lastArg = windowCallOp.getArguments().get(windowCallOp.getArguments().size() - 1);
if (!lastArg.isConstantNull()) {
disableColumns.union(windowCallOp.getUsedColumns());
disableColumns.union(key);
continue;
}
}
Map<Boolean, List<ScalarOperator>> argGroups = windowCallOp.getChildren().stream()
.filter(Predicate.not(ScalarOperator::isConstant))
.collect(Collectors.partitioningBy(ScalarOperator::isColumnRef));

View File

@ -959,6 +959,38 @@ public class LowCardinalityArrayTest extends PlanTestBase {
}
}
@Test
public void testNotSupportedWindowFunctionLeadLagWithSpecifiedDefaultValue() throws Exception {
String sqlFmt = "with cte as(\n" +
" select s1.v1, s1.v2, t.a1 a1\n" +
" from s1,unnest(s1.a1)t(a1) \n" +
")\n" +
"select v1, a1, {WINDOW_FUN}(a1, 1, 'ABCD') over(partition by v1)\n" +
"from cte;";
String[] windowFuncs = new String[] {
FunctionSet.LEAD,
FunctionSet.LAG
};
for (String wf : windowFuncs) {
String q = sqlFmt.replace("{WINDOW_FUN}", wf);
String plan = getVerboseExplain(q);
String[] lines = plan.split("\n");
List<Integer> decodeNodeLines = IntStream.range(0, lines.length).boxed()
.filter(lineno -> lines[lineno]
.matches("^\\s*\\d+:Decode\\s*$"))
.collect(Collectors.toList());
List<Integer> analyticNodeLines = IntStream.range(0, lines.length).boxed()
.filter(lineno -> lines[lineno]
.matches("^\\s*\\d+:ANALYTIC\\s*$"))
.collect(Collectors.toList());
Assertions.assertEquals(1, decodeNodeLines.size(), plan);
Assertions.assertEquals(1, analyticNodeLines.size(), plan);
Assertions.assertTrue(decodeNodeLines.get(0) > analyticNodeLines.get(0), plan);
}
}
@Test
public void testdWindowFunctionCount() throws Exception {
String sql1 = "with cte as(\n" +