From 031c2a76238198ebf9ed374371d96ec14126bd69 Mon Sep 17 00:00:00 2001 From: Aleksey Plekhanov Date: Tue, 28 Apr 2026 13:27:20 +0300 Subject: [PATCH 1/2] IGNITE-27854 Fix flaky CacheQueryEntityWithDateTimeApiFieldsTest.testSelectByAllFields --- .../internal/processors/query/h2/H2Utils.java | 19 +++++++ .../query/h2/database/H2TreeIndex.java | 4 +- ...eQueryEntityWithDateTimeApiFieldsTest.java | 54 ++++++++++--------- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java index 1302fbf990145..e3e4229f88765 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java @@ -39,6 +39,7 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; +import java.util.concurrent.TimeUnit; import javax.cache.CacheException; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; @@ -604,6 +605,24 @@ public static Value wrap(CacheObjectValueContext coCtx, Object obj, int type) th throw new IgniteCheckedException("Failed to wrap value[type=" + type + ", value=" + obj + "]"); } + /** + * Unwraps {@link Value} to respective object. + * + * @param val Value. + * @return Unwrapped object. + */ + public static Object unwrap(Value val) { + // Gets time preserving nanoseconds. Method getObject() returns Time object without nanoseconds. + if (val instanceof ValueTime) { + ValueTime val0 = (ValueTime)val; + + if (val0.getNanos() % TimeUnit.MILLISECONDS.toNanos(1L) != 0) + return LocalDateTimeUtils.valueToLocalTime(val); + } + + return val.getObject(); + } + /** * Gets corresponding DB type from java class. * diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java index d885e504d521f..9741e864f1a91 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java @@ -294,7 +294,7 @@ private IndexRow preparePlainIndexKey(SearchRow row, InlineIndexRowHandler rowHn else { InlineIndexKeyType colKeyType = InlineIndexKeyTypeRegistry.get(colType, queryIndex.keyTypeSettings()); - IndexKey idxKey = IndexKeyFactory.wrap(v.getObject(), v.getType(), cctx.cacheObjectContext(), + IndexKey idxKey = IndexKeyFactory.wrap(H2Utils.unwrap(v), v.getType(), cctx.cacheObjectContext(), queryIndex.keyTypeSettings()); if (colKeyType.isComparableTo(idxKey)) { @@ -312,7 +312,7 @@ private IndexRow preparePlainIndexKey(SearchRow row, InlineIndexRowHandler rowHn } keys[i] = IndexKeyFactory.wrap( - v.getObject(), v.getType(), cctx.cacheObjectContext(), queryIndex.keyTypeSettings()); + H2Utils.unwrap(v), v.getType(), cctx.cacheObjectContext(), queryIndex.keyTypeSettings()); } return new IndexPlainRowImpl(keys, rowHnd); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/CacheQueryEntityWithDateTimeApiFieldsTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/CacheQueryEntityWithDateTimeApiFieldsTest.java index 3aeef8712c490..a917d7cc3ef98 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/CacheQueryEntityWithDateTimeApiFieldsTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/CacheQueryEntityWithDateTimeApiFieldsTest.java @@ -35,6 +35,7 @@ import org.apache.ignite.cache.query.annotations.QuerySqlField; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.internal.processors.cache.index.AbstractIndexingCommonTest; +import org.apache.ignite.internal.processors.query.QueryUtils; import org.junit.Ignore; import org.junit.Test; @@ -111,11 +112,9 @@ private static CacheConfiguration createCacheCon /** * Tests insertion of an entity. - * - * @throws Exception If failed. */ @Test - public void testInsertEntityFields() throws Exception { + public void testInsertEntityFields() { cache.remove(entity.getId()); assertEquals(0, cache.size()); @@ -136,11 +135,9 @@ public void testInsertEntityFields() throws Exception { /** * Tests MERGE statement. - * - * @throws Exception If failed. */ @Test - public void testMergeEntityFields() throws Exception { + public void testMergeEntityFields() { assertEquals(1, cache.size()); SqlFieldsQuery qry = new SqlFieldsQuery( @@ -160,11 +157,9 @@ public void testMergeEntityFields() throws Exception { /** * Tests that DATEDIFF SQL function works for {@link LocalDateTime} * fields with the time part set to midnight. - * - * @throws Exception If failed. */ @Test - public void testDateDiffForLocalDateTimeFieldAtMidnight() throws Exception { + public void testDateDiffForLocalDateTimeFieldAtMidnight() { SqlFieldsQuery qry = new SqlFieldsQuery("select DATEDIFF('DAY', locDateTime, CURRENT_DATE ()) from EntityWithDateTimeFields"); @@ -176,11 +171,9 @@ public void testDateDiffForLocalDateTimeFieldAtMidnight() throws Exception { /** * Tests that selection for a {@link LocalTime} field returns {@link Time}. - * - * @throws Exception If failed. */ @Test - public void testSelectLocalTimeFieldReturnsTime() throws Exception { + public void testSelectLocalTimeFieldReturnsTime() { SqlFieldsQuery qry = new SqlFieldsQuery("select locTime from EntityWithDateTimeFields"); List> qryResults = cache.query(qry).getAll(); @@ -191,11 +184,9 @@ public void testSelectLocalTimeFieldReturnsTime() throws Exception { /** * Tests that selection for a {@link LocalDate} field returns {@link Date}. - * - * @throws Exception If failed. */ @Test - public void testSelectLocalDateFieldReturnsDate() throws Exception { + public void testSelectLocalDateFieldReturnsDate() { SqlFieldsQuery qry = new SqlFieldsQuery("select locDate from EntityWithDateTimeFields"); List> qryResults = cache.query(qry).getAll(); @@ -206,11 +197,9 @@ public void testSelectLocalDateFieldReturnsDate() throws Exception { /** * Tests that selection for a {@link LocalDateTime} field returns {@link Timestamp}. - * - * @throws Exception If failed. */ @Test - public void testSelectLocalDateTimeFieldReturnsTimestamp() throws Exception { + public void testSelectLocalDateTimeFieldReturnsTimestamp() { SqlFieldsQuery qry = new SqlFieldsQuery("select locDateTime from EntityWithDateTimeFields"); List> qryResults = cache.query(qry).getAll(); @@ -224,14 +213,27 @@ public void testSelectLocalDateTimeFieldReturnsTimestamp() throws Exception { */ @Test public void testSelectByAllFields() { - SqlFieldsQuery qry = new SqlFieldsQuery( - "select locDate from EntityWithDateTimeFields where locTime = ? and locDate = ? and locDateTime = ?" - ).setArgs(entity.getLocalTime(), entity.getLocalDate(), entity.getLocalDateTime()); - - List> qryResults = cache.query(qry).getAll(); - - assertEquals(1, qryResults.size()); - assertEquals(Date.valueOf(entity.getLocalDate()), qryResults.get(0).get(0)); + String[] idxs = new String[] { + QueryUtils.PRIMARY_KEY_INDEX, + "ENTITYWITHDATETIMEFIELDS_LOCTIME_IDX", + "ENTITYWITHDATETIMEFIELDS_LOCDATETIME_IDX", + "ENTITYWITHDATETIMEFIELDS_LOCDATE_IDX", + }; + + for (String idx : idxs) { + String sql = "select locDate, locTime, locDateTime from EntityWithDateTimeFields " + + "use index (\"" + idx + "\") where locTime = ? and locDate = ? and locDateTime = ?"; + + SqlFieldsQuery qry = new SqlFieldsQuery(sql) + .setArgs(entity.getLocalTime(), entity.getLocalDate(), entity.getLocalDateTime()); + + List> qryResults = cache.query(qry).getAll(); + + assertEquals("Unexpected result size for query [sql=" + sql + ']', 1, qryResults.size()); + assertEquals(Date.valueOf(entity.getLocalDate()), qryResults.get(0).get(0)); + assertEquals(Time.valueOf(entity.getLocalTime()), qryResults.get(0).get(1)); + assertEquals(Timestamp.valueOf(entity.getLocalDateTime()), qryResults.get(0).get(2)); + } } /** From c0e0a1e82da92dfdbf080cdd202978481b41075a Mon Sep 17 00:00:00 2001 From: Aleksey Plekhanov Date: Tue, 28 Apr 2026 13:49:01 +0300 Subject: [PATCH 2/2] IGNITE-27854 Fix flaky CacheQueryEntityWithDateTimeApiFieldsTest.testSelectByAllFields --- .../org/apache/ignite/internal/processors/query/h2/H2Utils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java index e3e4229f88765..322cfb1f6e203 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java @@ -612,8 +612,8 @@ public static Value wrap(CacheObjectValueContext coCtx, Object obj, int type) th * @return Unwrapped object. */ public static Object unwrap(Value val) { - // Gets time preserving nanoseconds. Method getObject() returns Time object without nanoseconds. if (val instanceof ValueTime) { + // Gets time preserving nanoseconds. Method ValueTime#getObject() returns Time object without nanoseconds. ValueTime val0 = (ValueTime)val; if (val0.getNanos() % TimeUnit.MILLISECONDS.toNanos(1L) != 0)