You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2022/08/29 12:30:18 UTC

[ignite-3] branch main updated: IGNITE-17583 Extract BinaryTuple core parts into a separate module (#1040)

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 0dc1b58525 IGNITE-17583 Extract BinaryTuple core parts into a separate module (#1040)
0dc1b58525 is described below

commit 0dc1b5852531c2e7f06dc1091c21b94c454fedd3
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Mon Aug 29 15:30:12 2022 +0300

    IGNITE-17583 Extract BinaryTuple core parts into a separate module (#1040)
    
    Decouple `BinaryTupleParser`, `BinaryTupleBuilder`, `BinaryTupleReader` from internal schema functionality (`NativeTypeSpec`, etc), move to `ignite-binary-tuple` module. Allows reuse from client side.
---
 modules/binary-tuple/README.md                     |   3 +
 modules/{schema => binary-tuple}/pom.xml           |  86 +-----------
 .../internal/binarytuple}/BinaryTupleBuilder.java  | 148 ++++-----------------
 .../internal/binarytuple/BinaryTupleCommon.java    | 113 ++++++++++++++++
 .../binarytuple}/BinaryTupleFormatException.java   |  13 +-
 .../internal/binarytuple}/BinaryTupleParser.java   |  67 +++++-----
 .../internal/binarytuple}/BinaryTupleReader.java   |   2 +-
 .../internal/binarytuple}/BinaryTupleTest.java     |   6 +-
 modules/schema/pom.xml                             |   5 +
 .../ignite/internal/schema/BinaryConverter.java    |   6 +-
 .../apache/ignite/internal/schema/BinaryTuple.java |   1 +
 .../ignite/internal/schema/BinaryTupleSchema.java  | 117 ++++------------
 .../storage/AbstractMvTableStorageTest.java        |   4 +-
 .../index/impl/BinaryTupleRowSerializer.java       |  75 ++++++++++-
 parent/pom.xml                                     |  12 +-
 pom.xml                                            |   1 +
 16 files changed, 315 insertions(+), 344 deletions(-)

diff --git a/modules/binary-tuple/README.md b/modules/binary-tuple/README.md
new file mode 100644
index 0000000000..95980fa3ff
--- /dev/null
+++ b/modules/binary-tuple/README.md
@@ -0,0 +1,3 @@
+# Binary Tuple module
+
+Core binary tuple functionality. See [IEP-92: Binary Tuple Format](https://cwiki.apache.org/confluence/display/IGNITE/IEP-92%3A+Binary+Tuple+Format).
diff --git a/modules/schema/pom.xml b/modules/binary-tuple/pom.xml
similarity index 53%
copy from modules/schema/pom.xml
copy to modules/binary-tuple/pom.xml
index b256cb19fc..98effa4a21 100644
--- a/modules/schema/pom.xml
+++ b/modules/binary-tuple/pom.xml
@@ -29,35 +29,15 @@
         <relativePath>../../parent/pom.xml</relativePath>
     </parent>
 
-    <artifactId>ignite-schema</artifactId>
+    <artifactId>ignite-binary-tuple</artifactId>
     <version>3.0.0-SNAPSHOT</version>
 
     <dependencies>
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-api</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-bytecode</artifactId>
-        </dependency>
-
         <dependency>
             <groupId>org.apache.ignite</groupId>
             <artifactId>ignite-core</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-configuration</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-extended-api</artifactId>
-        </dependency>
-
         <!-- 3rd party dependencies -->
         <dependency>
             <groupId>org.jetbrains</groupId>
@@ -65,78 +45,15 @@
         </dependency>
 
         <!-- Test dependencies -->
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-configuration</artifactId>
-            <scope>test</scope>
-            <type>test-jar</type>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-core</artifactId>
-            <scope>test</scope>
-            <type>test-jar</type>
-        </dependency>
-
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter-engine</artifactId>
             <scope>test</scope>
         </dependency>
-
-        <dependency>
-            <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-params</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>com.github.npathai</groupId>
-            <artifactId>hamcrest-optional</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <!-- Benchmarks dependencies -->
-        <dependency>
-            <groupId>org.openjdk.jmh</groupId>
-            <artifactId>jmh-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>javax.annotation</groupId>
-            <artifactId>javax.annotation-api</artifactId>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
 
     <build>
         <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>default-testJar</id>
-                        <goals>
-                            <goal>test-jar</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
@@ -159,4 +76,5 @@
             </plugin>
         </plugins>
     </build>
+
 </project>
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleBuilder.java b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleBuilder.java
similarity index 82%
rename from modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleBuilder.java
rename to modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleBuilder.java
index 97e4fc6749..60825b3aad 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleBuilder.java
+++ b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleBuilder.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.schema;
+package org.apache.ignite.internal.binarytuple;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -75,9 +75,9 @@ public class BinaryTupleBuilder {
     private BinaryTupleBuilder(int numElements, boolean allowNulls, int totalValueSize) {
         this.numElements = numElements;
 
-        int base = BinaryTupleSchema.HEADER_SIZE;
+        int base = BinaryTupleCommon.HEADER_SIZE;
         if (allowNulls) {
-            base += BinaryTupleSchema.nullMapSize(numElements);
+            base += BinaryTupleCommon.nullMapSize(numElements);
         }
 
         entryBase = base;
@@ -85,7 +85,7 @@ public class BinaryTupleBuilder {
         if (totalValueSize < 0) {
             entrySize = Integer.BYTES;
         } else {
-            entrySize = BinaryTupleSchema.flagsToEntrySize(BinaryTupleSchema.valueSizeToFlags(totalValueSize));
+            entrySize = BinaryTupleCommon.flagsToEntrySize(BinaryTupleCommon.valueSizeToFlags(totalValueSize));
         }
 
         valueBase = base + entrySize * numElements;
@@ -93,27 +93,6 @@ public class BinaryTupleBuilder {
         allocate(totalValueSize);
     }
 
-    /**
-     * Creates a builder.
-     *
-     * @param schema Tuple schema.
-     * @return Tuple builder.
-     */
-    public static BinaryTupleBuilder create(BinaryTupleSchema schema) {
-        return create(schema.elementCount(), schema.hasNullableElements());
-    }
-
-    /**
-     * Creates a builder.
-     *
-     * @param schema Tuple schema.
-     * @param allowNulls True if NULL values are possible, false otherwise.
-     * @return Tuple builder.
-     */
-    public static BinaryTupleBuilder create(BinaryTupleSchema schema, boolean allowNulls) {
-        return create(schema.elementCount(), schema.hasNullableElements() && allowNulls);
-    }
-
     /**
      * Creates a builder.
      *
@@ -125,29 +104,6 @@ public class BinaryTupleBuilder {
         return create(numElements, allowNulls, -1);
     }
 
-    /**
-     * Creates a builder.
-     *
-     * @param schema Tuple schema.
-     * @param totalValueSize Total estimated length of non-NULL values, -1 if not known.
-     * @return Tuple builder.
-     */
-    public static BinaryTupleBuilder create(BinaryTupleSchema schema, int totalValueSize) {
-        return create(schema.elementCount(), schema.hasNullableElements(), totalValueSize);
-    }
-
-    /**
-     * Creates a builder.
-     *
-     * @param schema Tuple schema.
-     * @param allowNulls True if NULL values are possible, false otherwise.
-     * @param totalValueSize Total estimated length of non-NULL values, -1 if not known.
-     * @return Tuple builder.
-     */
-    public static BinaryTupleBuilder create(BinaryTupleSchema schema, boolean allowNulls, int totalValueSize) {
-        return create(schema.elementCount(), schema.hasNullableElements() && allowNulls, totalValueSize);
-    }
-
     /**
      * Creates a builder.
      *
@@ -164,7 +120,7 @@ public class BinaryTupleBuilder {
      * Check if the binary tuple contains a null map.
      */
     public boolean hasNullMap() {
-        return entryBase > BinaryTupleSchema.HEADER_SIZE;
+        return entryBase > BinaryTupleCommon.HEADER_SIZE;
     }
 
     /**
@@ -179,8 +135,8 @@ public class BinaryTupleBuilder {
 
         hasNullValues = true;
 
-        int nullIndex = BinaryTupleSchema.nullOffset(elementIndex);
-        byte nullMask = BinaryTupleSchema.nullMask(elementIndex);
+        int nullIndex = BinaryTupleCommon.nullOffset(elementIndex);
+        byte nullMask = BinaryTupleCommon.nullMask(elementIndex);
         buffer.put(nullIndex, (byte) (buffer.get(nullIndex) | nullMask));
 
         return proceed();
@@ -388,7 +344,7 @@ public class BinaryTupleBuilder {
         try {
             putString(value);
         } catch (CharacterCodingException e) {
-            throw new AssemblyException("Failed to encode string in binary tuple builder", e);
+            throw new BinaryTupleFormatException("Failed to encode string in binary tuple builder", e);
         }
         return proceed();
     }
@@ -478,7 +434,7 @@ public class BinaryTupleBuilder {
      * @return {@code this} for chaining.
      */
     public BinaryTupleBuilder appendDateNotNull(@NotNull LocalDate value) {
-        if (value != BinaryTupleSchema.DEFAULT_DATE) {
+        if (value != BinaryTupleCommon.DEFAULT_DATE) {
             putDate(value);
         }
         return proceed();
@@ -501,7 +457,7 @@ public class BinaryTupleBuilder {
      * @return {@code this} for chaining.
      */
     public BinaryTupleBuilder appendTimeNotNull(@NotNull LocalTime value) {
-        if (value != BinaryTupleSchema.DEFAULT_TIME) {
+        if (value != BinaryTupleCommon.DEFAULT_TIME) {
             putTime(value);
         }
         return proceed();
@@ -524,7 +480,7 @@ public class BinaryTupleBuilder {
      * @return {@code this} for chaining.
      */
     public BinaryTupleBuilder appendDateTimeNotNull(@NotNull LocalDateTime value) {
-        if (value != BinaryTupleSchema.DEFAULT_DATE_TIME) {
+        if (value != BinaryTupleCommon.DEFAULT_DATE_TIME) {
             putDate(value.toLocalDate());
             putTime(value.toLocalTime());
         }
@@ -548,7 +504,7 @@ public class BinaryTupleBuilder {
      * @return {@code this} for chaining.
      */
     public BinaryTupleBuilder appendTimestampNotNull(@NotNull Instant value) {
-        if (value != BinaryTupleSchema.DEFAULT_TIMESTAMP) {
+        if (value != BinaryTupleCommon.DEFAULT_TIMESTAMP) {
             long seconds = value.getEpochSecond();
             int nanos = value.getNano();
             putLong(seconds);
@@ -569,63 +525,6 @@ public class BinaryTupleBuilder {
         return value == null ? appendNull() : appendTimestampNotNull(value);
     }
 
-    /**
-     * Append a value for the current element.
-     *
-     * @param schema Tuple schema.
-     * @param value Element value.
-     * @return {@code this} for chaining.
-     */
-    public BinaryTupleBuilder appendValue(BinaryTupleSchema schema, Object value) {
-        BinaryTupleSchema.Element element = schema.element(elementIndex);
-
-        if (value == null) {
-            if (!element.nullable) {
-                throw new SchemaMismatchException("NULL value for non-nullable column in binary tuple builder.");
-            }
-            return appendNull();
-        }
-
-        switch (element.typeSpec) {
-            case INT8:
-                return appendByte((byte) value);
-            case INT16:
-                return appendShort((short) value);
-            case INT32:
-                return appendInt((int) value);
-            case INT64:
-                return appendLong((long) value);
-            case FLOAT:
-                return appendFloat((float) value);
-            case DOUBLE:
-                return appendDouble((double) value);
-            case NUMBER:
-                return appendNumberNotNull((BigInteger) value);
-            case DECIMAL:
-                return appendDecimalNotNull((BigDecimal) value);
-            case UUID:
-                return appendUuidNotNull((UUID) value);
-            case BYTES:
-                return appendBytesNotNull((byte[]) value);
-            case STRING:
-                return appendStringNotNull((String) value);
-            case BITMASK:
-                return appendBitmaskNotNull((BitSet) value);
-            case DATE:
-                return appendDateNotNull((LocalDate) value);
-            case TIME:
-                return appendTimeNotNull((LocalTime) value);
-            case DATETIME:
-                return appendDateTimeNotNull((LocalDateTime) value);
-            case TIMESTAMP:
-                return appendTimestampNotNull((Instant) value);
-            default:
-                break;
-        }
-
-        throw new InvalidTypeException("Unexpected type value: " + element.typeSpec);
-    }
-
     /**
      * Append some arbitrary content as the current element.
      *
@@ -650,6 +549,15 @@ public class BinaryTupleBuilder {
         return proceed();
     }
 
+    /**
+     * Gets the current element index.
+     *
+     * @return Element index.
+     */
+    public int elementIndex() {
+        return elementIndex;
+    }
+
     /**
      * Finalize tuple building.
      *
@@ -661,8 +569,8 @@ public class BinaryTupleBuilder {
         int offset = 0;
 
         int valueSize = buffer.position() - valueBase;
-        byte flags = BinaryTupleSchema.valueSizeToFlags(valueSize);
-        int desiredEntrySize = BinaryTupleSchema.flagsToEntrySize(flags);
+        byte flags = BinaryTupleCommon.valueSizeToFlags(valueSize);
+        int desiredEntrySize = BinaryTupleCommon.flagsToEntrySize(flags);
 
         // Shrink the offset table if needed.
         if (desiredEntrySize != entrySize) {
@@ -698,12 +606,12 @@ public class BinaryTupleBuilder {
         // Drop or move null map if needed.
         if (hasNullMap()) {
             if (!hasNullValues) {
-                offset += BinaryTupleSchema.nullMapSize(numElements);
+                offset += BinaryTupleCommon.nullMapSize(numElements);
             } else {
-                flags |= BinaryTupleSchema.NULLMAP_FLAG;
+                flags |= BinaryTupleCommon.NULLMAP_FLAG;
                 if (offset != 0) {
-                    int n = BinaryTupleSchema.nullMapSize(numElements);
-                    for (int i = BinaryTupleSchema.HEADER_SIZE + n - 1; i >= BinaryTupleSchema.HEADER_SIZE; i--) {
+                    int n = BinaryTupleCommon.nullMapSize(numElements);
+                    for (int i = BinaryTupleCommon.HEADER_SIZE + n - 1; i >= BinaryTupleCommon.HEADER_SIZE; i--) {
                         buffer.put(i + offset, buffer.get(i));
                     }
                 }
@@ -878,7 +786,7 @@ public class BinaryTupleBuilder {
         do {
             capacity *= 2;
             if (capacity < 0) {
-                throw new AssemblyException("Buffer overflow in binary tuple builder");
+                throw new BinaryTupleFormatException("Buffer overflow in binary tuple builder");
             }
         } while ((capacity - buffer.position()) < size);
 
diff --git a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleCommon.java b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleCommon.java
new file mode 100644
index 0000000000..bb5ec098fe
--- /dev/null
+++ b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleCommon.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.binarytuple;
+
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.UUID;
+import org.apache.ignite.lang.IgniteInternalException;
+
+/**
+ * Common binary tuple constants and utils.
+ */
+public class BinaryTupleCommon {
+    /** Size of a tuple header, in bytes. */
+    public static final int HEADER_SIZE = 1;
+
+    /** Mask for size of entries in variable-length offset table. */
+    public static final int VARSIZE_MASK = 0b011;
+
+    /** Flag that indicates null map presence. */
+    public static final int NULLMAP_FLAG = 0b100;
+
+    /** Default value for UUID elements. */
+    public static final UUID DEFAULT_UUID = new UUID(0, 0);
+
+    /** Default value for Date elements (Jan 1st 1 BC). */
+    public static final LocalDate DEFAULT_DATE = LocalDate.of(0, 1, 1);
+
+    /** Default value for Time elements (00:00:00). */
+    public static final LocalTime DEFAULT_TIME = LocalTime.of(0, 0);
+
+    /** Default value for DateTime elements (Jan 1st 1 BC, 00:00:00). */
+    public static final LocalDateTime DEFAULT_DATE_TIME = LocalDateTime.of(0, 1, 1, 0, 0);
+
+    /** Default value for Timestamp elements. */
+    public static final Instant DEFAULT_TIMESTAMP = Instant.EPOCH;
+
+    /**
+     * Calculates flags for a given size of variable-length area.
+     *
+     * @param size Variable-length area size.
+     * @return Flags value.
+     */
+    public static byte valueSizeToFlags(long size) {
+        if (size <= 0xff) {
+            return 0b00;
+        }
+        if (size <= 0xffff) {
+            return 0b01;
+        }
+        if (size <= Integer.MAX_VALUE) {
+            return 0b10;
+        }
+        throw new IgniteInternalException("Too big binary tuple size");
+    }
+
+    /**
+     * Calculates the size of entry in variable-length offset table for given flags.
+     *
+     * @param flags Flags value.
+     * @return Size of entry in variable-length offset table.
+     */
+    public static int flagsToEntrySize(byte flags) {
+        return 1 << (flags & VARSIZE_MASK);
+    }
+
+    /**
+     * Calculates the null map size.
+     *
+     * @param numElements Number of tuple elements.
+     * @return Null map size in bytes.
+     */
+    public static int nullMapSize(int numElements) {
+        return (numElements + 7) / 8;
+    }
+
+    /**
+     * Returns offset of the byte that contains null-bit of a given tuple element.
+     *
+     * @param index Tuple element index.
+     * @return Offset of the required byte relative to the tuple start.
+     */
+    public static int nullOffset(int index) {
+        return HEADER_SIZE + index / 8;
+    }
+
+    /**
+     * Returns a null-bit mask corresponding to a given tuple element.
+     *
+     * @param index Tuple element index.
+     * @return Mask to extract the required null-bit.
+     */
+    public static byte nullMask(int index) {
+        return (byte) (1 << (index % 8));
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleFormatException.java b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleFormatException.java
similarity index 82%
rename from modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleFormatException.java
rename to modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleFormatException.java
index 51525ce0f0..f1ac0f0a71 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleFormatException.java
+++ b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleFormatException.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.schema;
+package org.apache.ignite.internal.binarytuple;
 
 import org.apache.ignite.lang.IgniteInternalException;
 
@@ -24,11 +24,20 @@ import org.apache.ignite.lang.IgniteInternalException;
  */
 public class BinaryTupleFormatException extends IgniteInternalException {
     /**
-     * Constructor with error message.
+     * Constructor.
      *
      * @param msg Message.
      */
     public BinaryTupleFormatException(String msg) {
         super(msg);
     }
+
+    /**
+     * Constructor.
+     *
+     * @param msg Message.
+     */
+    public BinaryTupleFormatException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
 }
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleParser.java b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
similarity index 88%
rename from modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleParser.java
rename to modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
index 7539ed998a..0ace31f197 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleParser.java
+++ b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.schema;
+package org.apache.ignite.internal.binarytuple;
 
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
@@ -46,6 +46,9 @@ public class BinaryTupleParser {
         void nextElement(int index, int begin, int end);
     }
 
+    /** UUID size in bytes. */
+    private static final int UUID_SIZE = 16;
+
     /** Number of elements in the tuple. */
     private final int numElements;
 
@@ -67,7 +70,7 @@ public class BinaryTupleParser {
      * @param numElements Number of tuple elements.
      * @param buffer Buffer with a binary tuple.
      */
-    BinaryTupleParser(int numElements, ByteBuffer buffer) {
+    public BinaryTupleParser(int numElements, ByteBuffer buffer) {
         this.numElements = numElements;
 
         assert buffer.order() == ByteOrder.LITTLE_ENDIAN;
@@ -76,13 +79,13 @@ public class BinaryTupleParser {
 
         byte flags = buffer.get(0);
 
-        int base = BinaryTupleSchema.HEADER_SIZE;
-        if ((flags & BinaryTupleSchema.NULLMAP_FLAG) != 0) {
-            base += BinaryTupleSchema.nullMapSize(numElements);
+        int base = BinaryTupleCommon.HEADER_SIZE;
+        if ((flags & BinaryTupleCommon.NULLMAP_FLAG) != 0) {
+            base += BinaryTupleCommon.nullMapSize(numElements);
         }
 
         entryBase = base;
-        entrySize = 1 << (flags & BinaryTupleSchema.VARSIZE_MASK);
+        entrySize = 1 << (flags & BinaryTupleCommon.VARSIZE_MASK);
         valueBase = base + entrySize * numElements;
     }
 
@@ -104,7 +107,7 @@ public class BinaryTupleParser {
      * Check if the binary tuple contains a null map.
      */
     public boolean hasNullMap() {
-        return entryBase > BinaryTupleSchema.HEADER_SIZE;
+        return entryBase > BinaryTupleCommon.HEADER_SIZE;
     }
 
     /**
@@ -137,8 +140,8 @@ public class BinaryTupleParser {
         }
 
         if (offset == nextOffset && hasNullMap()) {
-            int nullIndex = BinaryTupleSchema.nullOffset(index);
-            byte nullMask = BinaryTupleSchema.nullMask(index);
+            int nullIndex = BinaryTupleCommon.nullOffset(index);
+            byte nullMask = BinaryTupleCommon.nullMask(index);
             if ((buffer.get(nullIndex) & nullMask) != 0) {
                 sink.nextElement(index, 0, 0);
                 return;
@@ -164,8 +167,8 @@ public class BinaryTupleParser {
             }
 
             if (offset == nextOffset && hasNullMap()) {
-                int nullIndex = BinaryTupleSchema.nullOffset(i);
-                byte nullMask = BinaryTupleSchema.nullMask(i);
+                int nullIndex = BinaryTupleCommon.nullOffset(i);
+                byte nullMask = BinaryTupleCommon.nullMask(i);
                 if ((buffer.get(nullIndex) & nullMask) != 0) {
                     sink.nextElement(i, 0, 0);
                     entry += entrySize;
@@ -186,7 +189,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final byte byteValue(int begin, int end) {
+    public final byte byteValue(int begin, int end) {
         switch (end - begin) {
             case 0:
                 return 0;
@@ -204,7 +207,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final short shortValue(int begin, int end) {
+    public final short shortValue(int begin, int end) {
         switch (end - begin) {
             case 0:
                 return 0;
@@ -224,7 +227,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final int intValue(int begin, int end) {
+    public final int intValue(int begin, int end) {
         switch (end - begin) {
             case 0:
                 return 0;
@@ -246,7 +249,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final long longValue(int begin, int end) {
+    public final long longValue(int begin, int end) {
         switch (end - begin) {
             case 0:
                 return 0;
@@ -270,7 +273,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final float floatValue(int begin, int end) {
+    public final float floatValue(int begin, int end) {
         switch (end - begin) {
             case 0:
                 return 0.0F;
@@ -288,7 +291,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final double doubleValue(int begin, int end) {
+    public final double doubleValue(int begin, int end) {
         switch (end - begin) {
             case 0:
                 return 0.0;
@@ -308,7 +311,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final BigInteger numberValue(int begin, int end) {
+    public final BigInteger numberValue(int begin, int end) {
         byte[] bytes;
         int len = end - begin;
         if (buffer.hasArray()) {
@@ -328,7 +331,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final String stringValue(int begin, int end) {
+    public final String stringValue(int begin, int end) {
         byte[] bytes;
         int len = end - begin;
         if (buffer.hasArray()) {
@@ -348,7 +351,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final byte[] bytesValue(int begin, int end) {
+    public final byte[] bytesValue(int begin, int end) {
         byte[] bytes = new byte[end - begin];
         buffer.duplicate().position(begin).limit(end).get(bytes);
         return bytes;
@@ -361,11 +364,11 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final UUID uuidValue(int begin, int end) {
+    public final UUID uuidValue(int begin, int end) {
         int len = end - begin;
-        if (len != NativeTypes.UUID.sizeInBytes()) {
+        if (len != UUID_SIZE) {
             if (len == 0) {
-                return BinaryTupleSchema.DEFAULT_UUID;
+                return BinaryTupleCommon.DEFAULT_UUID;
             }
             throw new BinaryTupleFormatException("Invalid length for a tuple element");
         }
@@ -381,7 +384,7 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final BitSet bitmaskValue(int begin, int end) {
+    public final BitSet bitmaskValue(int begin, int end) {
         return BitSet.valueOf(buffer.duplicate().position(begin).limit(end));
     }
 
@@ -392,11 +395,11 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final LocalDate dateValue(int begin, int end) {
+    public final LocalDate dateValue(int begin, int end) {
         int len = end - begin;
         if (len != 3) {
             if (len == 0) {
-                return BinaryTupleSchema.DEFAULT_DATE;
+                return BinaryTupleCommon.DEFAULT_DATE;
             }
             throw new BinaryTupleFormatException("Invalid length for a tuple element");
         }
@@ -410,11 +413,11 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final LocalTime timeValue(int begin, int end) {
+    public final LocalTime timeValue(int begin, int end) {
         int len = end - begin;
         if (len < 4 || len > 6) {
             if (len == 0) {
-                return BinaryTupleSchema.DEFAULT_TIME;
+                return BinaryTupleCommon.DEFAULT_TIME;
             }
             throw new BinaryTupleFormatException("Invalid length for a tuple element");
         }
@@ -428,11 +431,11 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final LocalDateTime dateTimeValue(int begin, int end) {
+    public final LocalDateTime dateTimeValue(int begin, int end) {
         int len = end - begin;
         if (len < 7 || len > 9) {
             if (len == 0) {
-                return BinaryTupleSchema.DEFAULT_DATE_TIME;
+                return BinaryTupleCommon.DEFAULT_DATE_TIME;
             }
             throw new BinaryTupleFormatException("Invalid length for a tuple element");
         }
@@ -446,11 +449,11 @@ public class BinaryTupleParser {
      * @param end End offset of the element.
      * @return Element value.
      */
-    final Instant timestampValue(int begin, int end) {
+    public final Instant timestampValue(int begin, int end) {
         int len = end - begin;
         if (len != 8 && len != 12) {
             if (len == 0) {
-                return BinaryTupleSchema.DEFAULT_TIMESTAMP;
+                return BinaryTupleCommon.DEFAULT_TIMESTAMP;
             }
             throw new BinaryTupleFormatException("Invalid length for a tuple element");
         }
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleReader.java b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
similarity index 99%
rename from modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleReader.java
rename to modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
index cad39739ca..0b30537b03 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleReader.java
+++ b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.schema;
+package org.apache.ignite.internal.binarytuple;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/BinaryTupleTest.java b/modules/binary-tuple/src/test/java/org/apache/ignite/internal/binarytuple/BinaryTupleTest.java
similarity index 99%
rename from modules/schema/src/test/java/org/apache/ignite/internal/schema/BinaryTupleTest.java
rename to modules/binary-tuple/src/test/java/org/apache/ignite/internal/binarytuple/BinaryTupleTest.java
index 412d191082..76cca3ddf1 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/BinaryTupleTest.java
+++ b/modules/binary-tuple/src/test/java/org/apache/ignite/internal/binarytuple/BinaryTupleTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.schema;
+package org.apache.ignite.internal.binarytuple;
 
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -49,7 +49,7 @@ public class BinaryTupleTest {
         // Header: 1 byte with null map flag.
         // NullMap: 1 byte with first bit set.
         // Offset table: 1 zero byte
-        byte[] bytes = { BinaryTupleSchema.NULLMAP_FLAG, 1, 0 };
+        byte[] bytes = { BinaryTupleCommon.NULLMAP_FLAG, 1, 0 };
 
         var reader = new BinaryTupleReader(1, bytes);
         assertEquals(bytes.length, reader.size());
@@ -87,7 +87,7 @@ public class BinaryTupleTest {
         // Header: 1 byte with null map flag.
         // NullMap: 1 byte with no bit set.
         // Offset table: 1 zero byte
-        byte[] bytes2 = { BinaryTupleSchema.NULLMAP_FLAG, 0, 0 };
+        byte[] bytes2 = { BinaryTupleCommon.NULLMAP_FLAG, 0, 0 };
 
         byte[][] bytesArray = { bytes1, bytes2 };
 
diff --git a/modules/schema/pom.xml b/modules/schema/pom.xml
index b256cb19fc..616b56fc17 100644
--- a/modules/schema/pom.xml
+++ b/modules/schema/pom.xml
@@ -58,6 +58,11 @@
             <artifactId>ignite-extended-api</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-binary-tuple</artifactId>
+        </dependency>
+
         <!-- 3rd party dependencies -->
         <dependency>
             <groupId>org.jetbrains</groupId>
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryConverter.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryConverter.java
index 71bd1123a6..60907b0008 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryConverter.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryConverter.java
@@ -20,6 +20,8 @@ package org.apache.ignite.internal.schema;
 import java.math.BigDecimal;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
+import org.apache.ignite.internal.binarytuple.BinaryTupleParser;
 import org.apache.ignite.internal.schema.row.Row;
 import org.apache.ignite.internal.schema.row.RowAssembler;
 import org.jetbrains.annotations.Nullable;
@@ -116,7 +118,9 @@ public class BinaryConverter {
         }
 
         // Now compose the tuple.
-        BinaryTupleBuilder builder = BinaryTupleBuilder.create(tupleSchema, hasNulls, estimatedValueSize);
+        BinaryTupleBuilder builder = BinaryTupleBuilder.create(
+                tupleSchema.elementCount(), hasNulls, estimatedValueSize);
+
         for (int elementIndex = 0; elementIndex < tupleSchema.elementCount(); elementIndex++) {
             BinaryTupleSchema.Element elt = tupleSchema.element(elementIndex);
             NativeTypeSpec typeSpec = elt.typeSpec;
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTuple.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTuple.java
index 765a0de3ca..db71a86a36 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTuple.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTuple.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.schema;
 
 import java.math.BigDecimal;
 import java.nio.ByteBuffer;
+import org.apache.ignite.internal.binarytuple.BinaryTupleReader;
 import org.apache.ignite.internal.schema.row.InternalTuple;
 
 /**
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleSchema.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleSchema.java
index 6947a274c7..8f1b315c5b 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleSchema.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleSchema.java
@@ -17,41 +17,10 @@
 
 package org.apache.ignite.internal.schema;
 
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.UUID;
-import org.apache.ignite.lang.IgniteInternalException;
-
 /**
  * Description of a binary tuple.
  */
 public class BinaryTupleSchema {
-    /** Size of a tuple header, in bytes. */
-    public static final int HEADER_SIZE = 1;
-
-    /** Mask for size of entries in variable-length offset table. */
-    public static final int VARSIZE_MASK = 0b011;
-
-    /** Flag that indicates null map presence. */
-    public static final int NULLMAP_FLAG = 0b100;
-
-    /** Default value for UUID elements. */
-    public static final UUID DEFAULT_UUID = new UUID(0, 0);
-
-    /** Default value for Date elements (Jan 1st 1 BC). */
-    public static final LocalDate DEFAULT_DATE = LocalDate.of(0, 1, 1);
-
-    /** Default value for Time elements (00:00:00). */
-    public static final LocalTime DEFAULT_TIME = LocalTime.of(0, 0);
-
-    /** Default value for DateTime elements (Jan 1st 1 BC, 00:00:00). */
-    public static final LocalDateTime DEFAULT_DATE_TIME = LocalDateTime.of(0, 1, 1, 0, 0);
-
-    /** Default value for Timestamp elements. */
-    public static final Instant DEFAULT_TIMESTAMP = Instant.EPOCH;
-
     /**
      * Tuple element description used for tuple parsing and building.
      *
@@ -86,6 +55,33 @@ public class BinaryTupleSchema {
 
             this.nullable = nullable;
         }
+
+        /**
+         * Gets the type spec.
+         *
+         * @return Type spec.
+         */
+        public NativeTypeSpec typeSpec() {
+            return typeSpec;
+        }
+
+        /**
+         * Gets the decimal scale.
+         *
+         * @return Decimal scale.
+         */
+        public int decimalScale() {
+            return decimalScale;
+        }
+
+        /**
+         * Gets the nullable flag.
+         *
+         * @return Nullable flag.
+         */
+        public boolean nullable() {
+            return nullable;
+        }
     }
 
     /** Tuple schema corresponding to a set of row columns going in a contiguous range. */
@@ -249,65 +245,6 @@ public class BinaryTupleSchema {
         return new SparseRowSchema(elements, columns.clone(), hasNullables);
     }
 
-    /**
-     * Calculates flags for a given size of variable-length area.
-     *
-     * @param size Variable-length area size.
-     * @return Flags value.
-     */
-    public static byte valueSizeToFlags(long size) {
-        if (size <= 0xff) {
-            return 0b00;
-        }
-        if (size <= 0xffff) {
-            return 0b01;
-        }
-        if (size <= Integer.MAX_VALUE) {
-            return 0b10;
-        }
-        throw new IgniteInternalException("Too big binary tuple size");
-    }
-
-    /**
-     * Calculates the size of entry in variable-length offset table for given flags.
-     *
-     * @param flags Flags value.
-     * @return Size of entry in variable-length offset table.
-     */
-    public static int flagsToEntrySize(byte flags) {
-        return 1 << (flags & VARSIZE_MASK);
-    }
-
-    /**
-     * Calculates the null map size.
-     *
-     * @param numElements Number of tuple elements.
-     * @return Null map size in bytes.
-     */
-    public static int nullMapSize(int numElements) {
-        return (numElements + 7) / 8;
-    }
-
-    /**
-     * Returns offset of the byte that contains null-bit of a given tuple element.
-     *
-     * @param index Tuple element index.
-     * @return Offset of the required byte relative to the tuple start.
-     */
-    public static int nullOffset(int index) {
-        return HEADER_SIZE + index / 8;
-    }
-
-    /**
-     * Returns a null-bit mask corresponding to a given tuple element.
-     *
-     * @param index Tuple element index.
-     * @return Mask to extract the required null-bit.
-     */
-    public static byte nullMask(int index) {
-        return (byte) (1 << (index % 8));
-    }
-
     /**
      * Returns the number of elements in the tuple.
      */
diff --git a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/AbstractMvTableStorageTest.java b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/AbstractMvTableStorageTest.java
index 442b8a4a7d..64ac10fbb1 100644
--- a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/AbstractMvTableStorageTest.java
+++ b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/AbstractMvTableStorageTest.java
@@ -34,8 +34,8 @@ import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
 import org.apache.ignite.configuration.NamedListView;
 import org.apache.ignite.configuration.schemas.table.TableIndexView;
+import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
 import org.apache.ignite.internal.schema.BinaryTuple;
-import org.apache.ignite.internal.schema.BinaryTupleBuilder;
 import org.apache.ignite.internal.schema.BinaryTupleSchema;
 import org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
 import org.apache.ignite.internal.schema.NativeTypes;
@@ -197,7 +197,7 @@ public abstract class AbstractMvTableStorageTest extends BaseMvStoragesTest {
                 new Element(NativeTypes.INT32, false)
         });
 
-        ByteBuffer buffer = BinaryTupleBuilder.create(schema)
+        ByteBuffer buffer = BinaryTupleBuilder.create(schema.elementCount(), schema.hasNullableElements())
                 .appendInt(1)
                 .appendInt(2)
                 .build();
diff --git a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/impl/BinaryTupleRowSerializer.java b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/impl/BinaryTupleRowSerializer.java
index 39d62f7fac..708342dbd9 100644
--- a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/impl/BinaryTupleRowSerializer.java
+++ b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/impl/BinaryTupleRowSerializer.java
@@ -19,13 +19,23 @@ package org.apache.ignite.internal.storage.index.impl;
 
 import static java.util.stream.Collectors.toUnmodifiableList;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.BitSet;
 import java.util.List;
+import java.util.UUID;
+import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
 import org.apache.ignite.internal.schema.BinaryTuple;
-import org.apache.ignite.internal.schema.BinaryTupleBuilder;
 import org.apache.ignite.internal.schema.BinaryTupleSchema;
 import org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
+import org.apache.ignite.internal.schema.InvalidTypeException;
 import org.apache.ignite.internal.schema.NativeType;
 import org.apache.ignite.internal.schema.NativeTypeSpec;
+import org.apache.ignite.internal.schema.SchemaMismatchException;
 import org.apache.ignite.internal.storage.RowId;
 import org.apache.ignite.internal.storage.index.HashIndexDescriptor;
 import org.apache.ignite.internal.storage.index.IndexRow;
@@ -100,10 +110,11 @@ public class BinaryTupleRowSerializer {
 
         BinaryTupleSchema prefixSchema = BinaryTupleSchema.create(prefixElements);
 
-        BinaryTupleBuilder builder = BinaryTupleBuilder.create(prefixSchema);
+        BinaryTupleBuilder builder = BinaryTupleBuilder.create(
+                prefixSchema.elementCount(), prefixSchema.hasNullableElements());
 
         for (Object value : prefixColumnValues) {
-            builder.appendValue(prefixSchema, value);
+            appendValue(builder, prefixSchema, value);
         }
 
         return new BinaryTuple(prefixSchema, builder.build());
@@ -127,4 +138,62 @@ public class BinaryTupleRowSerializer {
 
         return result;
     }
+
+    /**
+     * Append a value for the current element.
+     *
+     * @param builder Builder.
+     * @param schema Tuple schema.
+     * @param value Element value.
+     * @return Builder for chaining.
+     */
+    private static BinaryTupleBuilder appendValue(BinaryTupleBuilder builder, BinaryTupleSchema schema, Object value) {
+        BinaryTupleSchema.Element element = schema.element(builder.elementIndex());
+
+        if (value == null) {
+            if (!element.nullable()) {
+                throw new SchemaMismatchException("NULL value for non-nullable column in binary tuple builder.");
+            }
+            return builder.appendNull();
+        }
+
+        switch (element.typeSpec()) {
+            case INT8:
+                return builder.appendByte((byte) value);
+            case INT16:
+                return builder.appendShort((short) value);
+            case INT32:
+                return builder.appendInt((int) value);
+            case INT64:
+                return builder.appendLong((long) value);
+            case FLOAT:
+                return builder.appendFloat((float) value);
+            case DOUBLE:
+                return builder.appendDouble((double) value);
+            case NUMBER:
+                return builder.appendNumberNotNull((BigInteger) value);
+            case DECIMAL:
+                return builder.appendDecimalNotNull((BigDecimal) value);
+            case UUID:
+                return builder.appendUuidNotNull((UUID) value);
+            case BYTES:
+                return builder.appendBytesNotNull((byte[]) value);
+            case STRING:
+                return builder.appendStringNotNull((String) value);
+            case BITMASK:
+                return builder.appendBitmaskNotNull((BitSet) value);
+            case DATE:
+                return builder.appendDateNotNull((LocalDate) value);
+            case TIME:
+                return builder.appendTimeNotNull((LocalTime) value);
+            case DATETIME:
+                return builder.appendDateTimeNotNull((LocalDateTime) value);
+            case TIMESTAMP:
+                return builder.appendTimestampNotNull((Instant) value);
+            default:
+                break;
+        }
+
+        throw new InvalidTypeException("Unexpected type value: " + element.typeSpec());
+    }
 }
diff --git a/parent/pom.xml b/parent/pom.xml
index 7eadaa8ff7..aeb562150d 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -241,6 +241,12 @@
                 <version>${project.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>org.apache.ignite</groupId>
+                <artifactId>ignite-binary-tuple</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
             <dependency>
                 <groupId>org.apache.ignite</groupId>
                 <artifactId>ignite-bytecode</artifactId>
@@ -301,12 +307,6 @@
                 <version>${project.version}</version>
             </dependency>
 
-            <dependency>
-                <groupId>org.apache.ignite</groupId>
-                <artifactId>ignite-table</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-
             <dependency>
                 <groupId>org.apache.ignite</groupId>
                 <artifactId>ignite-metastorage</artifactId>
diff --git a/pom.xml b/pom.xml
index cbb6461bc4..2f49d069b8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,6 +42,7 @@
         <module>modules/affinity</module>
         <module>modules/api</module>
         <module>modules/baseline</module>
+        <module>modules/binary-tuple</module>
         <module>modules/bytecode</module>
         <module>modules/cli</module>
         <module>modules/cli-common</module>