This is an automated email from the ASF dual-hosted git repository.
ptupitsyn 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 08171cc1a5 IGNITE-17992 .NET: Fix colocation hash for temporal types
with custom precision (#1598)
08171cc1a5 is described below
commit 08171cc1a5078cb22bd87dee76c4774f79d2981b
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Mon Jan 30 20:52:37 2023 +0200
IGNITE-17992 .NET: Fix colocation hash for temporal types with custom
precision (#1598)
When temporal type (Time, DateTime, Timestamp) precision is less than
`MAX_TIME_PRECISION`, column value is adjusted (truncated) by the server on
insert, resulting in a different colocation hash. For example, nanosecond
component is dropped when precision is 0.
* Propagate `Column.Precision` to .NET client (already sent by the server).
* Pass precision to `BinaryTupleBuilder` methods, and apply the same
`NormalizeNanos` logic that `RowAssembler` uses.
---
.../SerializerHandlerBenchmarksBase.cs | 6 +-
.../dotnet/Apache.Ignite.Tests/FakeServer.cs | 15 +-
.../Proto/BinaryTuple/BinaryTupleTests.cs | 51 ++++---
.../Proto/ColocationHashTests.cs | 170 +++++++++++++++++++--
.../Sql/IgniteDbDataReaderTests.cs | 4 +-
.../Serialization/ObjectSerializerHandlerTests.cs | 4 +-
.../Proto/BinaryTuple/BinaryTupleBuilder.cs | 82 +++++-----
.../Apache.Ignite/Internal/Proto/HashUtils.cs | 12 +-
.../dotnet/Apache.Ignite/Internal/Table/Column.cs | 10 +-
.../Table/Serialization/ObjectSerializerHandler.cs | 12 ++
.../Serialization/TuplePairSerializerHandler.cs | 2 +-
.../Table/Serialization/TupleSerializerHandler.cs | 2 +-
.../dotnet/Apache.Ignite/Internal/Table/Table.cs | 5 +-
.../Apache.Ignite/Internal/Table/TemporalTypes.cs | 54 +++++++
.../runner/app/PlatformTestNodeRunner.java | 36 +++--
.../internal/schema/row/TemporalTypesHelper.java | 18 +--
16 files changed, 358 insertions(+), 125 deletions(-)
diff --git
a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Table/Serialization/SerializerHandlerBenchmarksBase.cs
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Table/Serialization/SerializerHandlerBenchmarksBase.cs
index 07ca0922e0..3bae3cafb6 100644
---
a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Table/Serialization/SerializerHandlerBenchmarksBase.cs
+++
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Table/Serialization/SerializerHandlerBenchmarksBase.cs
@@ -46,9 +46,9 @@ namespace Apache.Ignite.Benchmarks.Table.Serialization
internal static readonly Schema Schema = new(1, 1, new[]
{
- new Column(nameof(Car.Id), ClientDataType.Uuid, IsNullable: false,
IsColocation: true, IsKey: true, SchemaIndex: 0, Scale: 0),
- new Column(nameof(Car.BodyType), ClientDataType.String,
IsNullable: false, IsColocation: false, IsKey: false, SchemaIndex: 1, Scale: 0),
- new Column(nameof(Car.Seats), ClientDataType.Int32, IsNullable:
false, IsColocation: false, IsKey: false, SchemaIndex: 2, Scale: 0)
+ new Column(nameof(Car.Id), ClientDataType.Uuid, IsNullable: false,
IsColocation: true, IsKey: true, SchemaIndex: 0, Scale: 0, Precision: 0),
+ new Column(nameof(Car.BodyType), ClientDataType.String,
IsNullable: false, IsColocation: false, IsKey: false, SchemaIndex: 1, Scale: 0,
Precision: 0),
+ new Column(nameof(Car.Seats), ClientDataType.Int32, IsNullable:
false, IsColocation: false, IsKey: false, SchemaIndex: 2, Scale: 0, Precision:
0)
});
internal static readonly byte[] SerializedData = GetSerializedData();
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/FakeServer.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/FakeServer.cs
index 9b14933084..7ad0ab251d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/FakeServer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/FakeServer.cs
@@ -340,53 +340,58 @@ namespace Apache.Ignite.Tests
if (tableId == ExistingTableId)
{
writer.WriteArrayHeader(1); // Columns.
- writer.WriteArrayHeader(6); // Column props.
+ writer.WriteArrayHeader(7); // Column props.
writer.Write("ID");
writer.Write((int)ClientDataType.Int32);
writer.Write(true); // Key.
writer.Write(false); // Nullable.
writer.Write(true); // Colocation.
writer.Write(0); // Scale.
+ writer.Write(0); // Precision.
}
else if (tableId == CompositeKeyTableId)
{
writer.WriteArrayHeader(2); // Columns.
- writer.WriteArrayHeader(6); // Column props.
+ writer.WriteArrayHeader(7); // Column props.
writer.Write("IdStr");
writer.Write((int)ClientDataType.String);
writer.Write(true); // Key.
writer.Write(false); // Nullable.
writer.Write(true); // Colocation.
writer.Write(0); // Scale.
+ writer.Write(0); // Precision.
- writer.WriteArrayHeader(6); // Column props.
+ writer.WriteArrayHeader(7); // Column props.
writer.Write("IdGuid");
writer.Write((int)ClientDataType.Uuid);
writer.Write(true); // Key.
writer.Write(false); // Nullable.
writer.Write(true); // Colocation.
writer.Write(0); // Scale.
+ writer.Write(0); // Precision.
}
else if (tableId == CustomColocationKeyTableId)
{
writer.WriteArrayHeader(2); // Columns.
- writer.WriteArrayHeader(6); // Column props.
+ writer.WriteArrayHeader(7); // Column props.
writer.Write("IdStr");
writer.Write((int)ClientDataType.String);
writer.Write(true); // Key.
writer.Write(false); // Nullable.
writer.Write(true); // Colocation.
writer.Write(0); // Scale.
+ writer.Write(0); // Precision.
- writer.WriteArrayHeader(6); // Column props.
+ writer.WriteArrayHeader(7); // Column props.
writer.Write("IdGuid");
writer.Write((int)ClientDataType.Uuid);
writer.Write(true); // Key.
writer.Write(false); // Nullable.
writer.Write(false); // Colocation.
writer.Write(0); // Scale.
+ writer.Write(0); // Precision.
}
Send(handler, requestId, arrayBufferWriter);
diff --git
a/modules/platforms/dotnet/Apache.Ignite.Tests/Proto/BinaryTuple/BinaryTupleTests.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/Proto/BinaryTuple/BinaryTupleTests.cs
index 6394a9b0eb..fbaf5a8e63 100644
---
a/modules/platforms/dotnet/Apache.Ignite.Tests/Proto/BinaryTuple/BinaryTupleTests.cs
+++
b/modules/platforms/dotnet/Apache.Ignite.Tests/Proto/BinaryTuple/BinaryTupleTests.cs
@@ -23,6 +23,7 @@ namespace Apache.Ignite.Tests.Proto.BinaryTuple
using System.Numerics;
using Internal.Proto;
using Internal.Proto.BinaryTuple;
+ using Internal.Table;
using NodaTime;
using NUnit.Framework;
@@ -527,12 +528,12 @@ namespace Apache.Ignite.Tests.Proto.BinaryTuple
var reader = BuildAndRead(
(ref BinaryTupleBuilder b) =>
{
- b.AppendTime(default);
- b.AppendTime(val);
- b.AppendTime(LocalTime.MinValue);
- b.AppendTime(LocalTime.MaxValue);
- b.AppendTime(LocalTime.Midnight);
- b.AppendTime(LocalTime.Noon);
+ b.AppendTime(default, 0);
+ b.AppendTime(val, TemporalTypes.MaxTimePrecision);
+ b.AppendTime(LocalTime.MinValue,
TemporalTypes.MaxTimePrecision);
+ b.AppendTime(LocalTime.MaxValue,
TemporalTypes.MaxTimePrecision);
+ b.AppendTime(LocalTime.Midnight, 0);
+ b.AppendTime(LocalTime.Noon, 0);
},
6);
@@ -552,10 +553,10 @@ namespace Apache.Ignite.Tests.Proto.BinaryTuple
var reader = BuildAndRead(
(ref BinaryTupleBuilder b) =>
{
- b.AppendDateTime(default);
- b.AppendDateTime(val);
- b.AppendDateTime(LocalDateTime.MaxIsoValue);
- b.AppendDateTime(LocalDateTime.MinIsoValue);
+ b.AppendDateTime(default, 0);
+ b.AppendDateTime(val, TemporalTypes.MaxTimePrecision);
+ b.AppendDateTime(LocalDateTime.MaxIsoValue,
TemporalTypes.MaxTimePrecision);
+ b.AppendDateTime(LocalDateTime.MinIsoValue,
TemporalTypes.MaxTimePrecision);
},
4);
@@ -573,12 +574,12 @@ namespace Apache.Ignite.Tests.Proto.BinaryTuple
var reader = BuildAndRead(
(ref BinaryTupleBuilder b) =>
{
- b.AppendTimestamp(default);
- b.AppendTimestamp(val);
- b.AppendTimestamp(Instant.MaxValue);
- b.AppendTimestamp(Instant.MinValue);
- b.AppendTimestamp(NodaConstants.BclEpoch);
- b.AppendTimestamp(NodaConstants.JulianEpoch);
+ b.AppendTimestamp(default, 0);
+ b.AppendTimestamp(val, TemporalTypes.MaxTimePrecision);
+ b.AppendTimestamp(Instant.MaxValue,
TemporalTypes.MaxTimePrecision);
+ b.AppendTimestamp(Instant.MinValue,
TemporalTypes.MaxTimePrecision);
+ b.AppendTimestamp(NodaConstants.BclEpoch,
TemporalTypes.MaxTimePrecision);
+ b.AppendTimestamp(NodaConstants.JulianEpoch,
TemporalTypes.MaxTimePrecision);
},
6);
@@ -738,12 +739,12 @@ namespace Apache.Ignite.Tests.Proto.BinaryTuple
b.AppendNumberNullable(null);
b.AppendDateNullable(date);
b.AppendDateNullable(null);
- b.AppendTimeNullable(dateTime.TimeOfDay);
- b.AppendTimeNullable(null);
- b.AppendDateTimeNullable(dateTime);
- b.AppendDateTimeNullable(null);
- b.AppendTimestampNullable(Instant.FromDateTimeUtc(utcNow));
- b.AppendTimestampNullable(null);
+ b.AppendTimeNullable(dateTime.TimeOfDay,
TemporalTypes.MaxTimePrecision);
+ b.AppendTimeNullable(null, 0);
+ b.AppendDateTimeNullable(dateTime,
TemporalTypes.MaxTimePrecision);
+ b.AppendDateTimeNullable(null, 0);
+ b.AppendTimestampNullable(Instant.FromDateTimeUtc(utcNow),
TemporalTypes.MaxTimePrecision);
+ b.AppendTimestampNullable(null, 0);
b.AppendDurationNullable(Duration.FromMinutes(1));
b.AppendDurationNullable(null);
b.AppendPeriodNullable(Period.FromDays(1));
@@ -815,10 +816,10 @@ namespace Apache.Ignite.Tests.Proto.BinaryTuple
b.AppendObject(bitArray, ClientDataType.BitMask);
b.AppendObject(guid, ClientDataType.Uuid);
b.AppendObject(bytes, ClientDataType.Bytes);
- b.AppendObject(LocalTime.FromMinutesSinceMidnight(123),
ClientDataType.Time);
+ b.AppendObject(LocalTime.FromMinutesSinceMidnight(123),
ClientDataType.Time, precision: TemporalTypes.MaxTimePrecision);
b.AppendObject(date, ClientDataType.Date);
- b.AppendObject(dateTime, ClientDataType.DateTime);
- b.AppendObject(Instant.FromDateTimeUtc(utcNow),
ClientDataType.Timestamp);
+ b.AppendObject(dateTime, ClientDataType.DateTime,
precision: TemporalTypes.MaxTimePrecision);
+ b.AppendObject(Instant.FromDateTimeUtc(utcNow),
ClientDataType.Timestamp, precision: TemporalTypes.MaxTimePrecision);
},
17);
diff --git
a/modules/platforms/dotnet/Apache.Ignite.Tests/Proto/ColocationHashTests.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/Proto/ColocationHashTests.cs
index 6b9780b6c2..4378f68c0f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/Proto/ColocationHashTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/Proto/ColocationHashTests.cs
@@ -20,10 +20,18 @@ namespace Apache.Ignite.Tests.Proto;
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
+using System.Reflection;
using System.Threading.Tasks;
+using Ignite.Table;
+using Internal.Buffers;
+using Internal.Proto;
using Internal.Proto.BinaryTuple;
+using Internal.Proto.MsgPack;
+using Internal.Table;
+using Internal.Table.Serialization;
using NodaTime;
using NUnit.Framework;
@@ -86,7 +94,8 @@ public class ColocationHashTests : IgniteTestsBase
new LocalDate(2, 1, 1),
new LocalDate(1, 1, 1),
default(LocalDate),
- new LocalTime(9, 8, 7),
+ new LocalTime(9, 8, 7, 6),
+ LocalTime.FromHourMinuteSecondNanosecond(hour: 1, minute: 2, second:
3, nanosecondWithinSecond: 456789),
LocalTime.Midnight,
LocalTime.Noon,
LocalDateTime.FromDateTime(DateTime.UtcNow).TimeOfDay,
@@ -102,48 +111,179 @@ public class ColocationHashTests : IgniteTestsBase
[Test]
[TestCaseSource(nameof(TestCases))]
public async Task
TestSingleKeyColocationHashIsSameOnServerAndClient(object key) =>
- await AssertClientAndServerHashesAreEqual(key);
+ await AssertClientAndServerHashesAreEqual(keys: key);
+
+ [Test]
+ public async Task
TestSingleKeyColocationHashIsSameOnServerAndClientCustomTimePrecision(
+ [Values(0, 1, 3, 4, 5, 6, 7, 8, 9)] int timePrecision,
+ [Values(0, 1, 3, 6)] int timestampPrecision)
+ {
+ foreach (var t in TestCases)
+ {
+ await AssertClientAndServerHashesAreEqual(timePrecision,
timestampPrecision, t);
+ }
+ }
+
+ [Test]
+ public async Task
TestLocalTimeColocationHashIsSameOnServerAndClient([Values(0, 1, 2, 3, 4, 5, 6,
7, 8, 9)] int timePrecision) =>
+ await AssertClientAndServerHashesAreEqual(timePrecision, keys:
LocalTime.FromHourMinuteSecondNanosecond(11, 33, 44, 123_456));
+
+ [Test]
+ public async Task
TestLocalDateTimeColocationHashIsSameOnServerAndClient([Values(0, 1, 2, 3, 4,
5, 6, 7, 8, 9)] int timePrecision) =>
+ await AssertClientAndServerHashesAreEqual(timePrecision, keys: new
LocalDateTime(2022, 01, 27, 1, 2, 3, 999));
+
+ [Test]
+ public async Task TestTimestampColocationHashIsSameOnServerAndClient(
+ [Values(0, 1, 2, 3, 4, 5, 6)] int timestampPrecision) =>
+ await AssertClientAndServerHashesAreEqual(timestampPrecision:
timestampPrecision, keys: Instant.FromDateTimeUtc(DateTime.UtcNow));
[Test]
public async Task TestMultiKeyColocationHashIsSameOnServerAndClient()
{
for (var i = 0; i < TestCases.Length; i++)
{
- await AssertClientAndServerHashesAreEqual(TestCases.Take(i +
1).ToArray());
- await
AssertClientAndServerHashesAreEqual(TestCases.Skip(i).ToArray());
+ await AssertClientAndServerHashesAreEqual(keys: TestCases.Take(i +
1).ToArray());
+ await AssertClientAndServerHashesAreEqual(keys:
TestCases.Skip(i).ToArray());
+ }
+ }
+
+ [Test]
+ public async Task
TestMultiKeyColocationHashIsSameOnServerAndClientCustomTimePrecision(
+ [Values(0, 1, 4, 5, 6, 7, 8, 9)] int timePrecision,
+ [Values(0, 1, 3, 6)] int timestampPrecision)
+ {
+ for (var i = 0; i < TestCases.Length; i++)
+ {
+ await AssertClientAndServerHashesAreEqual(timePrecision,
timestampPrecision, TestCases.Take(i + 1).ToArray());
+ await AssertClientAndServerHashesAreEqual(timePrecision,
timestampPrecision, TestCases.Skip(i).ToArray());
}
}
- private static (byte[] Bytes, int Hash)
WriteAsBinaryTuple(IReadOnlyCollection<object> arr)
+ private static (byte[] Bytes, int Hash)
WriteAsBinaryTuple(IReadOnlyCollection<object> arr, int timePrecision, int
timestampPrecision)
{
- using var builder = new BinaryTupleBuilder(arr.Count * 3,
hashedColumnsPredicate: new TestIndexProvider());
+ using var builder = new BinaryTupleBuilder(arr.Count * 3,
hashedColumnsPredicate: new TestIndexProvider(x => x % 3 == 2));
foreach (var obj in arr)
{
- builder.AppendObjectWithType(obj);
+ builder.AppendObjectWithType(obj, timePrecision,
timestampPrecision);
}
return (builder.Build().ToArray(), builder.Hash);
}
- private async Task AssertClientAndServerHashesAreEqual(params object[]
keys)
+ private static int WriteAsIgniteTuple(IReadOnlyCollection<object> arr, int
timePrecision, int timestampPrecision)
{
- var (bytes, hash) = WriteAsBinaryTuple(keys);
+ var igniteTuple = new IgniteTuple();
+ int i = 1;
+
+ foreach (var obj in arr)
+ {
+ igniteTuple["m_Item" + i++] = obj;
+ }
- var serverHash = await GetServerHash(bytes, keys.Length);
+ var builder = new BinaryTupleBuilder(arr.Count,
hashedColumnsPredicate: new TestIndexProvider(_ => true));
+
+ try
+ {
+ var schema = GetSchema(arr, timePrecision, timestampPrecision);
+ var noValueSet = new byte[arr.Count].AsSpan();
- Assert.AreEqual(serverHash, hash, string.Join(", ", keys));
+ TupleSerializerHandler.Instance.Write(ref builder, igniteTuple,
schema, arr.Count, noValueSet);
+ return builder.Hash;
+ }
+ finally
+ {
+ builder.Dispose();
+ }
+ }
+
+ [SuppressMessage("ReSharper", "UnusedMember.Local", Justification = "Used
by reflection.")]
+ private static int WriteAsPoco<T>(T obj, int timePrecision, int
timestampPrecision)
+ {
+ var poco = Tuple.Create(obj);
+ IRecordSerializerHandler<Tuple<T>> handler = new
ObjectSerializerHandler<Tuple<T>>();
+ var schema = GetSchema(new object[] { obj! }, timePrecision,
timestampPrecision);
+
+ using var buf = new PooledArrayBuffer();
+ var writer = new MsgPackWriter(buf);
+
+ return handler.Write(ref writer, schema, poco, computeHash: true);
+ }
+
+ private static Schema GetSchema(IReadOnlyCollection<object> arr, int
timePrecision, int timestampPrecision)
+ {
+ var columns = arr.Select((obj, ci) => GetColumn(obj, ci,
timePrecision, timestampPrecision)).ToArray();
+
+ return new Schema(Version: 0, arr.Count, columns);
+ }
+
+ private static Column GetColumn(object value, int schemaIndex, int
timePrecision, int timestampPrecision)
+ {
+ var colType = value switch
+ {
+ sbyte => ClientDataType.Int8,
+ short => ClientDataType.Int16,
+ int => ClientDataType.Int32,
+ long => ClientDataType.Int64,
+ float => ClientDataType.Float,
+ double => ClientDataType.Double,
+ decimal => ClientDataType.Decimal,
+ Guid => ClientDataType.Uuid,
+ byte[] => ClientDataType.Bytes,
+ string => ClientDataType.String,
+ BigInteger => ClientDataType.Number,
+ BitArray => ClientDataType.BitMask,
+ LocalTime => ClientDataType.Time,
+ LocalDate => ClientDataType.Date,
+ LocalDateTime => ClientDataType.DateTime,
+ Instant => ClientDataType.Timestamp,
+ _ => throw new Exception("Unknown type: " + value.GetType())
+ };
+
+ var precision = colType switch
+ {
+ ClientDataType.Time => timePrecision,
+ ClientDataType.DateTime => timePrecision,
+ ClientDataType.Timestamp => timestampPrecision,
+ _ => 0
+ };
+
+ var scale = value is decimal d ?
BitConverter.GetBytes(decimal.GetBits(d)[3])[2] : 0;
+
+ return new Column("m_Item" + (schemaIndex + 1), colType, false, true,
true, schemaIndex, Scale: scale, precision);
+ }
+
+ private async Task AssertClientAndServerHashesAreEqual(int timePrecision =
9, int timestampPrecision = 6, params object[] keys)
+ {
+ var (bytes, clientHash) = WriteAsBinaryTuple(keys, timePrecision,
timestampPrecision);
+ var clientHash2 = WriteAsIgniteTuple(keys, timePrecision,
timestampPrecision);
+
+ var serverHash = await GetServerHash(bytes, keys.Length,
timePrecision, timestampPrecision);
+
+ var msg = $"Time precision: {timePrecision}, timestamp precision:
{timestampPrecision}, keys: {string.Join(", ", keys)}";
+
+ Assert.AreEqual(serverHash, clientHash, $"Server hash mismatch.
{msg}");
+ Assert.AreEqual(clientHash, clientHash2, $"IgniteTuple hash mismatch.
{msg}");
+
+ if (keys.Length == 1)
+ {
+ var obj = keys[0];
+ var method = GetType().GetMethod("WriteAsPoco",
BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(obj.GetType());
+ var clientHash3 = (int)method.Invoke(null, new[] { obj,
timePrecision, timestampPrecision })!;
+
+ Assert.AreEqual(clientHash, clientHash3, $"Poco hash mismatch.
{msg}");
+ }
}
- private async Task<int> GetServerHash(byte[] bytes, int count)
+ private async Task<int> GetServerHash(byte[] bytes, int count, int
timePrecision, int timestampPrecision)
{
var nodes = await Client.GetClusterNodesAsync();
- return await Client.Compute.ExecuteAsync<int>(nodes,
ColocationHashJob, count, bytes);
+ return await Client.Compute.ExecuteAsync<int>(nodes,
ColocationHashJob, count, bytes, timePrecision, timestampPrecision);
}
- private class TestIndexProvider : IHashedColumnIndexProvider
+ private record TestIndexProvider(Func<int, bool> Delegate) :
IHashedColumnIndexProvider
{
- public bool IsHashedColumnIndex(int index) => index % 3 == 2;
+ public bool IsHashedColumnIndex(int index) => Delegate(index);
}
}
diff --git
a/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/IgniteDbDataReaderTests.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/IgniteDbDataReaderTests.cs
index 937918196a..8ca038db30 100644
---
a/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/IgniteDbDataReaderTests.cs
+++
b/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/IgniteDbDataReaderTests.cs
@@ -640,7 +640,7 @@ public class IgniteDbDataReaderTests : IgniteTestsBase
var dt = new DataTable();
dt.Load(reader);
- Assert.AreEqual(14, dt.Columns.Count);
+ Assert.AreEqual(17, dt.Columns.Count);
Assert.AreEqual(0, dt.Rows.Count);
}
@@ -660,7 +660,7 @@ public class IgniteDbDataReaderTests : IgniteTestsBase
bool readRes = await reader.ReadAsync();
Assert.IsFalse(readRes);
- Assert.AreEqual(14, reader.FieldCount);
+ Assert.AreEqual(17, reader.FieldCount);
Assert.IsFalse(reader.HasRows);
}
diff --git
a/modules/platforms/dotnet/Apache.Ignite.Tests/Table/Serialization/ObjectSerializerHandlerTests.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/Table/Serialization/ObjectSerializerHandlerTests.cs
index 18c3328a83..ffb1a946a0 100644
---
a/modules/platforms/dotnet/Apache.Ignite.Tests/Table/Serialization/ObjectSerializerHandlerTests.cs
+++
b/modules/platforms/dotnet/Apache.Ignite.Tests/Table/Serialization/ObjectSerializerHandlerTests.cs
@@ -34,8 +34,8 @@ namespace Apache.Ignite.Tests.Table.Serialization
{
private static readonly Schema Schema = new(1, 1, new[]
{
- new Column("Key", ClientDataType.Int64, IsNullable: false,
IsColocation: true, IsKey: true, SchemaIndex: 0, Scale: 0),
- new Column("Val", ClientDataType.String, IsNullable: false,
IsColocation: false, IsKey: false, SchemaIndex: 1, Scale: 0)
+ new Column("Key", ClientDataType.Int64, IsNullable: false,
IsColocation: true, IsKey: true, SchemaIndex: 0, Scale: 0, Precision: 0),
+ new Column("Val", ClientDataType.String, IsNullable: false,
IsColocation: false, IsKey: false, SchemaIndex: 1, Scale: 0, Precision: 0)
});
[Test]
diff --git
a/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/BinaryTuple/BinaryTupleBuilder.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/BinaryTuple/BinaryTupleBuilder.cs
index be26695dd9..caee7cd4f9 100644
---
a/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/BinaryTuple/BinaryTupleBuilder.cs
+++
b/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/BinaryTuple/BinaryTupleBuilder.cs
@@ -25,6 +25,7 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
using System.Runtime.InteropServices;
using Buffers;
using NodaTime;
+ using Table;
/// <summary>
/// Binary tuple builder.
@@ -691,16 +692,17 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
/// Appends a time.
/// </summary>
/// <param name="value">Value.</param>
- public void AppendTime(LocalTime value)
+ /// <param name="precision">Precision.</param>
+ public void AppendTime(LocalTime value, int precision)
{
if (ShouldHash())
{
- _hash = HashUtils.Hash32(value, _hash);
+ _hash = HashUtils.Hash32(value, precision, _hash);
}
if (value != default)
{
- PutTime(value);
+ PutTime(value, precision);
}
OnWrite();
@@ -710,7 +712,8 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
/// Appends a time.
/// </summary>
/// <param name="value">Value.</param>
- public void AppendTimeNullable(LocalTime? value)
+ /// <param name="precision">Precision.</param>
+ public void AppendTimeNullable(LocalTime? value, int precision)
{
if (value == null)
{
@@ -718,7 +721,7 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
}
else
{
- AppendTime(value.Value);
+ AppendTime(value.Value, precision);
}
}
@@ -726,17 +729,18 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
/// Appends a date and time.
/// </summary>
/// <param name="value">Value.</param>
- public void AppendDateTime(LocalDateTime value)
+ /// <param name="precision">Precision.</param>
+ public void AppendDateTime(LocalDateTime value, int precision)
{
if (ShouldHash())
{
- _hash = HashUtils.Hash32(value, _hash);
+ _hash = HashUtils.Hash32(value, precision, _hash);
}
if (value != BinaryTupleCommon.DefaultDateTime)
{
PutDate(value.Date);
- PutTime(value.TimeOfDay);
+ PutTime(value.TimeOfDay, precision);
}
OnWrite();
@@ -746,7 +750,8 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
/// Appends a date and time.
/// </summary>
/// <param name="value">Value.</param>
- public void AppendDateTimeNullable(LocalDateTime? value)
+ /// <param name="precision">Precision.</param>
+ public void AppendDateTimeNullable(LocalDateTime? value, int precision)
{
if (value == null)
{
@@ -754,7 +759,7 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
}
else
{
- AppendDateTime(value.Value);
+ AppendDateTime(value.Value, precision);
}
}
@@ -762,25 +767,15 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
/// Appends a timestamp (instant).
/// </summary>
/// <param name="value">Value.</param>
- public void AppendTimestamp(Instant value)
+ /// <param name="precision">Precision.</param>
+ public void AppendTimestamp(Instant value, int precision)
{
- if (value != default)
- {
- var (seconds, nanos) = PutTimestamp(value);
+ var (seconds, nanos) = value != default ? PutTimestamp(value,
precision) : (0, 0);
- if (ShouldHash())
- {
- _hash = HashUtils.Hash32(seconds, _hash);
- _hash = HashUtils.Hash32((long)nanos, _hash);
- }
- }
- else
+ if (ShouldHash())
{
- if (ShouldHash())
- {
- _hash = HashUtils.Hash32(0L, _hash);
- _hash = HashUtils.Hash32(0L, _hash);
- }
+ _hash = HashUtils.Hash32(seconds, _hash);
+ _hash = HashUtils.Hash32((long)nanos, _hash);
}
OnWrite();
@@ -790,7 +785,8 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
/// Appends a timestamp (instant).
/// </summary>
/// <param name="value">Value.</param>
- public void AppendTimestampNullable(Instant? value)
+ /// <param name="precision">Precision.</param>
+ public void AppendTimestampNullable(Instant? value, int precision)
{
if (value == null)
{
@@ -798,7 +794,7 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
}
else
{
- AppendTimestamp(value.Value);
+ AppendTimestamp(value.Value, precision);
}
}
@@ -880,7 +876,8 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
/// <param name="value">Value.</param>
/// <param name="colType">Column type.</param>
/// <param name="scale">Decimal scale.</param>
- public void AppendObject(object? value, ClientDataType colType, int
scale = 0)
+ /// <param name="precision">Precision.</param>
+ public void AppendObject(object? value, ClientDataType colType, int
scale = 0, int precision = TemporalTypes.MaxTimePrecision)
{
if (value == null)
{
@@ -943,15 +940,15 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
break;
case ClientDataType.Time:
- AppendTime((LocalTime)value);
+ AppendTime((LocalTime)value, precision);
break;
case ClientDataType.DateTime:
- AppendDateTime((LocalDateTime)value);
+ AppendDateTime((LocalDateTime)value, precision);
break;
case ClientDataType.Timestamp:
- AppendTimestamp((Instant)value);
+ AppendTimestamp((Instant)value, precision);
break;
default:
@@ -963,7 +960,12 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
/// Appends an object.
/// </summary>
/// <param name="value">Value.</param>
- public void AppendObjectWithType(object? value)
+ /// <param name="timePrecision">Time precision.</param>
+ /// <param name="timestampPrecision">Timestamp precision.</param>
+ public void AppendObjectWithType(
+ object? value,
+ int timePrecision = TemporalTypes.MaxTimePrecision,
+ int timestampPrecision = TemporalTypes.MaxTimePrecision)
{
switch (value)
{
@@ -1036,17 +1038,17 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
case LocalTime localTime:
AppendTypeAndScale(ClientDataType.Time);
- AppendTime(localTime);
+ AppendTime(localTime, timePrecision);
break;
case LocalDateTime localDateTime:
AppendTypeAndScale(ClientDataType.DateTime);
- AppendDateTime(localDateTime);
+ AppendDateTime(localDateTime, timePrecision);
break;
case Instant instant:
AppendTypeAndScale(ClientDataType.Timestamp);
- AppendTimestamp(instant);
+ AppendTimestamp(instant, timestampPrecision);
break;
case BitArray bitArray:
@@ -1227,7 +1229,7 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
_buffer.Advance(actualBytes);
}
- private (long Seconds, int Nanos) PutTimestamp(Instant value)
+ private (long Seconds, int Nanos) PutTimestamp(Instant value, int
precision)
{
// Logic taken from
//
https://github.com/nodatime/nodatime.serialization/blob/main/src/NodaTime.Serialization.Protobuf/NodaExtensions.cs#L69
@@ -1235,7 +1237,7 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
// See discussion:
https://github.com/nodatime/nodatime/issues/1644#issuecomment-1260524451
long seconds = value.ToUnixTimeSeconds();
Duration remainder = value - Instant.FromUnixTimeSeconds(seconds);
- int nanos = (int)remainder.NanosecondOfDay;
+ int nanos =
TemporalTypes.NormalizeNanos((int)remainder.NanosecondOfDay, precision);
PutLong(seconds);
@@ -1306,12 +1308,12 @@ namespace Apache.Ignite.Internal.Proto.BinaryTuple
}
}
- private void PutTime(LocalTime value)
+ private void PutTime(LocalTime value, int precision)
{
long hour = value.Hour;
long minute = value.Minute;
long second = value.Second;
- long nanos = value.NanosecondOfSecond;
+ long nanos =
TemporalTypes.NormalizeNanos(value.NanosecondOfSecond, precision);
if ((nanos % 1000) != 0)
{
diff --git a/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/HashUtils.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/HashUtils.cs
index 7e9a886e57..c386d535b2 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/HashUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/HashUtils.cs
@@ -21,6 +21,7 @@ using System;
using System.Buffers.Binary;
using System.Numerics;
using NodaTime;
+using Table;
/// <summary>
/// Hash function based on MurmurHash3
@@ -107,21 +108,24 @@ internal static class HashUtils
/// Generates 32-bit hash.
/// </summary>
/// <param name="data">Input data.</param>
+ /// <param name="precision">Precision.</param>
/// <param name="seed">Current hash.</param>
/// <returns>Resulting hash.</returns>
- public static int Hash32(LocalTime data, int seed)
+ public static int Hash32(LocalTime data, int precision, int seed)
{
- // TODO IGNITE-17992 Account for column precision.
- return Hash32((long)data.NanosecondOfSecond, Hash32((long)data.Second,
Hash32((long)data.Minute, Hash32((long)data.Hour, seed))));
+ var nanos =
(long)TemporalTypes.NormalizeNanos(data.NanosecondOfSecond, precision);
+
+ return Hash32(nanos, Hash32((long)data.Second,
Hash32((long)data.Minute, Hash32((long)data.Hour, seed))));
}
/// <summary>
/// Generates 32-bit hash.
/// </summary>
/// <param name="data">Input data.</param>
+ /// <param name="precision">Precision.</param>
/// <param name="seed">Current hash.</param>
/// <returns>Resulting hash.</returns>
- public static int Hash32(LocalDateTime data, int seed) =>
Hash32(data.TimeOfDay, Hash32(data.Date, seed));
+ public static int Hash32(LocalDateTime data, int precision, int seed) =>
Hash32(data.TimeOfDay, precision, Hash32(data.Date, seed));
private static int Hash32Internal(ulong data, ulong seed, byte byteCount)
{
diff --git a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Column.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Column.cs
index 72c7cc3a1b..0db3ab6972 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Column.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Column.cs
@@ -22,5 +22,13 @@ namespace Apache.Ignite.Internal.Table
/// <summary>
/// Schema column.
/// </summary>
- internal record Column(string Name, ClientDataType Type, bool IsNullable,
bool IsColocation, bool IsKey, int SchemaIndex, int Scale);
+ internal record Column(
+ string Name,
+ ClientDataType Type,
+ bool IsNullable,
+ bool IsColocation,
+ bool IsKey,
+ int SchemaIndex,
+ int Scale,
+ int Precision);
}
diff --git
a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/ObjectSerializerHandler.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/ObjectSerializerHandler.cs
index 0a47d5a0fc..834bffb9da 100644
---
a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/ObjectSerializerHandler.cs
+++
b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/ObjectSerializerHandler.cs
@@ -123,6 +123,10 @@ namespace Apache.Ignite.Internal.Table.Serialization
{
il.Emit(OpCodes.Ldc_I4, col.Scale);
}
+ else if (col.Type is ClientDataType.Time or
ClientDataType.DateTime or ClientDataType.Timestamp)
+ {
+ il.Emit(OpCodes.Ldc_I4, col.Precision);
+ }
il.Emit(OpCodes.Call, directWriteMethod);
@@ -162,6 +166,10 @@ namespace Apache.Ignite.Internal.Table.Serialization
{
il.Emit(OpCodes.Ldc_I4, col.Scale);
}
+ else if (col.Type is ClientDataType.Time or
ClientDataType.DateTime or ClientDataType.Timestamp)
+ {
+ il.Emit(OpCodes.Ldc_I4, col.Precision);
+ }
var writeMethod =
BinaryTupleMethods.GetWriteMethod(fieldInfo.FieldType);
il.Emit(OpCodes.Call, writeMethod);
@@ -238,6 +246,10 @@ namespace Apache.Ignite.Internal.Table.Serialization
{
il.Emit(OpCodes.Ldc_I4, col.Scale);
}
+ else if (col.Type is ClientDataType.Time or
ClientDataType.DateTime or ClientDataType.Timestamp)
+ {
+ il.Emit(OpCodes.Ldc_I4, col.Precision);
+ }
var writeMethod =
BinaryTupleMethods.GetWriteMethod(fieldInfo.FieldType);
il.Emit(OpCodes.Call, writeMethod);
diff --git
a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/TuplePairSerializerHandler.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/TuplePairSerializerHandler.cs
index 36cb87bba6..296c0b2321 100644
---
a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/TuplePairSerializerHandler.cs
+++
b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/TuplePairSerializerHandler.cs
@@ -92,7 +92,7 @@ internal class TuplePairSerializerHandler :
IRecordSerializerHandler<KvPair<IIgn
if (colIdx >= 0)
{
- tupleBuilder.AppendObject(rec[colIdx], col.Type, col.Scale);
+ tupleBuilder.AppendObject(rec[colIdx], col.Type, col.Scale,
col.Precision);
}
else
{
diff --git
a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/TupleSerializerHandler.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/TupleSerializerHandler.cs
index 2bdb64bf12..5eb0d4a5f3 100644
---
a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/TupleSerializerHandler.cs
+++
b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Serialization/TupleSerializerHandler.cs
@@ -91,7 +91,7 @@ namespace Apache.Ignite.Internal.Table.Serialization
if (colIdx >= 0)
{
- tupleBuilder.AppendObject(record[colIdx], col.Type,
col.Scale);
+ tupleBuilder.AppendObject(record[colIdx], col.Type,
col.Scale, col.Precision);
}
else
{
diff --git a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Table.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Table.cs
index f66d358d1a..2e110f246b 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Table.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/Table.cs
@@ -303,7 +303,7 @@ namespace Apache.Ignite.Internal.Table
for (var i = 0; i < columnCount; i++)
{
var propertyCount = r.ReadArrayHeader();
- const int expectedCount = 6;
+ const int expectedCount = 7;
Debug.Assert(propertyCount >= expectedCount, "propertyCount >=
" + expectedCount);
@@ -313,10 +313,11 @@ namespace Apache.Ignite.Internal.Table
var isNullable = r.ReadBoolean();
var isColocation = r.ReadBoolean(); // IsColocation.
var scale = r.ReadInt32();
+ var precision = r.ReadInt32();
r.Skip(propertyCount - expectedCount);
- var column = new Column(name, (ClientDataType)type,
isNullable, isColocation, isKey, i, scale);
+ var column = new Column(name, (ClientDataType)type,
isNullable, isColocation, isKey, i, scale, precision);
columns[i] = column;
diff --git
a/modules/platforms/dotnet/Apache.Ignite/Internal/Table/TemporalTypes.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/TemporalTypes.cs
new file mode 100644
index 0000000000..fb9b63ce51
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/Table/TemporalTypes.cs
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Internal.Table;
+
+using System;
+using Proto;
+
+/// <summary>
+/// Temporal type utils.
+/// </summary>
+internal static class TemporalTypes
+{
+ /// <summary>
+ /// Max <see cref="ClientDataType.Time"/> type precision.
+ /// </summary>
+ public const int MaxTimePrecision = 9;
+
+ /// <summary>
+ /// Normalize nanoseconds regarding the precision.
+ /// </summary>
+ /// <param name="nanos">Nanoseconds.</param>
+ /// <param name="precision">Precision.</param>
+ /// <returns>Normalized nanoseconds.</returns>
+ public static int NormalizeNanos(int nanos, int precision) =>
+ precision switch
+ {
+ 0 => 0,
+ 1 => (nanos / 100_000_000) * 100_000_000, // 100ms precision.
+ 2 => (nanos / 10_000_000) * 10_000_000, // 10ms precision.
+ 3 => (nanos / 1_000_000) * 1_000_000, // 1ms precision.
+ 4 => (nanos / 100_000) * 100_000, // 100us precision.
+ 5 => (nanos / 10_000) * 10_000, // 10us precision.
+ 6 => (nanos / 1_000) * 1_000, // 1us precision.
+ 7 => (nanos / 100) * 100, // 100ns precision.
+ 8 => (nanos / 10) * 10, // 10ns precision.
+ 9 => nanos, // 1ns precision
+ _ => throw new ArgumentException("Unsupported fractional seconds
precision: " + precision)
+ };
+}
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
index 1730ae4ddc..30c12d77a7 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
@@ -47,6 +47,7 @@ import org.apache.ignite.internal.schema.row.Row;
import
org.apache.ignite.internal.schema.testutils.SchemaConfigurationConverter;
import org.apache.ignite.internal.schema.testutils.builder.SchemaBuilders;
import org.apache.ignite.internal.schema.testutils.definition.ColumnType;
+import
org.apache.ignite.internal.schema.testutils.definition.ColumnType.TemporalColumnType;
import org.apache.ignite.internal.schema.testutils.definition.TableDefinition;
import org.apache.ignite.internal.table.distributed.TableManager;
import org.apache.ignite.internal.util.IgniteUtils;
@@ -179,6 +180,8 @@ public class PlatformTestNodeRunner {
.changePartitions(10)
));
+ int maxTimePrecision = TemporalColumnType.MAX_TIME_PRECISION;
+
TableDefinition schTblAll = SchemaBuilders.tableBuilder(SCHEMA_NAME,
TABLE_NAME_ALL_COLUMNS).columns(
SchemaBuilders.column(keyCol, ColumnType.INT64).build(),
SchemaBuilders.column("str",
ColumnType.string()).asNullable(true).build(),
@@ -191,12 +194,12 @@ public class PlatformTestNodeRunner {
SchemaBuilders.column("uuid",
ColumnType.UUID).asNullable(true).build(),
SchemaBuilders.column("date",
ColumnType.DATE).asNullable(true).build(),
SchemaBuilders.column("bitmask",
ColumnType.bitmaskOf(64)).asNullable(true).build(),
- SchemaBuilders.column("time",
ColumnType.time(ColumnType.TemporalColumnType.MAX_TIME_PRECISION))
- .asNullable(true).build(),
- SchemaBuilders.column("datetime",
ColumnType.datetime(ColumnType.TemporalColumnType.MAX_TIME_PRECISION))
- .asNullable(true).build(),
- SchemaBuilders.column("timestamp",
ColumnType.timestamp(ColumnType.TemporalColumnType.MAX_TIME_PRECISION))
- .asNullable(true).build(),
+ SchemaBuilders.column("time",
ColumnType.time(maxTimePrecision)).asNullable(true).build(),
+ SchemaBuilders.column("time2",
ColumnType.time(2)).asNullable(true).build(),
+ SchemaBuilders.column("datetime",
ColumnType.datetime(maxTimePrecision)).asNullable(true).build(),
+ SchemaBuilders.column("datetime2",
ColumnType.datetime(3)).asNullable(true).build(),
+ SchemaBuilders.column("timestamp",
ColumnType.timestamp(maxTimePrecision)).asNullable(true).build(),
+ SchemaBuilders.column("timestamp2",
ColumnType.timestamp(4)).asNullable(true).build(),
SchemaBuilders.column("blob",
ColumnType.blob()).asNullable(true).build(),
SchemaBuilders.column("decimal",
ColumnType.decimal()).asNullable(true).build()
).withPrimaryKey(keyCol).build();
@@ -218,12 +221,12 @@ public class PlatformTestNodeRunner {
SchemaBuilders.column("float",
ColumnType.FLOAT).asNullable(true).build(),
SchemaBuilders.column("double",
ColumnType.DOUBLE).asNullable(true).build(),
SchemaBuilders.column("date",
ColumnType.DATE).asNullable(true).build(),
- SchemaBuilders.column("time",
ColumnType.time(ColumnType.TemporalColumnType.MAX_TIME_PRECISION))
- .asNullable(true).build(),
- SchemaBuilders.column("datetime",
ColumnType.datetime(ColumnType.TemporalColumnType.MAX_TIME_PRECISION))
- .asNullable(true).build(),
- SchemaBuilders.column("timestamp",
ColumnType.timestamp(ColumnType.TemporalColumnType.MAX_TIME_PRECISION))
- .asNullable(true).build(),
+ SchemaBuilders.column("time",
ColumnType.time(maxTimePrecision)).asNullable(true).build(),
+ SchemaBuilders.column("time2",
ColumnType.time(maxTimePrecision)).asNullable(true).build(),
+ SchemaBuilders.column("datetime",
ColumnType.datetime(maxTimePrecision)).asNullable(true).build(),
+ SchemaBuilders.column("datetime2",
ColumnType.datetime(maxTimePrecision)).asNullable(true).build(),
+ SchemaBuilders.column("timestamp",
ColumnType.timestamp(maxTimePrecision)).asNullable(true).build(),
+ SchemaBuilders.column("timestamp2",
ColumnType.timestamp(maxTimePrecision)).asNullable(true).build(),
SchemaBuilders.column("blob",
ColumnType.blob()).asNullable(true).build(),
SchemaBuilders.column("decimal",
ColumnType.decimal()).asNullable(true).build()
).withPrimaryKey(keyCol).build();
@@ -350,6 +353,9 @@ public class PlatformTestNodeRunner {
public Integer execute(JobExecutionContext context, Object... args) {
var columnCount = (int) args[0];
var buf = (byte[]) args[1];
+ var timePrecision = (int) args[2];
+ var timestampPrecision = (int) args[3];
+
var columns = new Column[columnCount];
var tuple = Tuple.create(columnCount);
var reader = new BinaryTupleReader(columnCount * 3, buf);
@@ -423,17 +429,17 @@ public class PlatformTestNodeRunner {
break;
case ClientDataType.TIME:
- columns[i] = new Column(i, colName,
NativeTypes.time(9), false);
+ columns[i] = new Column(i, colName,
NativeTypes.time(timePrecision), false);
tuple.set(colName, reader.timeValue(valIdx));
break;
case ClientDataType.DATETIME:
- columns[i] = new Column(i, colName,
NativeTypes.datetime(9), false);
+ columns[i] = new Column(i, colName,
NativeTypes.datetime(timePrecision), false);
tuple.set(colName, reader.dateTimeValue(valIdx));
break;
case ClientDataType.TIMESTAMP:
- columns[i] = new Column(i, colName,
NativeTypes.timestamp(), false);
+ columns[i] = new Column(i, colName,
NativeTypes.timestamp(timestampPrecision), false);
tuple.set(colName, reader.timestampValue(valIdx));
break;
diff --git
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/TemporalTypesHelper.java
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/TemporalTypesHelper.java
index 3d6320ac90..223641b067 100644
---
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/TemporalTypesHelper.java
+++
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/TemporalTypesHelper.java
@@ -157,7 +157,7 @@ public class TemporalTypesHelper {
time |= localTime.getMinute() << SECONDS_FIELD_LENGTH;
time |= localTime.getSecond();
- int fractional = truncateTo(type.precision(), localTime.getNano());
+ int fractional = truncateTo(localTime.getNano(), type.precision());
return ((long) time << 32) | fractional;
}
@@ -223,15 +223,15 @@ public class TemporalTypesHelper {
break;
}
case 4: {
- nanos = (nanos / 100_000) * 100_000; // 100mcs precision.
+ nanos = (nanos / 100_000) * 100_000; // 100us precision.
break;
}
case 5: {
- nanos = (nanos / 10_000) * 10_000; // 10mcs precision.
+ nanos = (nanos / 10_000) * 10_000; // 10us precision.
break;
}
case 6: {
- nanos = (nanos / 1_000) * 1_000; // 1mcs precision.
+ nanos = (nanos / 1_000) * 1_000; // 1us precision.
break;
}
case 7: {
@@ -256,11 +256,11 @@ public class TemporalTypesHelper {
/**
* Normalize to given precision and truncate to meaningful time unit.
*
+ * @param nanos Seconds' fractional part.
* @param precision Precision.
- * @param nanos Seconds' fractional part.
* @return Truncated fractional seconds (millis, micros or nanos).
*/
- private static int truncateTo(int precision, int nanos) {
+ private static int truncateTo(int nanos, int precision) {
switch (precision) {
case 0:
return 0;
@@ -272,13 +272,13 @@ public class TemporalTypesHelper {
return nanos / 1_000_000; // 1ms precision.
}
case 4: {
- return (nanos / 100_000) * 100; // 100mcs precision.
+ return (nanos / 100_000) * 100; // 100us precision.
}
case 5: {
- return (nanos / 10_000) * 10; // 10mcs precision.
+ return (nanos / 10_000) * 10; // 10us precision.
}
case 6: {
- return nanos / 1_000; // 1mcs precision.
+ return nanos / 1_000; // 1us precision.
}
case 7: {
return (nanos / 100) * 100; // 100ns precision.