Skip to content

Commit 468301d

Browse files
committed
fix(tsql): skip gap-fill on descending bucket order
A bucket-led ORDER BY DESC combined with fillGaps emitted an ascending WITH FILL (positive step, ascending bounds), which produces invalid or empty fills. Skip the gap-fill rewrite for descending orders and let the plain descending query stand. Adds a DESC fillGaps test.
1 parent c8dba56 commit 468301d

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

internal-packages/tsql/src/query/printer.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3971,4 +3971,14 @@ describe("timeBucket() fillGaps", () => {
39713971
expect(sql).not.toContain("WITH FILL");
39723972
expect(sql).not.toContain("INTERPOLATE");
39733973
});
3974+
3975+
it("bucket-led ORDER BY DESC: fill is skipped (ascending fill would be invalid)", () => {
3976+
const query =
3977+
"SELECT timeBucket(), count() AS runs FROM metrics GROUP BY timeBucket ORDER BY timeBucket DESC";
3978+
const { sql } = run(query, true);
3979+
expect(sql).not.toContain("WITH FILL");
3980+
expect(sql).not.toContain("INTERPOLATE");
3981+
// The plain descending order still stands.
3982+
expect(sql).toContain("ORDER BY timebucket DESC");
3983+
});
39743984
});

internal-packages/tsql/src/query/printer.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,16 +652,24 @@ export class ClickHousePrinter {
652652
// js/polynomial-redos). endsWith + slice is linear.
653653
const trimmedLead = leadTerm.trim();
654654
const upperLead = trimmedLead.toUpperCase();
655+
const isDescending = upperLead.endsWith(" DESC");
655656
const leadExpr = upperLead.endsWith(" ASC")
656657
? trimmedLead.slice(0, -4).trimEnd()
657-
: upperLead.endsWith(" DESC")
658+
: isDescending
658659
? trimmedLead.slice(0, -5).trimEnd()
659660
: trimmedLead;
660661
const matchesBucket = (expr: string): boolean =>
661662
expr.toLowerCase() === bucketAlias!.toLowerCase() || expr === bucketSql;
662663
if (!matchesBucket(leadExpr)) {
663664
return null;
664665
}
666+
// WITH FILL is emitted with ascending bounds and a positive STEP, which is
667+
// only valid for an ascending bucket order. A descending order would need
668+
// swapped bounds and a negative step (newer ClickHouse only), so skip the
669+
// gap-fill rewrite and let the plain descending ORDER BY stand.
670+
if (isDescending) {
671+
return null;
672+
}
665673

666674
// Group dims = GROUP BY expressions that are NOT the timeBucket column.
667675
const groupDims = (groupBy ?? []).filter((g) => !matchesBucket(g.trim()));

0 commit comments

Comments
 (0)