77
88import com .google .common .collect .ImmutableList ;
99import java .util .ArrayList ;
10+ import java .util .LinkedList ;
1011import java .util .List ;
1112import java .util .Map ;
13+ import java .util .OptionalInt ;
1214import java .util .stream .Collectors ;
15+ import java .util .stream .IntStream ;
1316import lombok .Getter ;
1417import org .apache .calcite .plan .Convention ;
1518import org .apache .calcite .plan .RelOptCluster ;
1619import org .apache .calcite .plan .RelOptPlanner ;
1720import org .apache .calcite .plan .RelOptRule ;
1821import org .apache .calcite .plan .RelOptTable ;
1922import org .apache .calcite .plan .RelTraitSet ;
23+ import org .apache .calcite .rel .RelCollation ;
2024import org .apache .calcite .rel .RelCollations ;
2125import org .apache .calcite .rel .RelFieldCollation ;
2226import org .apache .calcite .rel .core .Aggregate ;
@@ -199,8 +203,15 @@ public CalciteLogicalIndexScan pushDownLimit(Integer limit, Integer offset) {
199203
200204 public CalciteLogicalIndexScan pushDownSort (List <RelFieldCollation > collations ) {
201205 try {
206+ // Merge with existing sort if any
207+ RelCollation existingCollation = getTraitSet ().getCollation ();
208+ List <RelFieldCollation > existingFieldCollations =
209+ existingCollation == null ? List .of () : existingCollation .getFieldCollations ();
210+ List <RelFieldCollation > mergedCollations =
211+ mergeCollations (existingFieldCollations , collations );
212+
202213 // Propagate the sort to the new scan
203- RelTraitSet newTraitSet = getTraitSet ().plus (RelCollations .of (collations ));
214+ RelTraitSet newTraitSet = getTraitSet ().plus (RelCollations .of (mergedCollations ));
204215 CalciteLogicalIndexScan newScan =
205216 new CalciteLogicalIndexScan (
206217 getCluster (),
@@ -212,7 +223,7 @@ public CalciteLogicalIndexScan pushDownSort(List<RelFieldCollation> collations)
212223 pushDownContext .clone ());
213224
214225 List <SortBuilder <?>> builders = new ArrayList <>();
215- for (RelFieldCollation collation : collations ) {
226+ for (RelFieldCollation collation : mergedCollations ) {
216227 int index = collation .getFieldIndex ();
217228 String fieldName = this .getRowType ().getFieldNames ().get (index );
218229 RelFieldCollation .Direction direction = collation .getDirection ();
@@ -245,4 +256,32 @@ public CalciteLogicalIndexScan pushDownSort(List<RelFieldCollation> collations)
245256 }
246257 return null ;
247258 }
259+
260+ /**
261+ * Merges existing and new collations, ensuring that the last occurrence of each field index takes
262+ * precedence.
263+ *
264+ * @param existingCollations Existing collation list.
265+ * @param newCollations New collation list to be merged.
266+ * @return Merged list of collations.
267+ */
268+ private static List <RelFieldCollation > mergeCollations (
269+ List <RelFieldCollation > existingCollations , List <RelFieldCollation > newCollations ) {
270+ List <RelFieldCollation > concatenatedCollations = new ArrayList <>(existingCollations );
271+ concatenatedCollations .addAll (newCollations );
272+ LinkedList <RelFieldCollation > mergedCollations = new LinkedList <>();
273+ for (RelFieldCollation collation : concatenatedCollations ) {
274+ // If the collation is already in the merged list, remove it from the list before adding
275+ // This is because the sort that comes later in the list should take precedence
276+ OptionalInt index =
277+ IntStream .range (0 , mergedCollations .size ())
278+ .filter (i -> mergedCollations .get (i ).getFieldIndex () == collation .getFieldIndex ())
279+ .findFirst ();
280+ if (index .isPresent ()) {
281+ mergedCollations .remove (index .getAsInt ());
282+ }
283+ mergedCollations .add (collation );
284+ }
285+ return mergedCollations ;
286+ }
248287}
0 commit comments