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.
