nizhikov commented on code in PR #11438:
URL: https://github.com/apache/ignite/pull/11438#discussion_r1758464907


##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ListCursor.java:
##########
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.query.calcite.exec;
+
+import java.util.Comparator;
+import java.util.List;
+import org.apache.ignite.internal.util.lang.GridCursor;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Cursor to navigate through a sorted list with duplicates.
+ */
+public class ListCursor<Row> implements GridCursor<Row> {
+    /** */
+    private final Comparator<Row> comp;
+
+    /** List of rows. */
+    private final List<Row> rows;
+
+    /** Upper bound. */
+    private final Row upper;
+
+    /** Include upper bound. */
+    private final boolean includeUpper;
+
+    /** Current row. */
+    private Row row;
+
+    /** Current index of list element. */
+    private int idx;
+
+    /**
+     * @param comp Rows comparator.
+     * @param rows List of rows.
+     * @param lower Lower bound.
+     * @param upper Upper bound.
+     * @param lowerInclude {@code True} for inclusive lower bound.
+     * @param upperInclude {@code True} for inclusive upper bound.
+     */
+    public ListCursor(
+        Comparator<Row> comp,
+        List<Row> rows,
+        @Nullable Row lower,
+        @Nullable Row upper,
+        boolean lowerInclude,
+        boolean upperInclude
+    ) {
+        this.comp = comp;
+        this.rows = rows;
+        this.upper = upper;
+        this.includeUpper = upperInclude;
+
+        idx = lower == null ? 0 : lowerBound(rows, lower, lowerInclude);
+    }
+
+    /**
+     * Searches the lower bound (skipping duplicates) using a binary search.
+     *
+     * @param rows List of rows.
+     * @param bound Lower bound.
+     * @return Lower bound position in the list.
+     */
+    private int lowerBound(List<Row> rows, Row bound, boolean includeBound) {
+        int low = 0, high = rows.size() - 1, idx = -1;
+
+        while (low <= high) {
+            int mid = (high - low) / 2 + low;
+            int compRes = comp.compare(rows.get(mid), bound);
+
+            if (compRes > 0)
+                high = mid - 1;
+            else if (compRes == 0 && includeBound) {
+                idx = mid;
+                high = mid - 1;
+            }
+            else
+                low = mid + 1;
+        }
+
+        return idx == -1 ? low : idx;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean next() {
+        if (idx == rows.size() || (upper != null && 
-comp.compare(rows.get(idx), upper) < (includeUpper ? 0 : 1)))

Review Comment:
   `InlineIndexTree#compareFullRows` works correctly only with specific 
parameters order - first `IndexRow` must be from tree, second is search row. 
Otherwise NPE will be thrown on null search key field.
    
   ```
       /** */
       public static int compareFullRows(
           IndexRow currRow,
           IndexRow row,
           int from,
           InlineIndexRowHandler rowHnd,
           IndexRowComparator rowCmp
       ) throws IgniteCheckedException {
           if (currRow == row)
               return 0;
   
           List<IndexKeyDefinition> idxKeyDefs = rowHnd.indexKeyDefinitions();
   
           for (int i = from; i < idxKeyDefs.size(); i++) {
               // If a search key is null then skip other keys (consider that 
null shows that we should get all
               // possible keys for that comparison).
               if (row.key(i) == null)
                   return 0;
   
               int c = rowCmp.compareRow(currRow, row, i);
   
               if (c != 0)
                   return applySortOrder(Integer.signum(c), 
idxKeyDefs.get(i).order().sortOrder());
           }
   
           return 0;
       }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@ignite.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to