This is an automated email from the ASF dual-hosted git repository.

ibessonov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new e896751ac6 IGNITE-21890 Fix BinaryTupleComparator for decimal values 
(#3527)
e896751ac6 is described below

commit e896751ac6e5478944364f38b3c5aeb5ba432479
Author: Alexander Polovtcev <[email protected]>
AuthorDate: Tue Apr 2 10:42:24 2024 +0300

    IGNITE-21890 Fix BinaryTupleComparator for decimal values (#3527)
---
 .../internal/binarytuple/BinaryTupleReader.java    |  7 ++-
 .../apache/ignite/internal/lang/InternalTuple.java |  3 +-
 .../storage/index/BinaryTupleComparator.java       |  6 +--
 .../storage/index/BinaryTupleComparatorTest.java   |  4 +-
 .../index/AbstractSortedIndexStorageTest.java      | 27 +++++++----
 .../internal/storage/index/impl/TestIndexRow.java  | 55 ++++++++++++++++++----
 6 files changed, 77 insertions(+), 25 deletions(-)

diff --git 
a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
 
b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
index 050d26d9be..26cda8b375 100644
--- 
a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
+++ 
b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
@@ -255,7 +255,8 @@ public class BinaryTupleReader extends BinaryTupleParser 
implements BinaryTupleP
      * Reads value of specified element.
      *
      * @param index Element index.
-     * @param scale Decimal scale.
+     * @param scale Decimal scale. If equal to {@link Integer#MIN_VALUE}, then 
the value will be returned with whatever scale it is
+     *         stored in.
      * @return Element value.
      */
     public @Nullable BigDecimal decimalValue(int index, int scale) {
@@ -266,7 +267,9 @@ public class BinaryTupleReader extends BinaryTupleParser 
implements BinaryTupleP
 
         short valScale = shortValue(begin, begin + 2);
 
-        return new BigDecimal(numberValue(begin + 2, end), 
valScale).setScale(scale, RoundingMode.UNNECESSARY);
+        BigDecimal decimalValue = new BigDecimal(numberValue(begin + 2, end), 
valScale);
+
+        return scale < 0 ? decimalValue : decimalValue.setScale(scale, 
RoundingMode.UNNECESSARY);
     }
 
     /**
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/lang/InternalTuple.java 
b/modules/core/src/main/java/org/apache/ignite/internal/lang/InternalTuple.java
index 596e3a3a18..55e5a0866a 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/lang/InternalTuple.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/lang/InternalTuple.java
@@ -160,7 +160,8 @@ public interface InternalTuple {
      * Reads value from specified column.
      *
      * @param col Column index.
-     * @param decimalScale Decimal scale.
+     * @param decimalScale Decimal scale. If equal to {@link 
Integer#MIN_VALUE}, then the value will be returned with whatever scale
+     *         it is stored in.
      * @return Column value.
      */
     BigDecimal decimalValue(int col, int decimalScale);
diff --git 
a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/BinaryTupleComparator.java
 
b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/BinaryTupleComparator.java
index de6f03bd0a..243492bb20 100644
--- 
a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/BinaryTupleComparator.java
+++ 
b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/BinaryTupleComparator.java
@@ -141,11 +141,11 @@ public class BinaryTupleComparator implements 
Comparator<ByteBuffer> {
                 return 
tuple1.stringValue(index).compareTo(tuple2.stringValue(index));
 
             case NUMBER:
-            case DECIMAL:
-                // Floating point position is irrelevant during comparison.
-                // The only real requirement is that it matches in both 
arguments, and it does.
                 return 
tuple1.numberValue(index).compareTo(tuple2.numberValue(index));
 
+            case DECIMAL:
+                return tuple1.decimalValue(index, 
Integer.MIN_VALUE).compareTo(tuple2.decimalValue(index, Integer.MIN_VALUE));
+
             case TIMESTAMP:
                 return 
tuple1.timestampValue(index).compareTo(tuple2.timestampValue(index));
 
diff --git 
a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/BinaryTupleComparatorTest.java
 
b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/BinaryTupleComparatorTest.java
index 0c66f72b2c..73c0a7ab14 100644
--- 
a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/BinaryTupleComparatorTest.java
+++ 
b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/BinaryTupleComparatorTest.java
@@ -199,11 +199,11 @@ public class BinaryTupleComparatorTest {
 
             case DECIMAL: {
                 tuple1 = new BinaryTupleBuilder(1)
-                        .appendDecimal(BigDecimal.valueOf(-1), 4)
+                        .appendDecimal(BigDecimal.valueOf(-1), 0)
                         .build();
 
                 tuple2 = new BinaryTupleBuilder(1)
-                        .appendDecimal(BigDecimal.valueOf(123456789.1234), 4)
+                        .appendDecimal(BigDecimal.valueOf(123456789.12), 2)
                         .build();
 
                 break;
diff --git 
a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractSortedIndexStorageTest.java
 
b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractSortedIndexStorageTest.java
index 2fbb534b02..10e0d198b0 100644
--- 
a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractSortedIndexStorageTest.java
+++ 
b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractSortedIndexStorageTest.java
@@ -35,6 +35,7 @@ import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.sameInstance;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -70,6 +71,7 @@ import org.apache.ignite.internal.storage.RowId;
 import 
org.apache.ignite.internal.storage.index.StorageSortedIndexDescriptor.StorageSortedIndexColumnDescriptor;
 import org.apache.ignite.internal.storage.index.impl.BinaryTupleRowSerializer;
 import org.apache.ignite.internal.storage.index.impl.TestIndexRow;
+import 
org.apache.ignite.internal.storage.index.impl.TestIndexRow.TestIndexPrefix;
 import org.apache.ignite.internal.testframework.VariableSource;
 import org.apache.ignite.internal.util.Cursor;
 import org.apache.ignite.sql.ColumnType;
@@ -286,18 +288,19 @@ public abstract class AbstractSortedIndexStorageTest 
extends AbstractIndexStorag
         int firstIndex = 3;
         int lastIndex = 8;
 
+        TestIndexPrefix first = entries.get(firstIndex).prefix(3);
+        TestIndexPrefix last = entries.get(lastIndex).prefix(5);
+
         List<IndexRow> expected = entries.stream()
-                .skip(firstIndex)
-                .limit(lastIndex - firstIndex + 1)
+                .filter(row -> row.compareTo(first) >= 0 && 
row.compareTo(last) <= 0)
                 .collect(toList());
 
-        BinaryTuplePrefix first = entries.get(firstIndex).prefix(3);
-        BinaryTuplePrefix last = entries.get(lastIndex).prefix(5);
+        assertThat(expected, hasSize(greaterThanOrEqualTo(lastIndex - 
firstIndex + 1)));
 
-        try (Cursor<IndexRow> cursor = indexStorage.scan(first, last, 
GREATER_OR_EQUAL | LESS_OR_EQUAL)) {
+        try (Cursor<IndexRow> cursor = indexStorage.scan(first.prefix(), 
last.prefix(), GREATER_OR_EQUAL | LESS_OR_EQUAL)) {
             List<IndexRow> actual = cursor.stream().collect(toList());
 
-            assertThat(actual, hasSize(lastIndex - firstIndex + 1));
+            assertThat(actual, hasSize(expected.size()));
 
             for (int i = firstIndex; i < actual.size(); ++i) {
                 assertThat(actual.get(i).rowId(), 
is(equalTo(expected.get(i).rowId())));
@@ -413,7 +416,11 @@ public abstract class AbstractSortedIndexStorageTest 
extends AbstractIndexStorag
         put(indexStorage, entry1);
         put(indexStorage, entry2);
 
-        try (Cursor<IndexRow> cursor = 
indexStorage.scan(entry2.prefix(indexSchema.size()), 
entry1.prefix(indexSchema.size()), 0)) {
+        try (Cursor<IndexRow> cursor = indexStorage.scan(
+                entry2.prefix(indexSchema.size()).prefix(),
+                entry1.prefix(indexSchema.size()).prefix(),
+                0
+        )) {
             assertThat(cursor.stream().collect(toList()), is(empty()));
         }
     }
@@ -442,7 +449,11 @@ public abstract class AbstractSortedIndexStorageTest 
extends AbstractIndexStorag
             entry1 = t;
         }
 
-        try (Cursor<IndexRow> cursor = storage.scan(entry1.prefix(1), 
entry2.prefix(1), GREATER_OR_EQUAL | LESS_OR_EQUAL)) {
+        try (Cursor<IndexRow> cursor = storage.scan(
+                entry1.prefix(1).prefix(),
+                entry2.prefix(1).prefix(),
+                GREATER_OR_EQUAL | LESS_OR_EQUAL
+        )) {
             assertThat(
                     cursor.stream().map(row -> 
row.indexColumns().byteBuffer()).collect(toList()),
                     contains(entry1.indexColumns().byteBuffer(), 
entry2.indexColumns().byteBuffer())
diff --git 
a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/impl/TestIndexRow.java
 
b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/impl/TestIndexRow.java
index 56d0eb71d8..36d4974666 100644
--- 
a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/impl/TestIndexRow.java
+++ 
b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/impl/TestIndexRow.java
@@ -24,7 +24,7 @@ import java.lang.reflect.Array;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Comparator;
-import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.Function;
 import java.util.stream.IntStream;
 import org.apache.ignite.internal.schema.BinaryTuple;
@@ -62,11 +62,9 @@ public class TestIndexRow implements IndexRow, 
Comparable<TestIndexRow> {
      * Creates an row with random column values that satisfies the given 
schema.
      */
     public static TestIndexRow randomRow(SortedIndexStorage indexStorage, int 
partitionId) {
-        var random = new Random();
-
         Object[] columns = indexStorage.indexDescriptor().columns().stream()
                 .map(StorageSortedIndexColumnDescriptor::type)
-                .map(type -> generateRandomValue(random, type))
+                .map(type -> generateRandomValue(ThreadLocalRandom.current(), 
type))
                 .toArray();
 
         var rowId = new RowId(partitionId);
@@ -78,11 +76,35 @@ public class TestIndexRow implements IndexRow, 
Comparable<TestIndexRow> {
         return new TestIndexRow(indexStorage, serializer, row, columns);
     }
 
+    /**
+     * Class representing an Index Key prefix.
+     */
+    public static class TestIndexPrefix {
+        private final BinaryTuplePrefix prefix;
+
+        private final Object[] prefixColumns;
+
+        TestIndexPrefix(BinaryTuplePrefix prefix, Object[] prefixColumns) {
+            this.prefix = prefix;
+            this.prefixColumns = prefixColumns;
+        }
+
+        public BinaryTuplePrefix prefix() {
+            return prefix;
+        }
+
+        public Object[] prefixColumns() {
+            return prefixColumns;
+        }
+    }
+
     /**
      * Creates an Index Key prefix of the given length.
      */
-    public BinaryTuplePrefix prefix(int length) {
-        return serializer.serializeRowPrefix(Arrays.copyOf(columns, length));
+    public TestIndexPrefix prefix(int length) {
+        Object[] prefixColumns = Arrays.copyOf(columns, length);
+
+        return new 
TestIndexPrefix(serializer.serializeRowPrefix(prefixColumns), prefixColumns);
     }
 
     @Override
@@ -103,10 +125,25 @@ public class TestIndexRow implements IndexRow, 
Comparable<TestIndexRow> {
             return sizeCompare;
         }
 
-        for (int i = 0; i < columns.length; ++i) {
-            Comparator<Object> comparator = comparator(columns[i].getClass());
+        return compareColumns(columns, o.columns);
+    }
+
+    /**
+     * Compares the row with the given row prefix.
+     */
+    public int compareTo(TestIndexPrefix prefix) {
+        Object[] prefixColumns = prefix.prefixColumns();
+
+        assert prefixColumns.length <= columns.length;
+
+        return compareColumns(columns, prefixColumns);
+    }
+
+    private int compareColumns(Object[] a, Object[] b) {
+        for (int i = 0; i < Math.min(a.length, b.length); ++i) {
+            Comparator<Object> comparator = comparator(a[i].getClass());
 
-            int compare = comparator.compare(columns[i], o.columns[i]);
+            int compare = comparator.compare(a[i], b[i]);
 
             if (compare != 0) {
                 boolean asc = 
indexStorage.indexDescriptor().columns().get(i).asc();

Reply via email to