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

amashenkov pushed a commit to branch sql-virtual-column-poc
in repository https://gitbox.apache.org/repos/asf/ignite-3.git

commit d1d3f3f9b6c2d4465f6a5faf3e1218798170d4d8
Author: amashenkov <[email protected]>
AuthorDate: Fri Jun 14 15:07:27 2024 +0300

    wip
---
 .../internal/sql/engine/ItCreateTableDdlTest.java  | 27 +++++++---
 .../exec/ProjectedTableRowConverterImpl.java       | 62 ++++++++++++++++++++--
 .../sql/engine/exec/ScannableTableImpl.java        | 24 +++++----
 .../sql/engine/exec/TableRowConverterFactory.java  |  6 ++-
 .../engine/exec/TableRowConverterFactoryImpl.java  |  8 +--
 .../internal/sql/engine/exec/UpdatableTable.java   |  2 +-
 .../sql/engine/exec/UpdatableTableImpl.java        | 12 ++---
 .../internal/sql/engine/rel/IgniteTableModify.java |  1 +
 .../sql/engine/schema/IgniteTableImpl.java         |  8 +--
 .../sql/engine/schema/SqlSchemaManagerImpl.java    | 42 +++++++--------
 .../sql/engine/schema/TableDescriptor.java         | 10 ++++
 .../sql/engine/schema/TableDescriptorImpl.java     | 53 ++++++++++++++++--
 .../sql/engine/util/AbstractProjectedTuple.java    |  4 +-
 .../util/FieldDeserializingProjectedTuple.java     |  2 +-
 14 files changed, 198 insertions(+), 63 deletions(-)

diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
index 82359cc374..3d6fd1cc98 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
@@ -246,35 +246,48 @@ public class ItCreateTableDdlTest extends 
BaseSqlIntegrationTest {
 
         Tuple key1 = Tuple.create().set("id", 101L);
         Tuple key2 = Tuple.create().set("id", 102L);
+        Tuple key3 = Tuple.create().set("id", 103L);
 
         Table table = CLUSTER.node(0).tables().table("T0");
+        table.keyValueView().put(null, key3, Tuple.create().set("val", "v3"));
+
+        assertEquals(Tuple.create().set("val", "v3"), 
table.keyValueView().get(null, key3));
         assertEquals(Tuple.create().set("val", "v1"), 
table.keyValueView().get(null, key1));
         assertEquals(Tuple.create().set("val", "v2"), 
table.keyValueView().get(null, key2));
 
+        PartitionManager partitionManager = table.partitionManager();
+        int key1Part = 
((HashPartition)partitionManager.partitionAsync(key1).get()).partitionId();
+        int key2Part = 
((HashPartition)partitionManager.partitionAsync(key2).get()).partitionId();
+        int key3Part = 
((HashPartition)partitionManager.partitionAsync(key3).get()).partitionId();
+
+        assert key1Part != key2Part : key1Part;
+
+        log.info(format("XXX Partition: part={}, key={}", key1Part, key1));
+        log.info(format("XXX Partition: part={}, key={}", key2Part, key2));
+        log.info(format("XXX Partition: part={}, key={}", key3Part, key3));
+
         assertQuery("SELECT id, val FROM t0")
                 .returns(101L, "v1")
                 .returns(102L, "v2")
+                .returns(103L, "v3")
                 .check();
 
         assertQuery("SELECT * FROM t0")
                 .returns(101L, "v1")
                 .returns(102L, "v2")
+                .returns(103L, "v3")
                 .check();
 
-        PartitionManager partitionManager = table.partitionManager();
-        int key1Part = 
((HashPartition)partitionManager.partitionAsync(key1).get()).partitionId();
-        int key2Part = 
((HashPartition)partitionManager.partitionAsync(key2).get()).partitionId();
-
-        assert key1Part != key2Part : key1Part;
-
-        assertQuery("SELECT __part FROM t0")
+        assertQuery("SELECT __PART FROM t0")
                 .returns(key1Part)
                 .returns(key2Part)
+                .returns(key3Part)
                 .check();
 
         assertQuery("SELECT __part, id, val FROM t0")
                 .returns(key1Part, 101L, "v1")
                 .returns(key2Part, 102L, "v2")
+                .returns(key3Part, 103L, "v3")
                 .check();
     }
 
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 d7ece09da3..c1d4ebd9f0 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
@@ -18,10 +18,13 @@
 package org.apache.ignite.internal.sql.engine.exec;
 
 import java.util.BitSet;
+import org.apache.ignite.internal.binarytuple.BinaryTupleBuilder;
 import org.apache.ignite.internal.lang.InternalTuple;
 import org.apache.ignite.internal.schema.BinaryRow;
+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.SchemaDescriptor;
 import org.apache.ignite.internal.schema.SchemaRegistry;
@@ -40,15 +43,22 @@ public class ProjectedTableRowConverterImpl extends 
TableRowConverterImpl {
 
     private final BinaryTupleSchema fullTupleSchema;
 
+    // Partition id or -1 if not required.
+    private final int partId;
+
     /** Constructor. */
     ProjectedTableRowConverterImpl(
             SchemaRegistry schemaRegistry,
             BinaryTupleSchema fullTupleSchema,
             SchemaDescriptor schemaDescriptor,
-            BitSet requiredColumns
+            BitSet requiredColumns,
+            int partId
     ) {
         super(schemaRegistry, schemaDescriptor);
 
+        assert !requiredColumns.get(schemaDescriptor.length()) || partId >= 0 
: "Required partId was not set.";
+
+        this.partId = partId;
         this.fullTupleSchema = fullTupleSchema;
 
         int size = requiredColumns.cardinality();
@@ -61,12 +71,15 @@ public class ProjectedTableRowConverterImpl extends 
TableRowConverterImpl {
                 requiredColumnsMapping[requiredIndex++] = 
column.positionInRow();
             }
         }
+
+        if (requiredColumns.get(schemaDescriptor.length()))
+            requiredColumnsMapping[requiredIndex] = schemaDescriptor.length();
     }
 
     @Override
     public <RowT> RowT toRow(ExecutionContext<RowT> ectx, BinaryRow tableRow, 
RowFactory<RowT> factory) {
         InternalTuple tuple;
-        if (tableRow.schemaVersion() == schemaDescriptor.version()) {
+        if (tableRow.schemaVersion() == schemaDescriptor.version() && partId 
== -1) {
             BinaryTuple tableTuple = new 
BinaryTuple(schemaDescriptor.length(), tableRow.tupleSlice());
 
             tuple = new FormatAwareProjectedTuple(tableTuple, 
requiredColumnsMapping);
@@ -77,7 +90,50 @@ public class ProjectedTableRowConverterImpl extends 
TableRowConverterImpl {
                     fullTupleSchema,
                     tableTuple,
                     requiredColumnsMapping
-            );
+            ){
+                @Override
+                public int intValue(int col) {
+                    if (requiredColumnsMapping[col] == 
schemaDescriptor.length()) {
+                        return partId;
+                    }
+
+                    return super.intValue(col);
+                }
+
+                @Override
+                public Integer intValueBoxed(int col) {
+                    // Last column is partId when required.
+                    if (requiredColumnsMapping[col] == 
schemaDescriptor.length()) {
+                        return partId;
+                    }
+
+                    return super.intValueBoxed(col);
+                }
+
+                @Override
+                protected void normalize() {
+                    var builder = new BinaryTupleBuilder(projection.length);
+                    var newProjection = new int[projection.length];
+
+                    for (int i = 0; i < projection.length; i++) {
+                        int col = projection[i];
+
+                        newProjection[i] = i;
+
+                        if (col == schemaDescriptor.length()) {
+                            builder.appendInt(partId);
+                            continue;
+                        }
+
+                        Element element = schema.element(col);
+
+                        BinaryRowConverter.appendValue(builder, element, 
schema.value(delegate, col));
+                    }
+
+                    delegate = new BinaryTuple(projection.length, 
builder.build());
+                    projection = newProjection;
+                }
+            };
         }
 
         return factory.create(tuple);
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ScannableTableImpl.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ScannableTableImpl.java
index ec41c9be2b..0766783a79 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ScannableTableImpl.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ScannableTableImpl.java
@@ -61,18 +61,20 @@ public class ScannableTableImpl implements ScannableTable {
         Publisher<BinaryRow> pub;
         TxAttributes txAttributes = ctx.txAttributes();
 
+        int partId = partWithConsistencyToken.partId();
+
         if (txAttributes.readOnly()) {
             HybridTimestamp readTime = txAttributes.time();
 
             assert readTime != null;
 
-            pub = internalTable.scan(partWithConsistencyToken.partId(), 
txAttributes.id(), readTime, ctx.localNode(),
+            pub = internalTable.scan(partId, txAttributes.id(), readTime, 
ctx.localNode(),
                     txAttributes.coordinatorId());
         } else {
             PrimaryReplica recipient = new PrimaryReplica(ctx.localNode(), 
partWithConsistencyToken.enlistmentConsistencyToken());
 
             pub = internalTable.scan(
-                    partWithConsistencyToken.partId(),
+                    partId,
                     txAttributes.id(),
                     txAttributes.commitPartition(),
                     txAttributes.coordinatorId(),
@@ -85,7 +87,7 @@ public class ScannableTableImpl implements ScannableTable {
             );
         }
 
-        TableRowConverter rowConverter = 
converterFactory.create(requiredColumns);
+        TableRowConverter rowConverter = 
converterFactory.create(requiredColumns, partId);
 
         return new TransformingPublisher<>(pub, item -> 
rowConverter.toRow(ctx, item, rowFactory));
     }
@@ -122,13 +124,15 @@ public class ScannableTableImpl implements ScannableTable 
{
             flags |= (cond.upperInclude()) ? LESS_OR_EQUAL : 0;
         }
 
+        int partId = partWithConsistencyToken.partId();
+
         if (txAttributes.readOnly()) {
             HybridTimestamp readTime = txAttributes.time();
 
             assert readTime != null;
 
             pub = internalTable.scan(
-                    partWithConsistencyToken.partId(),
+                    partId,
                     txAttributes.id(),
                     readTime,
                     ctx.localNode(),
@@ -141,7 +145,7 @@ public class ScannableTableImpl implements ScannableTable {
             );
         } else {
             pub = internalTable.scan(
-                    partWithConsistencyToken.partId(),
+                    partId,
                     txAttributes.id(),
                     txAttributes.commitPartition(),
                     txAttributes.coordinatorId(),
@@ -154,7 +158,7 @@ public class ScannableTableImpl implements ScannableTable {
             );
         }
 
-        TableRowConverter rowConverter = 
converterFactory.create(requiredColumns);
+        TableRowConverter rowConverter = 
converterFactory.create(requiredColumns, partId);
 
         return new TransformingPublisher<>(pub, item -> 
rowConverter.toRow(ctx, item, rowFactory));
     }
@@ -179,13 +183,15 @@ public class ScannableTableImpl implements ScannableTable 
{
         assert keyTuple.elementCount() == columns.size()
                 : format("Key should contain exactly {} fields, but was {}", 
columns.size(), handler.toString(key));
 
+        int partId = partWithConsistencyToken.partId();
+
         if (txAttributes.readOnly()) {
             HybridTimestamp readTime = txAttributes.time();
 
             assert readTime != null;
 
             pub = internalTable.lookup(
-                    partWithConsistencyToken.partId(),
+                    partId,
                     txAttributes.id(),
                     readTime,
                     ctx.localNode(),
@@ -196,7 +202,7 @@ public class ScannableTableImpl implements ScannableTable {
             );
         } else {
             pub = internalTable.lookup(
-                    partWithConsistencyToken.partId(),
+                    partId,
                     txAttributes.id(),
                     txAttributes.commitPartition(),
                     txAttributes.coordinatorId(),
@@ -207,7 +213,7 @@ public class ScannableTableImpl implements ScannableTable {
             );
         }
 
-        TableRowConverter rowConverter = 
converterFactory.create(requiredColumns);
+        TableRowConverter rowConverter = 
converterFactory.create(requiredColumns, partId);
 
         return new TransformingPublisher<>(pub, item -> 
rowConverter.toRow(ctx, item, rowFactory));
     }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/TableRowConverterFactory.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/TableRowConverterFactory.java
index e465fef494..2ceced43ba 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/TableRowConverterFactory.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/TableRowConverterFactory.java
@@ -26,5 +26,9 @@ import org.jetbrains.annotations.Nullable;
  */
 @FunctionalInterface
 public interface TableRowConverterFactory {
-    TableRowConverter create(@Nullable BitSet requiredColumns);
+    default TableRowConverter create(@Nullable BitSet requiredColumns) {
+        return create(requiredColumns, -1);
+    };
+
+    TableRowConverter create(BitSet requiredColumns, int partId);
 }
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 8ce0c7ab28..8ada3d687b 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
@@ -59,8 +59,9 @@ public class TableRowConverterFactoryImpl implements 
TableRowConverterFactory {
     }
 
     @Override
-    public TableRowConverter create(@Nullable BitSet requiredColumns) {
-        if (requiredColumns == null || requiredColumns.cardinality() == 
schemaDescriptor.length()) {
+    public TableRowConverter create(@Nullable BitSet requiredColumns, int 
partId) {
+        // PartId column is next to the last schema column.
+        if (requiredColumns == null || requiredColumns.nextClearBit(0) == 
schemaDescriptor.length()) {
             return fullRowConverter;
         }
 
@@ -68,7 +69,8 @@ public class TableRowConverterFactoryImpl implements 
TableRowConverterFactory {
                 schemaRegistry,
                 fullTupleSchema,
                 schemaDescriptor,
-                requiredColumns
+                requiredColumns,
+                requiredColumns.get(schemaDescriptor.length()) ? partId : -1
         );
     }
 }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/UpdatableTable.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/UpdatableTable.java
index 24f679b53b..75fc764f32 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/UpdatableTable.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/UpdatableTable.java
@@ -70,7 +70,7 @@ public interface UpdatableTable {
      * Updates rows if they are exists, inserts the rows otherwise.
      *
      * <p>The rows passed should match the full row type defined by the 
table's {@link #descriptor() descriptor}
-     * (see {@link TableDescriptor#rowType(IgniteTypeFactory, 
ImmutableBitSet)}).
+     * (see {@link TableDescriptor#insertRowType(IgniteTypeFactory)} 
(IgniteTypeFactory)}).
      *
      * @param ectx An execution context.
      * @param rows Rows to upsert.
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/UpdatableTableImpl.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/UpdatableTableImpl.java
index 378af1ad16..699a0384da 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/UpdatableTableImpl.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/UpdatableTableImpl.java
@@ -116,7 +116,7 @@ public final class UpdatableTableImpl implements 
UpdatableTable {
 
         validateNotNullConstraint(ectx.rowHandler(), rows);
 
-        RelDataType rowType = descriptor().rowType(ectx.getTypeFactory(), 
null);
+        RelDataType rowType = 
descriptor().insertRowType(ectx.getTypeFactory());
         Supplier<RowSchema> schemaSupplier = makeSchemaSupplier(ectx);
 
         rows = validateCharactersOverflowAndTrimIfPossible(rowType, 
ectx.rowHandler(), rows, schemaSupplier);
@@ -199,7 +199,7 @@ public final class UpdatableTableImpl implements 
UpdatableTable {
     ) {
         validateNotNullConstraint(ectx.rowHandler(), row);
 
-        RelDataType rowType = descriptor().rowType(ectx.getTypeFactory(), 
null);
+        RelDataType rowType = 
descriptor().insertRowType(ectx.getTypeFactory());
         Supplier<RowSchema> schemaSupplier = makeSchemaSupplier(ectx);
 
         RowT validatedRow = 
TypeUtils.validateCharactersOverflowAndTrimIfPossible(rowType, 
ectx.rowHandler(), row, schemaSupplier);
@@ -230,7 +230,7 @@ public final class UpdatableTableImpl implements 
UpdatableTable {
 
         validateNotNullConstraint(ectx.rowHandler(), rows);
 
-        RelDataType rowType = descriptor().rowType(ectx.getTypeFactory(), 
null);
+        RelDataType rowType = 
descriptor().insertRowType(ectx.getTypeFactory());
         Supplier<RowSchema> schemaSupplier = makeSchemaSupplier(ectx);
 
         rows = validateCharactersOverflowAndTrimIfPossible(rowType, 
ectx.rowHandler(), rows, schemaSupplier);
@@ -347,7 +347,7 @@ public final class UpdatableTableImpl implements 
UpdatableTable {
 
                     RowHandler<RowT> handler = ectx.rowHandler();
                     IgniteTypeFactory typeFactory = ectx.getTypeFactory();
-                    RowSchema rowSchema = 
rowSchemaFromRelTypes(RelOptUtil.getFieldTypeList(desc.rowType(typeFactory, 
null)));
+                    RowSchema rowSchema = 
rowSchemaFromRelTypes(RelOptUtil.getFieldTypeList(desc.insertRowType(typeFactory)));
                     RowHandler.RowFactory<RowT> rowFactory = 
handler.factory(rowSchema);
 
                     ArrayList<String> conflictRows = new 
ArrayList<>(response.size());
@@ -400,7 +400,7 @@ public final class UpdatableTableImpl implements 
UpdatableTable {
         for (int i = 0; i < desc.columnsCount(); i++) {
             ColumnDescriptor column = desc.columnDescriptor(i);
 
-            if (!column.nullable() && rowHandler.isNull(i, row)) {
+            if (!column.nullable() && !column.system() && rowHandler.isNull(i, 
row)) {
                 String message = 
Static.RESOURCE.columnNotNullable(column.name()).ex().getMessage();
                 throw new SqlException(CONSTRAINT_VIOLATION_ERR, message);
             }
@@ -413,7 +413,7 @@ public final class UpdatableTableImpl implements 
UpdatableTable {
                 return rowSchema;
             }
 
-            RelDataType rowType = descriptor().rowType(ectx.getTypeFactory(), 
null);
+            RelDataType rowType = 
descriptor().insertRowType(ectx.getTypeFactory());
             rowSchema = 
rowSchemaFromRelTypes(RelOptUtil.getFieldTypeList(rowType));
             return rowSchema;
         };
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableModify.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableModify.java
index 53d02b7417..367b0fd1c1 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableModify.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableModify.java
@@ -25,6 +25,7 @@ import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelShuttle;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.core.TableModify;
 import org.apache.calcite.rex.RexNode;
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTableImpl.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTableImpl.java
index 170f23861d..47869dd3a6 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTableImpl.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTableImpl.java
@@ -28,6 +28,7 @@ import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.hint.RelHint;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.schema.Statistic;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
@@ -78,9 +79,9 @@ public class IgniteTableImpl extends AbstractIgniteDataSource 
implements IgniteT
     ) {
         var builder = new RelDataTypeFactory.Builder(typeFactory);
 
-        RelDataType fullRow = desc.rowType(typeFactory, null);
+        List<RelDataTypeField> fieldList = desc.rowType(typeFactory, 
null).getFieldList();
         for (int i : keyColumns) {
-            builder.add(fullRow.getFieldList().get(i));
+            builder.add(fieldList.get(i));
         }
 
         return builder.build();
@@ -175,7 +176,8 @@ public class IgniteTableImpl extends 
AbstractIgniteDataSource implements IgniteT
     /** {@inheritDoc} */
     @Override
     public RelDataType rowTypeForInsert(IgniteTypeFactory factory) {
-        return descriptor().rowType(factory, columnsToInsert);
+//        return descriptor().rowType(factory, columnsToInsert);
+        return descriptor().insertRowType(factory);
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImpl.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImpl.java
index 3beadff444..8ea2705076 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImpl.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/SqlSchemaManagerImpl.java
@@ -214,43 +214,39 @@ public class SqlSchemaManagerImpl implements 
SqlSchemaManager {
     }
 
     private static TableDescriptor 
createTableDescriptorForTable(CatalogTableDescriptor descriptor) {
-        List<ColumnDescriptor> colDescriptors = new ArrayList<>();
-
         List<CatalogTableColumnDescriptor> columns = descriptor.columns();
-        Object2IntMap<String> columnToIndex = new Object2IntOpenHashMap<>();
+
+        List<ColumnDescriptor> colDescriptors = new ArrayList<>(columns.size() 
+ 1);
+        Object2IntMap<String> columnToIndex = new 
Object2IntOpenHashMap<>(columns.size() + 1);
+
         for (int i = 0; i < columns.size(); i++) {
             CatalogTableColumnDescriptor col = columns.get(i);
             boolean key = descriptor.isPrimaryKeyColumn(col.name());
-            CatalogColumnDescriptor columnDescriptor = 
createColumnDescriptor(col, key, i);
+            ColumnDescriptor columnDescriptor = createColumnDescriptor(col, 
key, i);
 
             columnToIndex.put(col.name(), i);
-
             colDescriptors.add(columnDescriptor);
         }
 
+        if (Commons.implicitPkEnabled()) {
+            int implicitPkColIdx = 
columnToIndex.getInt(Commons.IMPLICIT_PK_COL_NAME);
+
+            colDescriptors.set(implicitPkColIdx, 
injectDefault(colDescriptors.get(implicitPkColIdx)));
+        }
+
         List<Integer> colocationColumns = 
descriptor.colocationColumns().stream()
                 .map(columnToIndex::getInt)
                 .collect(Collectors.toList());
 
+        // Add virtual column.
+        ColumnDescriptorImpl partVirtualColumn = 
createPartitionVirtualColumn(columns.size());
+        colDescriptors.add(partVirtualColumn);
+        columnToIndex.put(partVirtualColumn.name(), 
partVirtualColumn.logicalIndex());
+
         // TODO Use the actual zone ID after implementing 
https://issues.apache.org/jira/browse/IGNITE-18426.
         int tableId = descriptor.id();
         IgniteDistribution distribution = 
IgniteDistributions.affinity(colocationColumns, tableId, tableId);
 
-        if (Commons.implicitPkEnabled()) {
-            colDescriptors = colDescriptors.stream()
-                    .map(column -> {
-                        if 
(Commons.IMPLICIT_PK_COL_NAME.equals(column.name())) {
-                            return injectDefault(column);
-                        }
-
-                        return column;
-                    })
-                    .collect(Collectors.toList());
-        }
-
-        // Add virtual column.
-        colDescriptors.add(createPartitionVirtualColumn(columns.size()));
-
         return new TableDescriptorImpl(colDescriptors, distribution);
     }
 
@@ -263,8 +259,10 @@ public class SqlSchemaManagerImpl implements 
SqlSchemaManager {
                 true,
                 logicalIndex,
                 NativeTypes.INT32,
-                DefaultValueStrategy.DEFAULT_NULL,
-                null
+                DefaultValueStrategy.DEFAULT_COMPUTED,
+                () -> {
+                    throw new AssertionError("Implicit primary key is 
generated by a function");
+                }
         );
     }
 
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/TableDescriptor.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/TableDescriptor.java
index 962ea8d714..6be2697d8d 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/TableDescriptor.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/TableDescriptor.java
@@ -41,6 +41,16 @@ public interface TableDescriptor extends 
InitializerExpressionFactory, Iterable<
      */
     RelDataType rowType(IgniteTypeFactory factory, @Nullable ImmutableBitSet 
usedColumns);
 
+    /**
+     * Returns row type.
+     *
+     * @param factory     Type factory.
+     * @return Row type.
+     */
+    default RelDataType insertRowType(IgniteTypeFactory factory) {
+        return rowType(factory, null);
+    }
+
     /**
      * Returns column descriptor for given field name.
      *
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/TableDescriptorImpl.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/TableDescriptorImpl.java
index 761e4b8e18..30e671e84d 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/TableDescriptorImpl.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/TableDescriptorImpl.java
@@ -21,15 +21,19 @@ import static 
org.apache.ignite.internal.sql.engine.util.TypeUtils.native2relati
 import static org.apache.ignite.internal.util.IgniteUtils.newHashMap;
 
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeFactory.Builder;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.schema.ColumnStrategy;
+import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql2rel.InitializerContext;
 import org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
 import org.apache.calcite.util.ImmutableBitSet;
@@ -55,6 +59,11 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory implem
 
     private final RelDataType rowType;
 
+    private final ImmutableBitSet insertFields;
+
+    private final int partFieldIdx;
+    private RelDataTypeFieldImpl partField;
+
     /**
      * Constructor.
      *
@@ -68,15 +77,30 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory implem
 
         RelDataTypeFactory factory = Commons.typeFactory();
         RelDataTypeFactory.Builder typeBuilder = new 
RelDataTypeFactory.Builder(factory);
+        BitSet virtualFields = new BitSet();
         for (ColumnDescriptor descriptor : columnDescriptors) {
+            if (descriptor.system()) {
+                virtualFields.set(descriptor.logicalIndex());
+            }
+
             typeBuilder.add(descriptor.name(), deriveLogicalType(factory, 
descriptor));
             descriptorsMap.put(descriptor.name(), descriptor);
         }
 
         this.descriptors = columnDescriptors.toArray(DUMMY);
         this.descriptorsMap = descriptorsMap;
-
         this.rowType = typeBuilder.build();
+
+        if (virtualFields.isEmpty()) {
+            insertFields = null;
+            partFieldIdx = -1;
+        } else {
+            virtualFields.flip(0, descriptors.length);
+            insertFields = ImmutableBitSet.fromBitSet(virtualFields);
+
+            partFieldIdx = 
descriptorsMap.get(Commons.PART_COL_NAME).logicalIndex();
+            partField = new RelDataTypeFieldImpl(Commons.PART_COL_NAME, 
partFieldIdx, factory.createSqlType(SqlTypeName.INTEGER));
+        }
     }
 
     @Override
@@ -94,6 +118,9 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory implem
     @Override
     public ColumnStrategy generationStrategy(RelOptTable tbl, int colIdx) {
         if (descriptors[colIdx].system()) {
+            return ColumnStrategy.VIRTUAL;
+        }
+        if (descriptors[colIdx].hidden()) {
             return ColumnStrategy.STORED;
         }
         if (descriptors[colIdx].defaultStrategy() != 
DefaultValueStrategy.DEFAULT_NULL) {
@@ -124,6 +151,11 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory implem
                 return rexBuilder.makeLiteral(internalValue, relDataType, 
false);
             }
             case DEFAULT_COMPUTED: {
+                if (descriptor.system()) {
+
+                    return 
rexBuilder.makeInputRef(tbl.getRowType().getFieldList().get(colIdx).getType(), 
colIdx);
+                }
+
                 assert descriptor.key() : "DEFAULT_COMPUTED is only supported 
for primary key columns. Column: " + descriptor.name();
 
                 return rexBuilder.makeCall(IgniteSqlOperatorTable.RAND_UUID);
@@ -139,12 +171,23 @@ public class TableDescriptorImpl extends 
NullInitializerExpressionFactory implem
         if (usedColumns == null || usedColumns.cardinality() == 
descriptors.length) {
             return rowType;
         } else {
-            return new 
RelDataTypeFactory.Builder(factory).addAll(rowType.getFieldList().stream()
-                    .filter(field -> usedColumns.get(field.getIndex()))
-                    .collect(Collectors.toList())).build();
+            Builder builder = new Builder(factory);
+
+            List<RelDataTypeField> fieldList = rowType.getFieldList();
+            for (int i : usedColumns) {
+                builder.add(fieldList.get(i));
+            }
+
+            return builder.build();
         }
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public RelDataType insertRowType(IgniteTypeFactory factory) {
+        return rowType(factory, insertFields);
+    }
+
     /** {@inheritDoc} */
     @Override
     public ColumnDescriptor columnDescriptor(String fieldName) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/AbstractProjectedTuple.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/AbstractProjectedTuple.java
index 2ca099ad12..565000d977 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/AbstractProjectedTuple.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/AbstractProjectedTuple.java
@@ -47,8 +47,8 @@ import org.apache.ignite.internal.lang.InternalTuple;
  * </pre>
  */
 abstract class AbstractProjectedTuple implements InternalTuple {
-    InternalTuple delegate;
-    int[] projection;
+    protected InternalTuple delegate;
+    protected int[] projection;
 
     private boolean normalized = false;
 
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 22b0406851..1902fc6d68 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
@@ -36,7 +36,7 @@ import 
org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
  * @see AbstractProjectedTuple
  */
 public class FieldDeserializingProjectedTuple extends AbstractProjectedTuple {
-    private final BinaryTupleSchema schema;
+    protected final BinaryTupleSchema schema;
 
     /**
      * Constructor.

Reply via email to