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 2cb73723e41 IGNITE-24976 Sql. Optimize sql row serialization (#5536)
2cb73723e41 is described below
commit 2cb73723e4149b252fe0b4dded53ef511c71a46f
Author: Andrew V. Mashenkov <[email protected]>
AuthorDate: Mon Apr 7 17:32:00 2025 +0300
IGNITE-24976 Sql. Optimize sql row serialization (#5536)
---
.../internal/binarytuple/BinaryTupleParser.java | 2 +-
.../internal/binarytuple/BinaryTupleReader.java | 15 +++
.../internal/benchmark/UpgradeRowBenchmark.java | 113 +++++++++++++++++++++
.../ignite/internal/schema/BinaryRowConverter.java | 69 +++++++++++++
.../apache/ignite/internal/schema/BinaryTuple.java | 9 +-
.../{BinaryTuple.java => InternalTupleEx.java} | 28 ++---
.../schema/registry/UpgradingRowAdapter.java | 20 +++-
.../org/apache/ignite/internal/schema/row/Row.java | 4 +-
.../apache/ignite/internal/schema/row/RowImpl.java | 10 +-
.../exec/ProjectedTableRowConverterImpl.java | 27 ++---
.../engine/exec/TableRowConverterFactoryImpl.java | 15 +--
.../internal/sql/engine/exec/VirtualColumn.java | 10 +-
...ectedTuple.java => ExtendedProjectedTuple.java} | 70 ++++++++-----
.../util/FieldDeserializingProjectedTuple.java | 6 +-
...wareProjectedTuple.java => ProjectedTuple.java} | 62 +++++------
.../exec/ProjectedTableRowConverterSelfTest.java | 5 +-
.../sql/engine/util/ProjectedTupleTest.java | 50 ++++++++-
17 files changed, 384 insertions(+), 131 deletions(-)
diff --git
a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
index cd28909643e..7f1985d1fd0 100644
---
a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
+++
b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
@@ -67,7 +67,7 @@ public class BinaryTupleParser {
private final int valueBase;
/** Binary tuple. */
- private final ByteBuffer buffer;
+ protected final ByteBuffer buffer;
/**
* Constructor.
diff --git
a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
index a40f0b25c9c..db533a4a02b 100644
---
a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
+++
b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleReader.java
@@ -395,4 +395,19 @@ public class BinaryTupleReader extends BinaryTupleParser
implements BinaryTupleP
public void seek(int index) {
fetch(index, this);
}
+
+ /**
+ * Copies raw value of the specified element to the builder.
+ *
+ * @param builder Builder to copy value to.
+ * @param index Index of the element.
+ */
+ protected void copyRawValue(BinaryTupleBuilder builder, int index) {
+ seek(index);
+ if (begin == end) {
+ builder.appendNull();
+ } else {
+ builder.appendElementBytes(buffer, begin, end - begin);
+ }
+ }
}
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/benchmark/UpgradeRowBenchmark.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/benchmark/UpgradeRowBenchmark.java
new file mode 100644
index 00000000000..6b86b0dafae
--- /dev/null
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/benchmark/UpgradeRowBenchmark.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.benchmark;
+
+import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import org.apache.ignite.sql.IgniteSql;
+import org.apache.ignite.sql.ResultSet;
+import org.apache.ignite.sql.SqlRow;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * Benchmark that runs sql queries via embedded client on clusters of
different size.
+ */
+@State(Scope.Benchmark)
+@Fork(1)
+@Threads(1)
+@Warmup(iterations = 10, time = 2)
+@Measurement(iterations = 20, time = 2)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@SuppressWarnings({"WeakerAccess", "unused"})
+public class UpgradeRowBenchmark extends AbstractMultiNodeBenchmark {
+ private static final int TABLE_SIZE = 300_000;
+
+ private IgniteSql sql;
+
+ @Param({"1"})
+ private int clusterSize;
+
+ /** Fills the table with data. */
+ @Setup
+ public void setUp() throws IOException {
+ populateTable(TABLE_NAME, TABLE_SIZE, 1_000);
+
+ sql = publicIgnite.sql();
+
+ try (ResultSet<SqlRow> rs = sql.execute(null, format("ALTER TABLE {}
ADD COLUMN new_col INT DEFAULT 42", TABLE_NAME));) {
+ while (rs.hasNext()) {
+ rs.next();
+ }
+ }
+ }
+
+ /** Benchmark that measures performance of `SELECT *` query over entire
table. */
+ @Benchmark
+ public void selectAll(Blackhole bh) {
+ try (var rs = sql.execute(null, "SELECT * FROM usertable")) {
+ while (rs.hasNext()) {
+ bh.consume(rs.next());
+ }
+ }
+ }
+
+ /** Benchmark that measures performance of `SELECT` query with projection
over entire table. */
+ @Benchmark
+ public void selectAllProjected(Blackhole bh) {
+ try (var rs = sql.execute(null, "SELECT field1, field2, field3 FROM
usertable")) {
+ while (rs.hasNext()) {
+ bh.consume(rs.next());
+ }
+ }
+ }
+
+ /**
+ * Benchmark's entry point.
+ */
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(".*" + UpgradeRowBenchmark.class.getSimpleName() +
".*")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+ @Override
+ protected int nodes() {
+ return clusterSize;
+ }
+}
diff --git
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryRowConverter.java
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryRowConverter.java
index 8ea03495b08..3821c957cf2 100644
---
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryRowConverter.java
+++
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryRowConverter.java
@@ -28,6 +28,7 @@ import
org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
import org.apache.ignite.internal.binarytuple.BinaryTupleFormatException;
import org.apache.ignite.internal.binarytuple.BinaryTupleParser;
import org.apache.ignite.internal.binarytuple.BinaryTupleParser.Sink;
+import org.apache.ignite.internal.lang.InternalTuple;
import org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
@@ -149,6 +150,74 @@ public class BinaryRowConverter implements
ColumnsExtractor {
throw new InvalidTypeException("Unexpected type value: " +
element.typeSpec());
}
+ /**
+ * Helper method that copy column value from given tuple to the binary
tuple builder.
+ *
+ * @param delegate Source tuple to copy value from.
+ * @param builder Binary tuple builder to copy value to.
+ * @param element Binary schema element of the source tuple.
+ * @param col Column index in the delegate tuple.
+ */
+ public static void copyColumnValue(InternalTuple delegate,
BinaryTupleBuilder builder, Element element, int col) {
+ if (delegate.hasNullValue(col)) {
+ builder.appendNull();
+
+ return;
+ }
+
+ switch (element.typeSpec()) {
+ case BOOLEAN:
+ builder.appendBoolean(delegate.booleanValue(col));
+ return;
+ case INT8:
+ builder.appendByte(delegate.byteValue(col));
+ return;
+ case INT16:
+ builder.appendShort(delegate.shortValue(col));
+ return;
+ case INT32:
+ builder.appendInt(delegate.intValue(col));
+ return;
+ case INT64:
+ builder.appendLong(delegate.longValue(col));
+ return;
+ case FLOAT:
+ builder.appendFloat(delegate.floatValue(col));
+ return;
+ case DOUBLE:
+ builder.appendDouble(delegate.doubleValue(col));
+ return;
+ case DECIMAL:
+ builder.appendDecimalNotNull(delegate.decimalValue(col,
element.decimalScale()), element.decimalScale());
+ return;
+ case UUID:
+ builder.appendUuidNotNull(delegate.uuidValue(col));
+ return;
+ case BYTES:
+ builder.appendBytesNotNull(delegate.bytesValue(col));
+ return;
+ case STRING:
+ builder.appendStringNotNull(delegate.stringValue(col));
+ return;
+ case DATE:
+ builder.appendDateNotNull(delegate.dateValue(col));
+ return;
+ case TIME:
+ builder.appendTimeNotNull(delegate.timeValue(col));
+ return;
+ case DATETIME:
+ builder.appendDateTimeNotNull(delegate.dateTimeValue(col));
+ return;
+ case TIMESTAMP:
+ builder.appendTimestampNotNull(delegate.timestampValue(col));
+ return;
+ default:
+ break;
+ }
+
+ throw new InvalidTypeException("Unexpected type value: " +
element.typeSpec());
+ }
+
/**
* Returns destination tuple schema.
*/
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 2d8da1d4484..688138cca30 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
@@ -18,14 +18,14 @@
package org.apache.ignite.internal.schema;
import java.nio.ByteBuffer;
+import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
import org.apache.ignite.internal.binarytuple.BinaryTupleReader;
-import org.apache.ignite.internal.lang.InternalTuple;
/**
* Utility for access to binary tuple elements as typed values and with schema
knowledge that allows to read
* elements as objects.
*/
-public class BinaryTuple extends BinaryTupleReader implements InternalTuple {
+public class BinaryTuple extends BinaryTupleReader implements InternalTupleEx {
/**
* Constructor.
*
@@ -45,4 +45,9 @@ public class BinaryTuple extends BinaryTupleReader implements
InternalTuple {
public BinaryTuple(int elementCount, ByteBuffer buffer) {
super(elementCount, buffer);
}
+
+ @Override
+ public void copyValue(BinaryTupleBuilder builder, int columnIndex) {
+ copyRawValue(builder, columnIndex);
+ }
}
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/InternalTupleEx.java
similarity index 55%
copy from
modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTuple.java
copy to
modules/schema/src/main/java/org/apache/ignite/internal/schema/InternalTupleEx.java
index 2d8da1d4484..335524c5d46 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/InternalTupleEx.java
@@ -17,32 +17,18 @@
package org.apache.ignite.internal.schema;
-import java.nio.ByteBuffer;
-import org.apache.ignite.internal.binarytuple.BinaryTupleReader;
+import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
import org.apache.ignite.internal.lang.InternalTuple;
/**
- * Utility for access to binary tuple elements as typed values and with schema
knowledge that allows to read
- * elements as objects.
+ * Interface that provides a method to copy value (maybe raw) of the given
column directly into a tuple builder.
*/
-public class BinaryTuple extends BinaryTupleReader implements InternalTuple {
+public interface InternalTupleEx extends InternalTuple {
/**
- * Constructor.
+ * Copy value of the given column.
*
- * @param elementCount Number of tuple elements.
- * @param bytes Binary tuple.
+ * @param builder Binary tuple builder to copy value to.
+ * @param columnIndex Column index.
*/
- public BinaryTuple(int elementCount, byte[] bytes) {
- super(elementCount, bytes);
- }
-
- /**
- * Constructor.
- *
- * @param elementCount Number of tuple elements.
- * @param buffer Buffer with a binary tuple.
- */
- public BinaryTuple(int elementCount, ByteBuffer buffer) {
- super(elementCount, buffer);
- }
+ void copyValue(BinaryTupleBuilder builder, int columnIndex);
}
diff --git
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/registry/UpgradingRowAdapter.java
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/registry/UpgradingRowAdapter.java
index 58026797b57..1e8afe9cd8d 100644
---
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/registry/UpgradingRowAdapter.java
+++
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/registry/UpgradingRowAdapter.java
@@ -31,7 +31,6 @@ import
org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
import org.apache.ignite.internal.schema.BinaryRowConverter;
import org.apache.ignite.internal.schema.BinaryTuple;
import org.apache.ignite.internal.schema.BinaryTupleSchema;
-import org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
import org.apache.ignite.internal.schema.Column;
import org.apache.ignite.internal.schema.InvalidTypeException;
import org.apache.ignite.internal.schema.SchemaDescriptor;
@@ -458,14 +457,25 @@ public class UpgradingRowAdapter implements Row {
var builder = new BinaryTupleBuilder(size);
for (int col = 0; col < size; col++) {
- Element element = newBinaryTupleSchema.element(col);
-
- BinaryRowConverter.appendValue(builder, element, value(col));
+ copyValue(builder, col);
}
return new BinaryTuple(size, builder.build()).byteBuffer();
}
+ /** {@inheritDoc} */
+ @Override
+ public void copyValue(BinaryTupleBuilder builder, int colIdx) {
+ int mappedId = mapColumn(colIdx);
+
+ if (mappedId < 0) {
+ Column column = mapper.mappedColumn(colIdx);
+ BinaryRowConverter.appendValue(builder,
newBinaryTupleSchema.element(colIdx), column.defaultValue());
+ } else {
+ row.copyValue(builder, mappedId);
+ }
+ }
+
/** {@inheritDoc} */
@Override
public int tupleSliceLength() {
@@ -478,7 +488,7 @@ public class UpgradingRowAdapter implements Row {
throw new UnsupportedOperationException("Underlying binary can't be
accessed directly.");
}
- private void ensureTypeConversionAllowed(ColumnType from, ColumnType to)
throws InvalidTypeException {
+ private static void ensureTypeConversionAllowed(ColumnType from,
ColumnType to) throws InvalidTypeException {
if (!isSupportedColumnTypeChange(from, to)) {
throw new SchemaException(format("Type conversion is not allowed:
{} -> {}", from, to));
}
diff --git
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/Row.java
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/Row.java
index 34894a1fd63..67e09fcdd15 100644
---
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/Row.java
+++
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/Row.java
@@ -19,17 +19,17 @@ package org.apache.ignite.internal.schema.row;
import java.math.BigDecimal;
import org.apache.ignite.internal.binarytuple.BinaryTupleContainer;
-import org.apache.ignite.internal.lang.InternalTuple;
import org.apache.ignite.internal.schema.BinaryRow;
import org.apache.ignite.internal.schema.BinaryRowEx;
import org.apache.ignite.internal.schema.BinaryTupleSchema;
+import org.apache.ignite.internal.schema.InternalTupleEx;
import org.apache.ignite.internal.schema.SchemaAware;
import org.apache.ignite.internal.schema.SchemaDescriptor;
/**
* Schema-aware row interface.
*/
-public interface Row extends SchemaAware, BinaryRowEx, InternalTuple,
BinaryTupleContainer {
+public interface Row extends SchemaAware, BinaryRowEx, InternalTupleEx,
BinaryTupleContainer {
/**
* Creates a row from a given {@code BinaryRow}.
*
diff --git
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowImpl.java
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowImpl.java
index 592065f6fcf..181c256d3cc 100644
---
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowImpl.java
+++
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowImpl.java
@@ -19,9 +19,9 @@ package org.apache.ignite.internal.schema.row;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
+import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
import org.apache.ignite.internal.binarytuple.BinaryTupleReader;
import org.apache.ignite.internal.schema.BinaryRow;
-import org.apache.ignite.internal.schema.BinaryRowEx;
import org.apache.ignite.internal.schema.BinaryTuple;
import org.apache.ignite.internal.schema.BinaryTupleSchema;
import org.apache.ignite.internal.schema.Column;
@@ -38,7 +38,7 @@ import org.jetbrains.annotations.Nullable;
*
* <p>When a non-boxed primitive is read from a null column value, it is
converted to the primitive type default value.
*/
-public class RowImpl extends BinaryTupleReader implements Row, BinaryRowEx {
+public class RowImpl extends BinaryTupleReader implements Row {
/** Schema descriptor. */
private final SchemaDescriptor schema;
@@ -135,6 +135,12 @@ public class RowImpl extends BinaryTupleReader implements
Row, BinaryRowEx {
return new BinaryTuple(binaryTupleSchema.elementCount(),
row.tupleSlice());
}
+ /** {@inheritDoc} */
+ @Override
+ public void copyValue(BinaryTupleBuilder builder, int columnIndex) {
+ copyRawValue(builder, columnIndex);
+ }
+
/** {@inheritDoc} */
@Override
public boolean equals(Object o) {
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ProjectedTableRowConverterImpl.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ProjectedTableRowConverterImpl.java
index 99a19bdacb6..d0b99f578a2 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ProjectedTableRowConverterImpl.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ProjectedTableRowConverterImpl.java
@@ -17,19 +17,18 @@
package org.apache.ignite.internal.sql.engine.exec;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.util.BitSet;
-import java.util.List;
import org.apache.ignite.internal.lang.InternalTuple;
import org.apache.ignite.internal.schema.BinaryRow;
import org.apache.ignite.internal.schema.BinaryTuple;
-import org.apache.ignite.internal.schema.BinaryTupleSchema;
import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.InternalTupleEx;
import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.schema.SchemaRegistry;
import org.apache.ignite.internal.sql.engine.exec.RowHandler.RowFactory;
-import
org.apache.ignite.internal.sql.engine.util.ExtendedFieldDeserializingProjectedTuple;
-import
org.apache.ignite.internal.sql.engine.util.FieldDeserializingProjectedTuple;
-import org.apache.ignite.internal.sql.engine.util.FormatAwareProjectedTuple;
+import org.apache.ignite.internal.sql.engine.util.ExtendedProjectedTuple;
+import org.apache.ignite.internal.sql.engine.util.ProjectedTuple;
/**
* Converts rows to execution engine representation.
@@ -40,21 +39,17 @@ public class ProjectedTableRowConverterImpl extends
TableRowConverterImpl {
*/
private final int[] requiredColumnsMapping;
- private final BinaryTupleSchema fullTupleSchema;
-
- private final List<VirtualColumn> virtualColumns;
+ private final Int2ObjectMap<VirtualColumn> virtualColumns;
/** Constructor. */
ProjectedTableRowConverterImpl(
SchemaRegistry schemaRegistry,
- BinaryTupleSchema fullTupleSchema,
SchemaDescriptor schemaDescriptor,
BitSet requiredColumns,
- List<VirtualColumn> extraColumns
+ Int2ObjectMap<VirtualColumn> extraColumns
) {
super(schemaRegistry, schemaDescriptor);
- this.fullTupleSchema = fullTupleSchema;
this.virtualColumns = extraColumns;
int size = requiredColumns.cardinality();
@@ -68,7 +63,7 @@ public class ProjectedTableRowConverterImpl extends
TableRowConverterImpl {
}
}
- for (VirtualColumn col : extraColumns) {
+ for (VirtualColumn col : extraColumns.values()) {
requiredColumnsMapping[requiredIndex++] = col.columnIndex();
}
}
@@ -78,16 +73,14 @@ public class ProjectedTableRowConverterImpl extends
TableRowConverterImpl {
InternalTuple tuple;
boolean rowSchemaMatches = tableRow.schemaVersion() ==
schemaDescriptor.version();
- InternalTuple tableTuple = rowSchemaMatches
+ InternalTupleEx tableTuple = rowSchemaMatches
? new BinaryTuple(schemaDescriptor.length(),
tableRow.tupleSlice())
: schemaRegistry.resolve(tableRow, schemaDescriptor);
if (!virtualColumns.isEmpty()) {
- tuple = new
ExtendedFieldDeserializingProjectedTuple(fullTupleSchema, tableTuple,
requiredColumnsMapping, virtualColumns);
- } else if (rowSchemaMatches) {
- tuple = new FormatAwareProjectedTuple(tableTuple,
requiredColumnsMapping);
+ tuple = new ExtendedProjectedTuple(tableTuple,
requiredColumnsMapping, virtualColumns);
} else {
- tuple = new FieldDeserializingProjectedTuple(fullTupleSchema,
tableTuple, requiredColumnsMapping);
+ tuple = new ProjectedTuple(tableTuple, requiredColumnsMapping);
}
return factory.create(tuple);
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/TableRowConverterFactoryImpl.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/TableRowConverterFactoryImpl.java
index 1cac952417d..f187a47a049 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/TableRowConverterFactoryImpl.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/TableRowConverterFactoryImpl.java
@@ -17,10 +17,10 @@
package org.apache.ignite.internal.sql.engine.exec;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import java.util.BitSet;
-import java.util.List;
import java.util.function.IntFunction;
-import org.apache.ignite.internal.schema.BinaryTupleSchema;
import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.schema.SchemaRegistry;
import org.apache.ignite.internal.sql.engine.schema.ColumnDescriptor;
@@ -35,7 +35,6 @@ import org.jetbrains.annotations.Nullable;
public class TableRowConverterFactoryImpl implements TableRowConverterFactory {
private final SchemaRegistry schemaRegistry;
private final SchemaDescriptor schemaDescriptor;
- private final BinaryTupleSchema fullTupleSchema;
private final TableRowConverter fullRowConverter;
private final BitSet tableColumnSet;
private IntFunction<VirtualColumn> virtualColumnFactory;
@@ -56,7 +55,6 @@ public class TableRowConverterFactoryImpl implements
TableRowConverterFactory {
) {
this.schemaRegistry = schemaRegistry;
this.schemaDescriptor = schemaDescriptor;
- this.fullTupleSchema =
BinaryTupleSchema.createRowSchema(schemaDescriptor);
fullRowConverter = new TableRowConverterImpl(
schemaRegistry,
@@ -99,10 +97,15 @@ public class TableRowConverterFactoryImpl implements
TableRowConverterFactory {
return new ProjectedTableRowConverterImpl(
schemaRegistry,
- fullTupleSchema,
schemaDescriptor,
requiredColumns,
- requireVirtualColumn ?
List.of(virtualColumnFactory.apply(partId)) : List.of()
+ requireVirtualColumn ? createVirtualColumns(partId) :
Int2ObjectMaps.emptyMap()
);
}
+
+ private Int2ObjectMap<VirtualColumn> createVirtualColumns(int partId) {
+ VirtualColumn column = virtualColumnFactory.apply(partId);
+
+ return Int2ObjectMaps.singleton(column.columnIndex(), column);
+ }
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/VirtualColumn.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/VirtualColumn.java
index fb643469b1b..be1d2add033 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/VirtualColumn.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/VirtualColumn.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.sql.engine.exec;
+import org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
import org.apache.ignite.internal.tostring.IgniteToStringExclude;
import org.apache.ignite.internal.tostring.S;
import org.apache.ignite.internal.type.NativeType;
@@ -26,15 +27,16 @@ import org.apache.ignite.internal.type.NativeType;
*/
public class VirtualColumn {
private final int columnIndex;
- private final NativeType type;
+ private final Element type;
private final boolean nullable;
@IgniteToStringExclude
private final Object value;
- VirtualColumn(int columnIndex, NativeType type, boolean nullable, Object
value) {
+ /** Creates a new virtual column. */
+ public VirtualColumn(int columnIndex, NativeType type, boolean nullable,
Object value) {
this.columnIndex = columnIndex;
this.value = value;
- this.type = type;
+ this.type = new Element(type, nullable);
this.nullable = nullable;
}
@@ -42,7 +44,7 @@ public class VirtualColumn {
return columnIndex;
}
- public NativeType type() {
+ public Element schemaType() {
return type;
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/ExtendedFieldDeserializingProjectedTuple.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/ExtendedProjectedTuple.java
similarity index 79%
rename from
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/ExtendedFieldDeserializingProjectedTuple.java
rename to
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/ExtendedProjectedTuple.java
index 6529e5102f1..20d37b70478 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/ExtendedFieldDeserializingProjectedTuple.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/ExtendedProjectedTuple.java
@@ -18,79 +18,95 @@
package org.apache.ignite.internal.sql.engine.util;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
-import java.util.List;
import java.util.UUID;
import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
-import org.apache.ignite.internal.lang.InternalTuple;
+import org.apache.ignite.internal.binarytuple.BinaryTupleParser.Sink;
import org.apache.ignite.internal.schema.BinaryRowConverter;
import org.apache.ignite.internal.schema.BinaryTuple;
-import org.apache.ignite.internal.schema.BinaryTupleSchema;
-import org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
+import org.apache.ignite.internal.schema.InternalTupleEx;
import org.apache.ignite.internal.sql.engine.exec.VirtualColumn;
/**
- * A projected tuple that enriches {@link FieldDeserializingProjectedTuple}
with extra columns.
+ * A projected tuple that enriches {@link ProjectedTuple} with extra columns.
*
* <p>Not thread safe!
*
- * @see FieldDeserializingProjectedTuple
+ * @see ProjectedTuple
*/
-public class ExtendedFieldDeserializingProjectedTuple extends
FieldDeserializingProjectedTuple {
+public class ExtendedProjectedTuple extends ProjectedTuple {
- private final Int2ObjectMap<VirtualColumn> extraColumns;
+ private Int2ObjectMap<VirtualColumn> extraColumns;
/**
* Constructor.
*
- * @param schema A schema of the original tuple (represented by delegate).
Used to read content of the delegate to build a
- * proper byte buffer which content satisfying the schema with
regard to given projection.
* @param delegate An original tuple to create projection from.
* @param projection A projection. That is, desired order of fields in
original tuple. In that projection, index of the array is
* an index of field in resulting projection, and an element of
the array at that index is an index of column in original
* tuple.
* @param extraColumns Extra columns.
*/
- public ExtendedFieldDeserializingProjectedTuple(BinaryTupleSchema schema,
InternalTuple delegate, int[] projection,
- List<VirtualColumn> extraColumns) {
- super(schema, delegate, projection);
+ public ExtendedProjectedTuple(InternalTupleEx delegate, int[] projection,
+ Int2ObjectMap<VirtualColumn> extraColumns) {
+ super(delegate, projection);
- this.extraColumns = new Int2ObjectOpenHashMap<>(extraColumns.size());
-
- extraColumns.forEach(c -> this.extraColumns.put(c.columnIndex(), c));
+ this.extraColumns = extraColumns;
}
@Override
protected void normalize() {
- var builder = new BinaryTupleBuilder(projection.length, 32, false);
+ int estimatedValueSize = 32;
+
+ if (delegate instanceof BinaryTuple) {
+ // Estimate total data size.
+ var stats = new Sink() {
+ int estimatedValueSize = 0;
+
+ @Override
+ public void nextElement(int index, int begin, int end) {
+ estimatedValueSize += end - begin;
+ }
+ };
+
+
+ for (int columnIndex : projection) {
+ if (extraColumns.containsKey(columnIndex)) {
+ stats.estimatedValueSize += 8;
+ continue;
+ }
+ ((BinaryTuple) delegate).fetch(columnIndex, stats);
+ }
+ estimatedValueSize = stats.estimatedValueSize;
+ }
+
+ var builder = new BinaryTupleBuilder(projection.length,
estimatedValueSize, false);
var newProjection = new int[projection.length];
+ assert delegate instanceof InternalTupleEx;
+ InternalTupleEx delegate0 = (InternalTupleEx) delegate;
+
for (int i = 0; i < projection.length; i++) {
int col = projection[i];
-
newProjection[i] = i;
if (extraColumns.containsKey(col)) {
- VirtualColumn column = extraColumns.get(col);
-
- BinaryRowConverter.appendValue(builder, new
Element(column.type(), true), column.value());
-
+ VirtualColumn virtualColumn = extraColumns.get(col);
+ BinaryRowConverter.appendValue(builder,
virtualColumn.schemaType(), virtualColumn.value());
continue;
}
- Element element = schema.element(col);
-
- BinaryRowConverter.appendValue(builder, element,
schema.value(delegate, col));
+ delegate0.copyValue(builder, col);
}
delegate = new BinaryTuple(projection.length, builder.build());
projection = newProjection;
- extraColumns.clear();
+ extraColumns = Int2ObjectMaps.emptyMap();
}
private boolean isExtraColumn(int col) {
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/FieldDeserializingProjectedTuple.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/FieldDeserializingProjectedTuple.java
index 1bcd63b6e03..115858f6c24 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/FieldDeserializingProjectedTuple.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/FieldDeserializingProjectedTuple.java
@@ -62,11 +62,11 @@ public class FieldDeserializingProjectedTuple extends
AbstractProjectedTuple {
for (int i = 0; i < projection.length; i++) {
int col = projection[i];
- newProjection[i] = i;
-
Element element = schema.element(col);
- BinaryRowConverter.appendValue(builder, element,
schema.value(delegate, col));
+ BinaryRowConverter.copyColumnValue(delegate, builder, element,
col);
+
+ newProjection[i] = i;
}
delegate = new BinaryTuple(projection.length, builder.build());
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/FormatAwareProjectedTuple.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/ProjectedTuple.java
similarity index 55%
rename from
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/FormatAwareProjectedTuple.java
rename to
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/ProjectedTuple.java
index 5e6b24ea4ef..67e38bd09c7 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/FormatAwareProjectedTuple.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/ProjectedTuple.java
@@ -17,26 +17,19 @@
package org.apache.ignite.internal.sql.engine.util;
-import java.nio.ByteBuffer;
import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
-import org.apache.ignite.internal.binarytuple.BinaryTupleParser;
import org.apache.ignite.internal.binarytuple.BinaryTupleParser.Sink;
-import org.apache.ignite.internal.lang.InternalTuple;
import org.apache.ignite.internal.schema.BinaryTuple;
+import org.apache.ignite.internal.schema.InternalTupleEx;
/**
- * A projected tuple that aware of the format of delegate.
- *
- * <p>That is, the format of delegate is known to be Binary Tuple, thus it's
possible to avoid unnecessary
- * (de-)serialization during tuple normalization.
- *
- * <p>It's up to the caller to get sure that provided tuple respect the format.
+ * A projected tuple wrapper that is best effort to avoiding unnecessary
(de-)serialization during tuple normalization.
*
* <p>Not thread safe!
*
* @see AbstractProjectedTuple
*/
-public class FormatAwareProjectedTuple extends AbstractProjectedTuple {
+public class ProjectedTuple extends AbstractProjectedTuple {
/**
* Constructor.
*
@@ -45,46 +38,45 @@ public class FormatAwareProjectedTuple extends
AbstractProjectedTuple {
* an index of field in resulting projection, and an element of
the array at that index is an index of column in original
* tuple.
*/
- public FormatAwareProjectedTuple(InternalTuple delegate, int[] projection)
{
+ public ProjectedTuple(InternalTupleEx delegate, int[] projection) {
super(delegate, projection);
}
@Override
protected void normalize() {
- int[] newProjection = new int[projection.length];
- ByteBuffer tupleBuffer = delegate.byteBuffer();
+ BinaryTupleBuilder builder;
- BinaryTupleParser parser = new
BinaryTupleParser(delegate.elementCount(), tupleBuffer);
+ if (delegate instanceof BinaryTuple) {
+ // Estimate total data size.
+ var stats = new Sink() {
+ int estimatedValueSize = 0;
+
+ @Override
+ public void nextElement(int index, int begin, int end) {
+ estimatedValueSize += end - begin;
+ }
+ };
- // Estimate total data size.
- var stats = new Sink() {
- int estimatedValueSize = 0;
+ BinaryTuple binaryTuple = (BinaryTuple) delegate;
- @Override
- public void nextElement(int index, int begin, int end) {
- estimatedValueSize += end - begin;
+ for (int columnIndex : projection) {
+ binaryTuple.fetch(columnIndex, stats);
}
- };
- for (int columnIndex : projection) {
- parser.fetch(columnIndex, stats);
+ builder = new BinaryTupleBuilder(projection.length,
stats.estimatedValueSize, true);
+ } else {
+ builder = new BinaryTupleBuilder(projection.length, 32, false);
}
- // Now compose the tuple.
- BinaryTupleBuilder builder = new BinaryTupleBuilder(projection.length,
stats.estimatedValueSize);
+ assert delegate instanceof InternalTupleEx;
+ InternalTupleEx delegate0 = (InternalTupleEx) delegate;
+ // Now compose the tuple.
+ int[] newProjection = new int[projection.length];
for (int i = 0; i < projection.length; i++) {
- int columnIndex = projection[i];
-
- parser.fetch(columnIndex, (index, begin, end) -> {
- if (begin == end) {
- builder.appendNull();
- } else {
- builder.appendElementBytes(tupleBuffer, begin, end -
begin);
- }
- });
+ delegate0.copyValue(builder, projection[i]);
- newProjection[i] = columnIndex;
+ newProjection[i] = i;
}
delegate = new BinaryTuple(projection.length, builder.build());
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ProjectedTableRowConverterSelfTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ProjectedTableRowConverterSelfTest.java
index 067450001ec..09e32e42dc0 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ProjectedTableRowConverterSelfTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ProjectedTableRowConverterSelfTest.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.sql.engine.exec;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
@@ -28,7 +29,6 @@ import org.apache.calcite.util.BitSets;
import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
import org.apache.ignite.internal.schema.BinaryRow;
import org.apache.ignite.internal.schema.BinaryRowImpl;
-import org.apache.ignite.internal.schema.BinaryTupleSchema;
import org.apache.ignite.internal.schema.Column;
import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.schema.SchemaRegistry;
@@ -89,10 +89,9 @@ public class ProjectedTableRowConverterSelfTest extends
BaseIgniteAbstractTest {
ProjectedTableRowConverterImpl converter = new
ProjectedTableRowConverterImpl(
schemaRegistry,
- BinaryTupleSchema.createRowSchema(schema),
schema,
BitSets.of(1, 3),
- List.of()
+ Int2ObjectMaps.emptyMap()
);
RowWrapper row = converter.toRow(executionContext, binaryRow,
rowFactory);
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/ProjectedTupleTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/ProjectedTupleTest.java
index 5a97e4ca261..e4cac75daba 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/ProjectedTupleTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/ProjectedTupleTest.java
@@ -22,6 +22,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
@@ -37,6 +38,7 @@ import org.apache.ignite.internal.schema.BinaryTuple;
import org.apache.ignite.internal.schema.BinaryTupleSchema;
import org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
import org.apache.ignite.internal.schema.SchemaTestUtils;
+import org.apache.ignite.internal.sql.engine.exec.VirtualColumn;
import org.apache.ignite.internal.type.NativeTypeSpec;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -95,7 +97,7 @@ class ProjectedTupleTest {
InternalTuple projection1 = new FieldDeserializingProjectedTuple(
ALL_TYPES_SCHEMA, TUPLE, new int[projectionSize]
);
- InternalTuple projection2 = new FormatAwareProjectedTuple(
+ InternalTuple projection2 = new ProjectedTuple(
TUPLE, new int[projectionSize]
);
@@ -113,14 +115,14 @@ class ProjectedTupleTest {
int[] projection = {f1, f2, f3};
InternalTuple projectedTuple = useOptimizeProjection
- ? new FormatAwareProjectedTuple(TUPLE, projection)
+ ? new ProjectedTuple(TUPLE, projection)
: new FieldDeserializingProjectedTuple(ALL_TYPES_SCHEMA,
TUPLE, projection);
Element e1 = ALL_TYPES_SCHEMA.element(f1);
Element e2 = ALL_TYPES_SCHEMA.element(f2);
Element e3 = ALL_TYPES_SCHEMA.element(f3);
- BinaryTupleSchema projectedSchema = BinaryTupleSchema.create(new
Element[] {
+ BinaryTupleSchema projectedSchema = BinaryTupleSchema.create(new
Element[]{
e1, e2, e3
});
@@ -133,5 +135,47 @@ class ProjectedTupleTest {
assertThat(projectedSchema.value(restored, 0),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f1)));
assertThat(projectedSchema.value(restored, 1),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f2)));
assertThat(projectedSchema.value(restored, 2),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f3)));
+
+ // Ensure projected tuple is the same after normalization.
+ assertThat(projectedSchema.value(projectedTuple, 0),
equalTo(projectedSchema.value(restored, 0)));
+ assertThat(projectedSchema.value(projectedTuple, 1),
equalTo(projectedSchema.value(restored, 1)));
+ assertThat(projectedSchema.value(projectedTuple, 2),
equalTo(projectedSchema.value(restored, 2)));
+ }
+
+ @Test
+ void testProjectionWithExtraColumn() {
+ int f1 = RND.nextInt(ALL_TYPES_SCHEMA.elementCount());
+ int f2 = RND.nextInt(ALL_TYPES_SCHEMA.elementCount());
+ int f3 = RND.nextInt(ALL_TYPES_SCHEMA.elementCount());
+ int f4 = RND.nextInt(ALL_TYPES_SCHEMA.elementCount());
+
+ VirtualColumn virtualColumn = new VirtualColumn(
+ ALL_TYPES_SCHEMA.elementCount(),
+ specToType(ALL_TYPES_SCHEMA.element(f2).typeSpec()),
+ true, ALL_TYPES_SCHEMA.value(TUPLE, f2));
+
+ int[] projection = {f1, virtualColumn.columnIndex(), f3, f4};
+
+ InternalTuple projectedTuple = new ExtendedProjectedTuple(TUPLE,
projection,
+ Int2ObjectMaps.singleton(ALL_TYPES_SCHEMA.elementCount(),
virtualColumn));
+
+ Element e1 = ALL_TYPES_SCHEMA.element(f1);
+ Element e2 = ALL_TYPES_SCHEMA.element(f2);
+ Element e3 = ALL_TYPES_SCHEMA.element(f3);
+ Element e4 = ALL_TYPES_SCHEMA.element(f4);
+
+ BinaryTupleSchema projectedSchema = BinaryTupleSchema.create(new
Element[]{e1, e2, e3, e4});
+
+ assertThat(projectedSchema.value(projectedTuple, 0),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f1)));
+ assertThat(projectedSchema.value(projectedTuple, 1),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f2)));
+ assertThat(projectedSchema.value(projectedTuple, 2),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f3)));
+ assertThat(projectedSchema.value(projectedTuple, 3),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f4)));
+
+ InternalTuple restored = new BinaryTuple(projection.length,
projectedTuple.byteBuffer());
+
+ assertThat(projectedSchema.value(restored, 0),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f1)));
+ assertThat(projectedSchema.value(restored, 1),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f2)));
+ assertThat(projectedSchema.value(restored, 2),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f3)));
+ assertThat(projectedSchema.value(restored, 3),
equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f4)));
}
}