use of org.apache.ignite.configuration.schemas.table.TableChange in project ignite-3 by apache.
the class DdlCommandHandler method handleCreateTable.
/**
* Handles create table command.
*/
private void handleCreateTable(CreateTableCommand cmd) {
final PrimaryKeyDefinitionBuilder pkeyDef = SchemaBuilders.primaryKey();
pkeyDef.withColumns(IgniteObjectName.quoteNames(cmd.primaryKeyColumns()));
pkeyDef.withColocationColumns(IgniteObjectName.quoteNames(cmd.affColumns()));
final IgniteTypeFactory typeFactory = Commons.typeFactory();
final List<org.apache.ignite.schema.definition.ColumnDefinition> colsInner = new ArrayList<>();
for (ColumnDefinition col : cmd.columns()) {
ColumnDefinitionBuilder col0 = SchemaBuilders.column(IgniteObjectName.quote(col.name()), typeFactory.columnType(col.type())).asNullable(col.nullable()).withDefaultValueExpression(col.defaultValue());
colsInner.add(col0.build());
}
Consumer<TableChange> tblChanger = tblCh -> {
TableChange conv = convert(SchemaBuilders.tableBuilder(IgniteObjectName.quote(cmd.schemaName()), IgniteObjectName.quote(cmd.tableName())).columns(colsInner).withPrimaryKey(pkeyDef.build()).build(), tblCh);
if (cmd.partitions() != null) {
conv.changePartitions(cmd.partitions());
}
if (cmd.replicas() != null) {
conv.changeReplicas(cmd.replicas());
}
};
String fullName = TableDefinitionImpl.canonicalName(IgniteObjectName.quote(cmd.schemaName()), IgniteObjectName.quote(cmd.tableName()));
try {
tableManager.createTable(fullName, tblChanger);
} catch (TableAlreadyExistsException ex) {
if (!cmd.ifTableExists()) {
throw ex;
}
}
}
use of org.apache.ignite.configuration.schemas.table.TableChange in project ignite-3 by apache.
the class SchemaUtils method columnMapper.
/**
* Prepares column mapper.
*
* @param oldDesc Old schema descriptor.
* @param oldTbl Old table configuration.
* @param newDesc New schema descriptor.
* @param newTbl New table configuration.
* @return Column mapper.
*/
public static ColumnMapper columnMapper(SchemaDescriptor oldDesc, TableView oldTbl, SchemaDescriptor newDesc, TableChange newTbl) {
ColumnMapper mapper = null;
NamedListView<? extends ColumnView> newTblColumns = newTbl.columns();
NamedListView<? extends ColumnView> oldTblColumns = oldTbl.columns();
// because removed keys are simply replaced with nulls
assert newTblColumns.size() >= oldTblColumns.size();
for (int i = 0; i < newTblColumns.size(); ++i) {
ColumnView newColView = newTblColumns.get(i);
// new value can be null if a column has been deleted
if (newColView == null) {
continue;
}
if (i < oldTblColumns.size()) {
ColumnView oldColView = oldTblColumns.get(i);
Column newCol = newDesc.column(newColView.name());
Column oldCol = oldDesc.column(oldColView.name());
if (newCol.schemaIndex() == oldCol.schemaIndex()) {
continue;
}
if (mapper == null) {
mapper = ColumnMapping.createMapper(newDesc);
}
mapper.add(newCol.schemaIndex(), oldCol.schemaIndex());
} else {
// if the new Named List is larger than the old one, it can only mean that a new column has been added
Column newCol = newDesc.column(newColView.name());
assert !newDesc.isKeyColumn(newCol.schemaIndex());
if (mapper == null) {
mapper = ColumnMapping.createMapper(newDesc);
}
mapper.add(newCol);
}
}
// since newTblColumns comes from a TableChange, it will contain nulls for removed columns
Optional<Column> droppedKeyCol = newTblColumns.namedListKeys().stream().filter(k -> newTblColumns.get(k) == null).map(oldDesc::column).filter(c -> oldDesc.isKeyColumn(c.schemaIndex())).findAny();
// TODO: configuration validators.
assert droppedKeyCol.isEmpty() : IgniteStringFormatter.format("Dropping of key column is forbidden: [schemaVer={}, col={}]", newDesc.version(), droppedKeyCol.get());
return mapper == null ? ColumnMapping.identityMapping() : mapper;
}
use of org.apache.ignite.configuration.schemas.table.TableChange in project ignite-3 by apache.
the class TableManager method createTableAsyncInternal.
/**
* Internal method that creates a new table with the given {@code name} asynchronously. If a table with the same name already exists,
* a future will be completed with {@link TableAlreadyExistsException}.
*
* @param name Table name.
* @param tableInitChange Table changer.
* @return Future representing pending completion of the operation.
* @throws IgniteException If an unspecified platform exception has happened internally. Is thrown when:
* <ul>
* <li>the node is stopping.</li>
* </ul>
* @see TableAlreadyExistsException
*/
private CompletableFuture<Table> createTableAsyncInternal(String name, Consumer<TableChange> tableInitChange) {
CompletableFuture<Table> tblFut = new CompletableFuture<>();
tableAsyncInternal(name).thenAccept(tbl -> {
if (tbl != null) {
tblFut.completeExceptionally(new TableAlreadyExistsException(name));
} else {
tablesCfg.tables().change(change -> {
if (change.get(name) != null) {
throw new TableAlreadyExistsException(name);
}
change.create(name, (ch) -> {
tableInitChange.accept(ch);
var extConfCh = ((ExtendedTableChange) ch);
tableCreateFuts.put(extConfCh.id(), tblFut);
// Affinity assignments calculation.
extConfCh.changeAssignments(ByteUtils.toBytes(AffinityUtils.calculateAssignments(baselineMgr.nodes(), ch.partitions(), ch.replicas()))).changeSchemas(schemasCh -> schemasCh.create(String.valueOf(INITIAL_SCHEMA_VERSION), schemaCh -> {
SchemaDescriptor schemaDesc;
// prepareSchemaDescriptor() method.
try {
schemaDesc = SchemaUtils.prepareSchemaDescriptor(((ExtendedTableView) ch).schemas().size(), ch);
} catch (IllegalArgumentException ex) {
throw new ConfigurationValidationException(ex.getMessage());
}
schemaCh.changeSchema(SchemaSerializerImpl.INSTANCE.serialize(schemaDesc));
}));
});
}).exceptionally(t -> {
Throwable ex = getRootCause(t);
if (ex instanceof TableAlreadyExistsException) {
tblFut.completeExceptionally(ex);
} else {
LOG.error(IgniteStringFormatter.format("Table wasn't created [name={}]", name), ex);
tblFut.completeExceptionally(ex);
tableCreateFuts.values().removeIf(fut -> fut == tblFut);
}
return null;
});
}
});
return tblFut;
}
use of org.apache.ignite.configuration.schemas.table.TableChange in project ignite-3 by apache.
the class TableManager method alterTableAsyncInternal.
/**
* Internal method that alters a cluster table. If an appropriate table does not exist, a future will be
* completed with {@link TableNotFoundException}.
*
* @param name Table name.
* @param tableChange Table changer.
* @return Future representing pending completion of the operation.
* @throws IgniteException If an unspecified platform exception has happened internally. Is thrown when:
* <ul>
* <li>the node is stopping.</li>
* </ul>
* @see TableNotFoundException
*/
@NotNull
private CompletableFuture<Void> alterTableAsyncInternal(String name, Consumer<TableChange> tableChange) {
CompletableFuture<Void> tblFut = new CompletableFuture<>();
tableAsync(name).thenAccept(tbl -> {
if (tbl == null) {
tblFut.completeExceptionally(new TableNotFoundException(name));
} else {
TableImpl tblImpl = (TableImpl) tbl;
tablesCfg.tables().change(ch -> {
if (ch.get(name) == null) {
throw new TableNotFoundException(name);
}
ch.update(name, tblCh -> {
tableChange.accept(tblCh);
((ExtendedTableChange) tblCh).changeSchemas(schemasCh -> schemasCh.createOrUpdate(String.valueOf(schemasCh.size() + 1), schemaCh -> {
ExtendedTableView currTableView = (ExtendedTableView) tablesCfg.tables().get(name).value();
SchemaDescriptor descriptor;
// here to ensure a valid configuration passed to prepareSchemaDescriptor() method.
try {
descriptor = SchemaUtils.prepareSchemaDescriptor(((ExtendedTableView) tblCh).schemas().size(), tblCh);
descriptor.columnMapping(SchemaUtils.columnMapper(tblImpl.schemaView().schema(currTableView.schemas().size()), currTableView, descriptor, tblCh));
} catch (IllegalArgumentException ex) {
// Convert unexpected exceptions here,
// because validation actually happens later,
// when bulk configuration update is applied.
ConfigurationValidationException e = new ConfigurationValidationException(ex.getMessage());
e.addSuppressed(ex);
throw e;
}
schemaCh.changeSchema(SchemaSerializerImpl.INSTANCE.serialize(descriptor));
}));
});
}).whenComplete((res, t) -> {
if (t != null) {
Throwable ex = getRootCause(t);
if (ex instanceof TableNotFoundException) {
tblFut.completeExceptionally(ex);
} else {
LOG.error(IgniteStringFormatter.format("Table wasn't altered [name={}]", name), ex);
tblFut.completeExceptionally(ex);
}
} else {
tblFut.complete(res);
}
});
}
});
return tblFut;
}
use of org.apache.ignite.configuration.schemas.table.TableChange in project ignite-3 by apache.
the class TableManagerTest method testApiTableManagerOnStop.
/**
* Tests a work of the public API for Table manager {@see org.apache.ignite.table.manager.IgniteTables} when the manager is stopping.
*/
@Test
public void testApiTableManagerOnStop() {
createTableManager(tblManagerFut);
TableManager tableManager = tblManagerFut.join();
tableManager.beforeNodeStop();
tableManager.stop();
String tblFullName = "PUBLIC." + DYNAMIC_TABLE_FOR_DROP_NAME;
Consumer<TableChange> createTableChange = (TableChange change) -> SchemaConfigurationConverter.convert(SchemaBuilders.tableBuilder("PUBLIC", DYNAMIC_TABLE_FOR_DROP_NAME).columns(SchemaBuilders.column("key", ColumnType.INT64).build(), SchemaBuilders.column("val", ColumnType.INT64).asNullable(true).build()).withPrimaryKey("key").build(), change).changeReplicas(REPLICAS).changePartitions(PARTITIONS);
final Consumer<TableChange> addColumnChange = (TableChange change) -> change.changeColumns(cols -> {
int colIdx = change.columns().namedListKeys().stream().mapToInt(Integer::parseInt).max().getAsInt() + 1;
cols.create(String.valueOf(colIdx), colChg -> SchemaConfigurationConverter.convert(SchemaBuilders.column("name", ColumnType.string()).build(), colChg));
});
TableManager igniteTables = tableManager;
assertThrows(IgniteException.class, () -> igniteTables.createTable(tblFullName, createTableChange));
assertThrows(IgniteException.class, () -> igniteTables.createTableAsync(tblFullName, createTableChange));
assertThrows(IgniteException.class, () -> igniteTables.alterTable(tblFullName, addColumnChange));
assertThrows(IgniteException.class, () -> igniteTables.alterTableAsync(tblFullName, addColumnChange));
assertThrows(IgniteException.class, () -> igniteTables.dropTable(tblFullName));
assertThrows(IgniteException.class, () -> igniteTables.dropTableAsync(tblFullName));
assertThrows(IgniteException.class, () -> igniteTables.tables());
assertThrows(IgniteException.class, () -> igniteTables.tablesAsync());
assertThrows(IgniteException.class, () -> igniteTables.table(tblFullName));
assertThrows(IgniteException.class, () -> igniteTables.tableAsync(tblFullName));
}
Aggregations