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) {