Skip to content

Commit 77994ec

Browse files
authored
IGNITE-26990 Fix ClassCastException in Criteria API with BigDecimal (#6949)
1 parent 601746e commit 77994ec

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed

modules/marshaller-common/src/main/java/org/apache/ignite/internal/marshaller/TupleReader.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,12 @@ public byte[] readBytes() {
134134

135135
@Override
136136
public BigDecimal readBigDecimal(int scale) {
137-
return new BigDecimal(tuple.value(index++), scale);
137+
// Scale is already set by the BinaryTupleReader based on the schema.
138+
BigDecimal scaled = tuple.value(index++);
139+
140+
assert scaled == null || scaled.scale() == scale : "Unexpected scale [expected=" + scale + ", actual=" + scaled.scale() + "]";
141+
142+
return scaled;
138143
}
139144

140145
@Override

modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItCriteriaQueryTest.java

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,21 @@
4949
import static org.hamcrest.Matchers.empty;
5050
import static org.hamcrest.Matchers.hasEntry;
5151
import static org.hamcrest.Matchers.is;
52+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
5253
import static org.junit.jupiter.api.Assertions.assertEquals;
5354
import static org.junit.jupiter.api.Assertions.assertNotNull;
55+
import static org.junit.jupiter.api.Assertions.assertNull;
5456

57+
import java.math.BigDecimal;
58+
import java.time.Instant;
59+
import java.time.LocalDate;
60+
import java.time.LocalDateTime;
61+
import java.time.LocalTime;
5562
import java.util.List;
5663
import java.util.Map;
5764
import java.util.Map.Entry;
5865
import java.util.Spliterator;
66+
import java.util.UUID;
5967
import java.util.function.Function;
6068
import java.util.stream.Stream;
6169
import java.util.stream.StreamSupport;
@@ -76,6 +84,7 @@
7684
import org.hamcrest.Matchers;
7785
import org.junit.jupiter.api.AfterAll;
7886
import org.junit.jupiter.api.BeforeAll;
87+
import org.junit.jupiter.api.Test;
7988
import org.junit.jupiter.params.ParameterizedTest;
8089
import org.junit.jupiter.params.provider.Arguments;
8190
import org.junit.jupiter.params.provider.MethodSource;
@@ -517,6 +526,84 @@ public <T> void testKeyViewWithQuotes(CriteriaQuerySource<T> view, Function<T, E
517526
}
518527
}
519528

529+
@Test
530+
public void testQueryAllColumnTypes() {
531+
String tableName = "all_column_types";
532+
533+
CLIENT.sql().executeScript(format(
534+
"CREATE TABLE {} (str VARCHAR PRIMARY KEY, byteCol TINYINT, shortCol SMALLINT, intCol INT, longCol BIGINT, "
535+
+ "floatCol REAL, doubleCol DOUBLE, decimalCol DECIMAL(6, 3), boolCol BOOLEAN, bytesCol VARBINARY, "
536+
+ "uuidCol UUID, dateCol DATE, timeCol TIME, datetimeCol TIMESTAMP, instantCol TIMESTAMP WITH LOCAL TIME ZONE)",
537+
tableName));
538+
539+
UUID uuid = UUID.randomUUID();
540+
LocalDate localDate = LocalDate.of(2024, 1, 1);
541+
LocalTime localTime = LocalTime.of(12, 15, 10);
542+
LocalDateTime localDateTime = LocalDateTime.of(2024, 1, 1, 12, 0);
543+
Instant instant = Instant.parse("2024-01-01T12:00:00Z");
544+
byte[] bytes = {1, 2, 3};
545+
546+
CLIENT.sql().executeScript("INSERT INTO " + tableName + " (str, byteCol, shortCol, intCol, longCol, floatCol, doubleCol, "
547+
+ "decimalCol, boolCol, bytesCol, uuidCol, dateCol, timeCol, datetimeCol, instantCol) VALUES "
548+
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
549+
"test", (byte) 1, (short) 2, 3, 4L, 5.0f, 6.0d, new BigDecimal("7.89"), true,
550+
bytes, uuid, localDate, localTime, localDateTime, instant);
551+
552+
Table table = CLIENT.tables().table(tableName);
553+
554+
try (Cursor<TestAllColumnTypes> cur = table.recordView(TestAllColumnTypes.class).query(null, null)) {
555+
List<TestAllColumnTypes> results = StreamSupport.stream(spliteratorUnknownSize(cur, Spliterator.ORDERED), false)
556+
.collect(toList());
557+
558+
assertThat(results, Matchers.hasSize(1));
559+
560+
TestAllColumnTypes row = results.get(0);
561+
562+
assertEquals("test", row.str);
563+
assertEquals(Byte.valueOf((byte) 1), row.byteCol);
564+
assertEquals(Short.valueOf((short) 2), row.shortCol);
565+
assertEquals(Integer.valueOf(3), row.intCol);
566+
assertEquals(Long.valueOf(4L), row.longCol);
567+
assertEquals(Float.valueOf(5.0f), row.floatCol);
568+
assertEquals(Double.valueOf(6.0d), row.doubleCol);
569+
assertEquals(new BigDecimal("7.890"), row.decimalCol);
570+
assertEquals(Boolean.TRUE, row.boolCol);
571+
assertArrayEquals(bytes, row.bytesCol);
572+
assertEquals(uuid, row.uuidCol);
573+
assertEquals(localDate, row.dateCol);
574+
assertEquals(localTime, row.timeCol);
575+
assertEquals(localDateTime, row.datetimeCol);
576+
assertEquals(instant, row.instantCol);
577+
}
578+
579+
try (Cursor<Entry<String, TestAllColumnTypes>> cur = table.keyValueView(String.class, TestAllColumnTypes.class).query(null, null)) {
580+
List<Entry<String, TestAllColumnTypes>> results = StreamSupport.stream(spliteratorUnknownSize(cur, Spliterator.ORDERED), false)
581+
.collect(toList());
582+
583+
assertThat(results, Matchers.hasSize(1));
584+
585+
Entry<String, TestAllColumnTypes> entry = results.get(0);
586+
TestAllColumnTypes row = entry.getValue();
587+
588+
assertEquals("test", entry.getKey());
589+
assertNull(row.str);
590+
assertEquals(Byte.valueOf((byte) 1), row.byteCol);
591+
assertEquals(Short.valueOf((short) 2), row.shortCol);
592+
assertEquals(Integer.valueOf(3), row.intCol);
593+
assertEquals(Long.valueOf(4L), row.longCol);
594+
assertEquals(Float.valueOf(5.0f), row.floatCol);
595+
assertEquals(Double.valueOf(6.0d), row.doubleCol);
596+
assertEquals(new BigDecimal("7.890"), row.decimalCol);
597+
assertEquals(Boolean.TRUE, row.boolCol);
598+
assertArrayEquals(bytes, row.bytesCol);
599+
assertEquals(uuid, row.uuidCol);
600+
assertEquals(localDate, row.dateCol);
601+
assertEquals(localTime, row.timeCol);
602+
assertEquals(localDateTime, row.datetimeCol);
603+
assertEquals(instant, row.instantCol);
604+
}
605+
}
606+
520607
private static Stream<Arguments> testSessionClosing() {
521608
Table table = CLUSTER.aliveNode().tables().table(TABLE_NAME);
522609

@@ -565,4 +652,22 @@ static class TestObject {
565652

566653
byte[] hash;
567654
}
655+
656+
static class TestAllColumnTypes {
657+
String str;
658+
Byte byteCol;
659+
Short shortCol;
660+
Integer intCol;
661+
Long longCol;
662+
Float floatCol;
663+
Double doubleCol;
664+
BigDecimal decimalCol;
665+
Boolean boolCol;
666+
byte[] bytesCol;
667+
UUID uuidCol;
668+
LocalDate dateCol;
669+
LocalTime timeCol;
670+
LocalDateTime datetimeCol;
671+
Instant instantCol;
672+
}
568673
}

0 commit comments

Comments
 (0)