You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2022/11/14 10:22:01 UTC

[ignite-3] branch main updated: IGNITE-18015 Column's type mismatch error when inserting data into temporal columns with custom precision (#1323)

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

amashenkov 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 c7f3f8dd58 IGNITE-18015 Column's type mismatch error when inserting data into temporal columns with custom precision (#1323)
c7f3f8dd58 is described below

commit c7f3f8dd58bfe3d978f33f6929f933b72d22cc08
Author: Andrew V. Mashenkov <AM...@users.noreply.github.com>
AuthorDate: Mon Nov 14 13:21:56 2022 +0300

    IGNITE-18015 Column's type mismatch error when inserting data into temporal columns with custom precision (#1323)
---
 .../java/org/apache/ignite/table/TupleImpl.java    |   7 ++
 .../internal/tostring/IgniteToStringBuilder.java   |  24 +++++
 .../ignite/internal/schema/TemporalNativeType.java |   6 --
 .../exec/rel/IndexScanNodeExecutionTest.java       |   2 +-
 .../internal/table/MutableRowTupleAdapterTest.java | 103 ++++++++++++++++++++-
 5 files changed, 133 insertions(+), 9 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java b/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java
index 2ba4ff7bf4..25795195bc 100644
--- a/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java
+++ b/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java
@@ -32,6 +32,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.UUID;
 import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.internal.tostring.S;
 import org.apache.ignite.internal.util.IgniteNameUtils;
 import org.jetbrains.annotations.NotNull;
 
@@ -394,4 +395,10 @@ class TupleImpl implements Tuple, Serializable {
             colMapping.put(colNames.get(i), i);
         }
     }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(Tuple.class.getSimpleName(), colNames, colValues);
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/tostring/IgniteToStringBuilder.java b/modules/core/src/main/java/org/apache/ignite/internal/tostring/IgniteToStringBuilder.java
index a0ded66403..fc9c2b57bf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/tostring/IgniteToStringBuilder.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/tostring/IgniteToStringBuilder.java
@@ -1380,6 +1380,30 @@ public class IgniteToStringBuilder {
         }
     }
 
+    /**
+     * Creates an uniformed string presentation for the binary-like object.
+     *
+     * @param str Output prefix or {@code null} if empty.
+     * @param propNames Names of object properties.
+     * @param propVals Property values.
+     * @return String presentation of the object.
+     */
+    public static String toString(String str, List<?> propNames, List<?> propVals) {
+        StringBuilderLimitedLength sb = threadLocSB.get();
+
+        boolean newStr = sb.length() == 0;
+
+        try {
+            assert propNames.size() == propVals.size();
+
+            return toStringImpl(str, sb, propNames.toArray(), propVals.toArray(), null, propNames.size());
+        } finally {
+            if (newStr) {
+                sb.reset();
+            }
+        }
+    }
+
     /**
      * Produces uniformed output of string with context properties.
      *
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/TemporalNativeType.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/TemporalNativeType.java
index a71948e7c6..91164870c8 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/TemporalNativeType.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/TemporalNativeType.java
@@ -108,12 +108,6 @@ public class TemporalNativeType extends NativeType {
         return precision;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public boolean mismatch(NativeType type) {
-        return super.mismatch(type) || precision < ((TemporalNativeType) type).precision;
-    }
-
     /** {@inheritDoc} */
     @Override
     public String toString() {
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/IndexScanNodeExecutionTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/IndexScanNodeExecutionTest.java
index 9e90e4b288..4f0670a249 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/IndexScanNodeExecutionTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/IndexScanNodeExecutionTest.java
@@ -269,7 +269,7 @@ public class IndexScanNodeExecutionTest extends AbstractExecutionTest {
 
                 data[rowNum][0] = uniqueNumList.get(rowNum);
                 data[rowNum][1] = bound1 == 0 ? null : bound1;
-                data[rowNum][2] = bound2 == 0 ? null : bound2;;
+                data[rowNum][2] = bound2 == 0 ? null : bound2;
                 data[rowNum][3] = "row-" + rowNum;
             }
         }
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/MutableRowTupleAdapterTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/MutableRowTupleAdapterTest.java
index 05ac2df910..56bb7b6f85 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/MutableRowTupleAdapterTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/MutableRowTupleAdapterTest.java
@@ -30,6 +30,7 @@ import static org.apache.ignite.internal.schema.NativeTypes.STRING;
 import static org.apache.ignite.internal.schema.NativeTypes.datetime;
 import static org.apache.ignite.internal.schema.NativeTypes.time;
 import static org.apache.ignite.internal.schema.NativeTypes.timestamp;
+import static org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -54,9 +55,11 @@ import java.util.Random;
 import java.util.UUID;
 import org.apache.ignite.internal.schema.ByteBufferRow;
 import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.InvalidTypeException;
 import org.apache.ignite.internal.schema.NativeTypes;
 import org.apache.ignite.internal.schema.SchemaAware;
 import org.apache.ignite.internal.schema.SchemaDescriptor;
+import org.apache.ignite.internal.schema.SchemaMismatchException;
 import org.apache.ignite.internal.schema.marshaller.TupleMarshaller;
 import org.apache.ignite.internal.schema.marshaller.TupleMarshallerException;
 import org.apache.ignite.internal.schema.marshaller.TupleMarshallerImpl;
@@ -351,7 +354,7 @@ public class MutableRowTupleAdapterTest {
 
         TupleMarshaller marshaller = new TupleMarshallerImpl(new DummySchemaManagerImpl(fullSchema));
 
-        Tuple  tuple = Tuple.create()
+        Tuple tuple = Tuple.create()
                 .set("valByteCol", (byte) 1)
                 .set("valShortCol", (short) 2)
                 .set("valIntCol", 3)
@@ -543,6 +546,102 @@ public class MutableRowTupleAdapterTest {
         assertEquals(val1, val2);
     }
 
+    @Test
+    void testTemporalValuesPrecisionConstraint() throws Exception {
+        SchemaDescriptor schemaDescriptor = new SchemaDescriptor(1,
+                new Column[]{new Column("key", NativeTypes.INT32, false)},
+                new Column[]{
+                        new Column("time", NativeTypes.time(2), true),
+                        new Column("datetime", NativeTypes.datetime(2), true),
+                        new Column("timestamp", NativeTypes.timestamp(2), true)
+                }
+        );
+
+        Tuple tuple = Tuple.create().set("key", 1)
+                .set("time", LocalTime.of(1, 2, 3, 456_700_000))
+                .set("datetime", LocalDateTime.of(2022, 1, 2, 3, 4, 5, 678_900_000))
+                .set("timestamp", Instant.ofEpochSecond(123, 456_700_000));
+        Tuple expected = Tuple.create().set("key", 1)
+                .set("time", LocalTime.of(1, 2, 3, 450_000_000))
+                .set("datetime", LocalDateTime.of(2022, 1, 2, 3, 4, 5, 670_000_000))
+                .set("timestamp", Instant.ofEpochSecond(123, 450_000_000));
+
+        TupleMarshaller marshaller = new TupleMarshallerImpl(new DummySchemaManagerImpl(schemaDescriptor));
+
+        Row row = new Row(schemaDescriptor, new ByteBufferRow(marshaller.marshal(tuple).bytes()));
+
+        Tuple tuple1 = deserializeTuple(serializeTuple(TableRow.tuple(row)));
+
+        assertEquals(expected, tuple1);
+    }
+
+    @Test
+    void testVarlenValuesLengthConstraints() throws Exception {
+        SchemaDescriptor schemaDescriptor = new SchemaDescriptor(1,
+                new Column[]{new Column("key", NativeTypes.INT32, false)},
+                new Column[]{
+                        new Column("string", NativeTypes.stringOf(5), true),
+                        new Column("bytes", NativeTypes.blobOf(5), true),
+                }
+        );
+
+        TupleMarshaller marshaller = new TupleMarshallerImpl(new DummySchemaManagerImpl(schemaDescriptor));
+
+        Tuple tuple1 = Tuple.create().set("key", 1)
+                .set("string", "abcef")
+                .set("bytes", new byte[]{1, 2, 3, 4, 5, 6, 7, 8});
+        Tuple tuple2 = Tuple.create().set("key", 1)
+                .set("string", "abcefghi")
+                .set("bytes", new byte[]{1, 2, 3, 4, 5});
+
+        assertThrowsWithCause(() -> marshaller.marshal(tuple1).bytes(), InvalidTypeException.class, "Column's type mismatch");
+        assertThrowsWithCause(() -> marshaller.marshal(tuple2).bytes(), InvalidTypeException.class, "Column's type mismatch");
+
+        Tuple expected = Tuple.create().set("key", 1)
+                .set("string", "abc")
+                .set("bytes", new byte[]{1, 2, 3});
+
+        Row row = new Row(schemaDescriptor, new ByteBufferRow(marshaller.marshal(expected).bytes()));
+
+        assertEquals(expected, deserializeTuple(serializeTuple(TableRow.tuple(row))));
+    }
+
+    @Test
+    void testDecimalPrecisionConstraint() {
+        SchemaDescriptor schemaDescriptor = new SchemaDescriptor(1,
+                new Column[]{new Column("key", INT32, false)},
+                new Column[]{
+                        new Column("decimal", NativeTypes.decimalOf(7, 2), true),
+                }
+        );
+
+        TupleMarshaller marshaller = new TupleMarshallerImpl(new DummySchemaManagerImpl(schemaDescriptor));
+
+        Tuple tuple1 = Tuple.create().set("key", 1).set("decimal", new BigDecimal("123456.7"));
+
+        assertThrowsWithCause(() -> marshaller.marshal(tuple1).bytes(), SchemaMismatchException.class,
+                "Failed to set decimal value for column 'decimal' (max precision exceeds allocated precision)");
+    }
+
+    @Test
+    void testDecimalScaleConstraint() throws Exception {
+        SchemaDescriptor schemaDescriptor = new SchemaDescriptor(1,
+                new Column[]{new Column("key", INT32, false)},
+                new Column[]{
+                        new Column("decimal", NativeTypes.decimalOf(5, 2), true),
+                }
+        );
+
+        TupleMarshaller marshaller = new TupleMarshallerImpl(new DummySchemaManagerImpl(schemaDescriptor));
+
+        Tuple tuple = Tuple.create().set("key", 1).set("decimal", new BigDecimal("123.458"));
+        Tuple expected = Tuple.create().set("key", 1).set("decimal", new BigDecimal("123.46")); // Rounded.
+
+        Row row = new Row(schemaDescriptor, new ByteBufferRow(marshaller.marshal(tuple).bytes()));
+
+        assertEquals(expected, deserializeTuple(serializeTuple(TableRow.tuple(row))));
+    }
+
     private <T extends Temporal> T truncateToDefaultPrecision(T temporal) {
         int precision = temporal instanceof Instant ? ColumnType.TemporalColumnType.DEFAULT_TIMESTAMP_PRECISION
                 : ColumnType.TemporalColumnType.DEFAULT_TIME_PRECISION;
@@ -610,7 +709,7 @@ public class MutableRowTupleAdapterTest {
     /**
      * Returns random BitSet.
      *
-     * @param rnd  Random generator.
+     * @param rnd Random generator.
      * @param bits Amount of bits in bitset.
      */
     private static BitSet randomBitSet(Random rnd, int bits) {