@@ -48,8 +48,8 @@ protected SortExprIndexScanRule(SortExprIndexScanRule.Config config) {
4848 @ Override
4949 protected void onMatchImpl (RelOptRuleCall call ) {
5050 final Sort sort = call .rel (0 );
51- // CalciteEnumerableTopK carries fetch semantics; this rule may collapse Sort/TopK into a
52- // project-on-scan shape, so skip TopK and let dedicated TopK/ limit rules preserve semantics .
51+ // CalciteEnumerableTopK carries fetch semantics; this rule doesn't preserve it on physical
52+ // scans because limit pushdown path is logical-only .
5353 if (sort instanceof CalciteEnumerableTopK ) {
5454 return ;
5555 }
@@ -108,23 +108,14 @@ protected void onMatchImpl(RelOptRuleCall call) {
108108 newScan = scan .pushdownSortExpr (sortExprDigests );
109109 }
110110
111- // Keep top-k semantics intact: remove Sort only when limit/offset is also preserved in scan.
112- if (sort .fetch != null || sort .offset != null ) {
113- Integer limitValue = LimitIndexScanRule .extractLimitValue (sort .fetch );
114- Integer offsetValue = LimitIndexScanRule .extractOffsetValue (sort .offset );
115- if (!(newScan instanceof CalciteLogicalIndexScan )
116- || !(sort instanceof LogicalSort )
117- || limitValue == null
118- || offsetValue == null ) {
119- return ;
120- }
111+ // EnumerableSort won't have limit or offset
112+ Integer limitValue = LimitIndexScanRule .extractLimitValue (sort .fetch );
113+ Integer offsetValue = LimitIndexScanRule .extractOffsetValue (sort .offset );
114+ if (newScan instanceof CalciteLogicalIndexScan && limitValue != null && offsetValue != null ) {
121115 newScan =
122116 (CalciteLogicalIndexScan )
123117 ((CalciteLogicalIndexScan ) newScan )
124118 .pushDownLimit ((LogicalSort ) sort , limitValue , offsetValue );
125- if (newScan == null ) {
126- return ;
127- }
128119 }
129120
130121 if (newScan != null ) {
0 commit comments