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

apolovtsev 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 642918794c IGNITE-21215 Add Catalog API for renaming a table (#3029)
642918794c is described below

commit 642918794c2d8c74506b3ae3c71d8c21c765d1c2
Author: Alexander Polovtcev <alex.polovt...@gmail.com>
AuthorDate: Fri Jan 12 09:29:44 2024 +0200

    IGNITE-21215 Add Catalog API for renaming a table (#3029)
---
 .../catalog/commands/RenameTableCommand.java       |  97 +++++++++++++++
 .../commands/RenameTableCommandBuilder.java        |  32 +++++
 .../internal/catalog/events/CatalogEvent.java      |   2 +-
 .../catalog/events/RenameTableEventParameters.java |  46 +++++++
 .../internal/catalog/storage/RenameTableEntry.java | 107 +++++++++++++++++
 .../internal/catalog/CatalogManagerSelfTest.java   |  79 ++++++++++++
 .../commands/RenameTableCommandValidationTest.java | 132 +++++++++++++++++++++
 .../ignite/internal/client/table/ClientTable.java  |   1 +
 .../ignite/client/fakes/FakeInternalTable.java     |   5 +
 .../ignite/internal/table/InternalTable.java       |   8 ++
 .../apache/ignite/internal/table/TableImpl.java    |   5 +
 .../internal/table/distributed/TableManager.java   |  30 ++++-
 .../distributed/storage/InternalTableImpl.java     |   7 +-
 13 files changed, 548 insertions(+), 3 deletions(-)

diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/RenameTableCommand.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/RenameTableCommand.java
new file mode 100644
index 0000000000..8bd014cc05
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/RenameTableCommand.java
@@ -0,0 +1,97 @@
+/*
+ * 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.catalog.commands;
+
+import static 
org.apache.ignite.internal.catalog.CatalogParamsValidationUtils.ensureNoTableIndexOrSysViewExistsWithGivenName;
+import static 
org.apache.ignite.internal.catalog.CatalogParamsValidationUtils.validateIdentifier;
+import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.schemaOrThrow;
+import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.tableOrThrow;
+
+import java.util.List;
+import org.apache.ignite.internal.catalog.Catalog;
+import org.apache.ignite.internal.catalog.CatalogCommand;
+import org.apache.ignite.internal.catalog.CatalogValidationException;
+import org.apache.ignite.internal.catalog.descriptors.CatalogSchemaDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
+import org.apache.ignite.internal.catalog.storage.RenameTableEntry;
+import org.apache.ignite.internal.catalog.storage.UpdateEntry;
+
+/**
+ * A command that changes the name of a table.
+ */
+public class RenameTableCommand extends AbstractTableCommand {
+    /** Returns a builder to create a command to rename a table. */
+    public static RenameTableCommandBuilder builder() {
+        return new Builder();
+    }
+
+    private final String newTableName;
+
+    private RenameTableCommand(String schemaName, String tableName, String 
newTableName) throws CatalogValidationException {
+        super(schemaName, tableName);
+
+        validateIdentifier(newTableName, "New table name");
+
+        this.newTableName = newTableName;
+    }
+
+    @Override
+    public List<UpdateEntry> get(Catalog catalog) {
+        CatalogSchemaDescriptor schema = schemaOrThrow(catalog, schemaName);
+
+        ensureNoTableIndexOrSysViewExistsWithGivenName(schema, newTableName);
+
+        CatalogTableDescriptor table = tableOrThrow(schema, tableName);
+
+        return List.of(new RenameTableEntry(table.id(), newTableName));
+    }
+
+    private static class Builder implements RenameTableCommandBuilder {
+        private String schemaName;
+
+        private String tableName;
+
+        private String newTableName;
+
+        @Override
+        public RenameTableCommandBuilder schemaName(String schemaName) {
+            this.schemaName = schemaName;
+
+            return this;
+        }
+
+        @Override
+        public RenameTableCommandBuilder tableName(String tableName) {
+            this.tableName = tableName;
+
+            return this;
+        }
+
+        @Override
+        public RenameTableCommandBuilder newTableName(String newTableName) {
+            this.newTableName = newTableName;
+
+            return this;
+        }
+
+        @Override
+        public CatalogCommand build() {
+            return new RenameTableCommand(schemaName, tableName, newTableName);
+        }
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/RenameTableCommandBuilder.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/RenameTableCommandBuilder.java
new file mode 100644
index 0000000000..223739972e
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/RenameTableCommandBuilder.java
@@ -0,0 +1,32 @@
+/*
+ * 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.catalog.commands;
+
+/** Builder for {@link RenameTableCommand}s. */
+public interface RenameTableCommandBuilder extends 
AbstractTableCommandBuilder<RenameTableCommandBuilder> {
+    /**
+     * Sets the new name of the target table.
+     *
+     * <p>The new name must not be {@code null}, empty or blank. It is also 
required that a table with the same name does not already exist
+     * in the schema that the target table belongs to.
+     *
+     * @param newTableName New name of the target table.
+     * @return this instance (for chaining).
+     */
+    RenameTableCommandBuilder newTableName(String newTableName);
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEvent.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEvent.java
index 444aa30ffd..91c2ed325c 100644
--- 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEvent.java
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEvent.java
@@ -29,7 +29,7 @@ public enum CatalogEvent implements Event {
     /** This event is fired, when a table was dropped in Catalog. */
     TABLE_DROP,
 
-    /** This event is fired when a column has been modified, added to, or 
removed from a table. */
+    /** This event is fired when a table has been renamed or a column has been 
modified, added to, or removed from a table. */
     TABLE_ALTER,
 
     /** This event is fired, when an index was created in Catalog. */
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/RenameTableEventParameters.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/RenameTableEventParameters.java
new file mode 100644
index 0000000000..41749f2cf1
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/RenameTableEventParameters.java
@@ -0,0 +1,46 @@
+/*
+ * 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.catalog.events;
+
+/**
+ * Parameters for events that get produced when a table is renamed.
+ */
+public class RenameTableEventParameters extends TableEventParameters {
+    private final String newTableName;
+
+    /**
+     * Constructor.
+     *
+     * @param causalityToken Causality token for the event.
+     * @param catalogVersion New catalog version.
+     * @param tableId ID of the altered table.
+     * @param newTableName New name of the table.
+     */
+    public RenameTableEventParameters(long causalityToken, int catalogVersion, 
int tableId, String newTableName) {
+        super(causalityToken, catalogVersion, tableId);
+
+        this.newTableName = newTableName;
+    }
+
+    /**
+     * Returns the new name of the updated table.
+     */
+    public String newTableName() {
+        return newTableName;
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/RenameTableEntry.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/RenameTableEntry.java
new file mode 100644
index 0000000000..ed0e89c80c
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/RenameTableEntry.java
@@ -0,0 +1,107 @@
+/*
+ * 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.catalog.storage;
+
+import static java.util.Objects.requireNonNull;
+import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.replaceSchema;
+
+import org.apache.ignite.internal.catalog.Catalog;
+import org.apache.ignite.internal.catalog.descriptors.CatalogSchemaDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
+import org.apache.ignite.internal.catalog.events.CatalogEvent;
+import org.apache.ignite.internal.catalog.events.CatalogEventParameters;
+import org.apache.ignite.internal.catalog.events.RenameTableEventParameters;
+
+/** Entry representing a rename of a table. */
+public class RenameTableEntry implements UpdateEntry, Fireable {
+    private static final long serialVersionUID = 4841281816270322196L;
+
+    private final int tableId;
+
+    private final String newTableName;
+
+    public RenameTableEntry(int tableId, String newTableName) {
+        this.tableId = tableId;
+        this.newTableName = newTableName;
+    }
+
+    @Override
+    public CatalogEvent eventType() {
+        return CatalogEvent.TABLE_ALTER;
+    }
+
+    @Override
+    public CatalogEventParameters createEventParameters(long causalityToken, 
int catalogVersion) {
+        return new RenameTableEventParameters(causalityToken, catalogVersion, 
tableId, newTableName);
+    }
+
+    @Override
+    public Catalog applyUpdate(Catalog catalog, long causalityToken) {
+        CatalogTableDescriptor tableDescriptor = 
requireNonNull(catalog.table(tableId));
+
+        CatalogSchemaDescriptor schemaDescriptor = 
requireNonNull(catalog.schema(tableDescriptor.schemaId()));
+
+        CatalogTableDescriptor newTableDescriptor = 
tableDescriptor.newDescriptor(
+                newTableName,
+                tableDescriptor.tableVersion() + 1,
+                tableDescriptor.columns(),
+                causalityToken
+        );
+
+        CatalogSchemaDescriptor newSchemaDescriptor = 
replaceTableDescriptor(schemaDescriptor, newTableDescriptor, causalityToken);
+
+        return new Catalog(
+                catalog.version(),
+                catalog.time(),
+                catalog.objectIdGenState(),
+                catalog.zones(),
+                replaceSchema(newSchemaDescriptor, catalog.schemas())
+        );
+    }
+
+    private static CatalogSchemaDescriptor replaceTableDescriptor(
+            CatalogSchemaDescriptor schemaDescriptor,
+            CatalogTableDescriptor newTableDescriptor,
+            long causalityToken
+    ) {
+        CatalogTableDescriptor[] tableDescriptors = 
schemaDescriptor.tables().clone();
+
+        tableDescriptors[indexOf(tableDescriptors, newTableDescriptor)] = 
newTableDescriptor;
+
+        return new CatalogSchemaDescriptor(
+                schemaDescriptor.id(),
+                schemaDescriptor.name(),
+                tableDescriptors,
+                schemaDescriptor.indexes(),
+                schemaDescriptor.systemViews(),
+                causalityToken
+        );
+    }
+
+    private static int indexOf(CatalogTableDescriptor[] tableDescriptors, 
CatalogTableDescriptor newTableDescriptor) {
+        for (int i = 0; i < tableDescriptors.length; i++) {
+            if (tableDescriptors[i].id() == newTableDescriptor.id()) {
+                return i;
+            }
+        }
+
+        throw new IllegalStateException(String.format(
+                "Table with ID %d has not been found in schema with ID %d", 
newTableDescriptor.id(), newTableDescriptor.schemaId()
+        ));
+    }
+}
diff --git 
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java
 
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java
index adeeb24f0c..e383f9bee7 100644
--- 
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java
+++ 
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java
@@ -61,6 +61,7 @@ import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
@@ -104,6 +105,7 @@ import 
org.apache.ignite.internal.catalog.commands.DefaultValue;
 import org.apache.ignite.internal.catalog.commands.DropIndexCommand;
 import org.apache.ignite.internal.catalog.commands.DropZoneCommand;
 import org.apache.ignite.internal.catalog.commands.MakeIndexAvailableCommand;
+import org.apache.ignite.internal.catalog.commands.RenameTableCommand;
 import org.apache.ignite.internal.catalog.commands.RenameZoneCommand;
 import 
org.apache.ignite.internal.catalog.descriptors.CatalogHashIndexDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
@@ -124,6 +126,7 @@ import 
org.apache.ignite.internal.catalog.events.DropIndexEventParameters;
 import org.apache.ignite.internal.catalog.events.DropTableEventParameters;
 import org.apache.ignite.internal.catalog.events.DropZoneEventParameters;
 import 
org.apache.ignite.internal.catalog.events.MakeIndexAvailableEventParameters;
+import org.apache.ignite.internal.catalog.events.RenameTableEventParameters;
 import org.apache.ignite.internal.catalog.storage.ObjectIdGenUpdateEntry;
 import org.apache.ignite.internal.catalog.storage.UpdateLog;
 import org.apache.ignite.internal.catalog.storage.UpdateLog.OnUpdateHandler;
@@ -2067,6 +2070,82 @@ public class CatalogManagerSelfTest extends 
BaseCatalogManagerTest {
         assertThat(tableIndexIds(catalogVersion, tableId(TABLE_NAME)), 
equalTo(List.of(indexId0, indexId1, indexId2)));
     }
 
+    @Test
+    void testTableRename() {
+        createSomeTable(TABLE_NAME);
+
+        int prevVersion = manager.latestCatalogVersion();
+
+        CatalogCommand command = RenameTableCommand.builder()
+                .schemaName(SCHEMA_NAME)
+                .tableName(TABLE_NAME)
+                .newTableName(TABLE_NAME_2)
+                .build();
+
+        assertThat(manager.execute(command), willCompleteSuccessfully());
+
+        int curVersion = manager.latestCatalogVersion();
+
+        CatalogTableDescriptor prevDescriptor = table(prevVersion, TABLE_NAME);
+        CatalogTableDescriptor curDescriptor = table(curVersion, TABLE_NAME_2);
+
+        assertThat(prevDescriptor, is(notNullValue()));
+        assertThat(prevDescriptor.name(), is(TABLE_NAME));
+
+        assertThat(curDescriptor, is(notNullValue()));
+        assertThat(curDescriptor.name(), is(TABLE_NAME_2));
+
+        assertThat(table(prevVersion, TABLE_NAME_2), is(nullValue()));
+        assertThat(table(curVersion, TABLE_NAME), is(nullValue()));
+
+        assertThat(curDescriptor.tableVersion(), 
is(prevDescriptor.tableVersion() + 1));
+
+        // Assert that all other properties have been left intact.
+        assertThat(curDescriptor.id(), is(prevDescriptor.id()));
+        assertThat(curDescriptor.columns(), is(prevDescriptor.columns()));
+        assertThat(curDescriptor.colocationColumns(), 
is(prevDescriptor.colocationColumns()));
+        assertThat(curDescriptor.creationToken(), 
is(prevDescriptor.creationToken()));
+        assertThat(curDescriptor.primaryKeyColumns(), 
is(prevDescriptor.primaryKeyColumns()));
+        assertThat(curDescriptor.primaryKeyIndexId(), 
is(prevDescriptor.primaryKeyIndexId()));
+        assertThat(curDescriptor.schemaId(), is(prevDescriptor.schemaId()));
+    }
+
+    @Test
+    void testTableRenameFiresEvent() {
+        createSomeTable(TABLE_NAME);
+
+        var eventFuture = new CompletableFuture<CatalogEventParameters>();
+
+        manager.listen(CatalogEvent.TABLE_ALTER, (parameters, e) -> {
+            if (e != null) {
+                eventFuture.completeExceptionally(e);
+            } else {
+                eventFuture.complete(parameters);
+            }
+
+            return trueCompletedFuture();
+        });
+
+        CatalogCommand command = RenameTableCommand.builder()
+                .schemaName(SCHEMA_NAME)
+                .tableName(TABLE_NAME)
+                .newTableName(TABLE_NAME_2)
+                .build();
+
+        assertThat(manager.execute(command), willCompleteSuccessfully());
+        assertThat(eventFuture, willCompleteSuccessfully());
+
+        CatalogTableDescriptor tableDescriptor = 
table(manager.latestCatalogVersion(), TABLE_NAME_2);
+
+        assertThat(tableDescriptor, is(notNullValue()));
+
+        CatalogEventParameters eventParameters = eventFuture.join();
+
+        assertThat(eventParameters, 
is(instanceOf(RenameTableEventParameters.class)));
+        assertThat(((RenameTableEventParameters) eventParameters).tableId(), 
is(tableDescriptor.id()));
+        assertThat(((RenameTableEventParameters) 
eventParameters).newTableName(), is(tableDescriptor.name()));
+    }
+
     private CompletableFuture<Void> changeColumn(
             String tab,
             String col,
diff --git 
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/RenameTableCommandValidationTest.java
 
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/RenameTableCommandValidationTest.java
new file mode 100644
index 0000000000..0a983adbf0
--- /dev/null
+++ 
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/RenameTableCommandValidationTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.catalog.commands;
+
+import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrows;
+
+import java.util.List;
+import org.apache.ignite.internal.catalog.Catalog;
+import org.apache.ignite.internal.catalog.CatalogCommand;
+import org.apache.ignite.internal.catalog.CatalogValidationException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/**
+ * Test suite for validating parameters of {@link RenameTableCommand}s.
+ */
+public class RenameTableCommandValidationTest extends 
AbstractCommandValidationTest {
+    @ParameterizedTest(name = "[{index}] ''{argumentsWithNames}''")
+    @MethodSource("nullAndBlankStrings")
+    void schemaNameMustNotBeNullOrBlank(String name) {
+        RenameTableCommandBuilder builder = RenameTableCommand.builder()
+                .schemaName(name)
+                .tableName("TEST")
+                .newTableName("TEST2");
+
+        assertThrows(
+                CatalogValidationException.class,
+                builder::build,
+                "Name of the schema can't be null or blank"
+        );
+    }
+
+    @ParameterizedTest(name = "[{index}] ''{argumentsWithNames}''")
+    @MethodSource("nullAndBlankStrings")
+    void tableNameMustNotBeNullOrBlank(String name) {
+        RenameTableCommandBuilder builder = RenameTableCommand.builder()
+                .schemaName("TEST")
+                .tableName(name)
+                .newTableName("TEST2");
+
+        assertThrows(
+                CatalogValidationException.class,
+                builder::build,
+                "Name of the table can't be null or blank"
+        );
+    }
+
+    @ParameterizedTest(name = "[{index}] ''{argumentsWithNames}''")
+    @MethodSource("nullAndBlankStrings")
+    void newTableNameMustNotBeNullOrBlank(String name) {
+        RenameTableCommandBuilder builder = RenameTableCommand.builder()
+                .schemaName("TEST")
+                .tableName("TEST")
+                .newTableName(name);
+
+        assertThrows(
+                CatalogValidationException.class,
+                builder::build,
+                "New table name can't be null or blank"
+        );
+    }
+
+    @Test
+    void exceptionIsThrownIfSchemaDoesNotExist() {
+        Catalog catalog = emptyCatalog();
+
+        CatalogCommand command = RenameTableCommand.builder()
+                .schemaName("TEST")
+                .tableName("TEST")
+                .newTableName("TEST2")
+                .build();
+
+        assertThrows(
+                CatalogValidationException.class,
+                () -> command.get(catalog),
+                "Schema with name 'TEST' not found"
+        );
+    }
+
+    @Test
+    void exceptionIsThrownIfTableWithGivenNameNotFound() {
+        Catalog catalog = emptyCatalog();
+
+        CatalogCommand command = RenameTableCommand.builder()
+                .schemaName(SCHEMA_NAME)
+                .tableName("TEST")
+                .newTableName("TEST2")
+                .build();
+
+        assertThrows(
+                CatalogValidationException.class,
+                () -> command.get(catalog),
+                "Table with name 'PUBLIC.TEST' not found"
+        );
+    }
+
+    @Test
+    void exceptionIsThrownIfTableWithNewNameExists() {
+        Catalog catalog = catalog(List.of(
+                createTableCommand("TEST"),
+                createTableCommand("TEST2")
+        ));
+
+        CatalogCommand command = RenameTableCommand.builder()
+                .schemaName(SCHEMA_NAME)
+                .tableName("TEST")
+                .newTableName("TEST2")
+                .build();
+
+        assertThrows(
+                CatalogValidationException.class,
+                () -> command.get(catalog),
+                "Table with name 'PUBLIC.TEST2' already exists"
+        );
+    }
+}
diff --git 
a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
 
b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
index faee18b10c..69df134d0b 100644
--- 
a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
+++ 
b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
@@ -60,6 +60,7 @@ import org.jetbrains.annotations.Nullable;
 public class ClientTable implements Table {
     private final int id;
 
+    // TODO: table name can change, this approach should probably be reworked, 
see https://issues.apache.org/jira/browse/IGNITE-21237.
     private final String name;
 
     private final ReliableChannel ch;
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeInternalTable.java
 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeInternalTable.java
index 770204fd04..faf2db5484 100644
--- 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeInternalTable.java
+++ 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeInternalTable.java
@@ -105,6 +105,11 @@ public class FakeInternalTable implements InternalTable {
         return tableName;
     }
 
+    @Override
+    public void name(String newName) {
+        throw new UnsupportedOperationException("Should not be called");
+    }
+
     @Override
     public int partitionId(BinaryRowEx row) {
         return 0;
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/InternalTable.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/InternalTable.java
index c631642a69..d0bc67282c 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/InternalTable.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/InternalTable.java
@@ -68,6 +68,14 @@ public interface InternalTable extends ManuallyCloseable {
      */
     String name();
 
+    /**
+     * Sets the name of the table.
+     *
+     * @param newName New name.
+     */
+    // TODO: revisit this approach, see 
https://issues.apache.org/jira/browse/IGNITE-21235.
+    void name(String newName);
+
     /**
      * Extracts an identifier of a partition from a given row.
      *
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/TableImpl.java 
b/modules/table/src/main/java/org/apache/ignite/internal/table/TableImpl.java
index 6a5c316a5a..f12ddf0b31 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/TableImpl.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/TableImpl.java
@@ -133,6 +133,11 @@ public class TableImpl implements TableViewInternal {
         return tbl.name();
     }
 
+    // TODO: revisit this approach, see 
https://issues.apache.org/jira/browse/IGNITE-21235.
+    public void name(String newName) {
+        tbl.name(newName);
+    }
+
     @Override
     public SchemaRegistry schemaView() {
         return schemaReg;
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java
index ca770df651..976e0f2ae1 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java
@@ -88,6 +88,7 @@ import 
org.apache.ignite.internal.catalog.descriptors.CatalogZoneDescriptor;
 import org.apache.ignite.internal.catalog.events.CatalogEvent;
 import org.apache.ignite.internal.catalog.events.CreateTableEventParameters;
 import org.apache.ignite.internal.catalog.events.DropTableEventParameters;
+import org.apache.ignite.internal.catalog.events.RenameTableEventParameters;
 import org.apache.ignite.internal.causality.CompletionListener;
 import org.apache.ignite.internal.causality.IncrementalVersionedValue;
 import org.apache.ignite.internal.close.ManuallyCloseable;
@@ -535,6 +536,16 @@ public class TableManager implements IgniteTablesInternal, 
IgniteComponent {
                 return onTableDelete(((DropTableEventParameters) 
parameters)).thenApply(unused -> false);
             });
 
+            catalogService.listen(CatalogEvent.TABLE_ALTER, (parameters, 
exception) -> {
+                assert exception == null : parameters;
+
+                if (parameters instanceof RenameTableEventParameters) {
+                    return onTableRename((RenameTableEventParameters) 
parameters).thenApply(unused -> false);
+                } else {
+                    return falseCompletedFuture();
+                }
+            });
+
             partitionReplicatorNodeRecovery.start();
         });
 
@@ -584,7 +595,6 @@ public class TableManager implements IgniteTablesInternal, 
IgniteComponent {
                     })
                     .toArray(CompletableFuture[]::new);
 
-
             return allOf(futures)
                     // Simply log any errors, we don't want to block watch 
processing.
                     .exceptionally(e -> {
@@ -643,6 +653,24 @@ public class TableManager implements IgniteTablesInternal, 
IgniteComponent {
         });
     }
 
+    private CompletableFuture<?> onTableRename(RenameTableEventParameters 
parameters) {
+        return inBusyLockAsync(busyLock, () -> tablesByIdVv.update(
+                parameters.causalityToken(),
+                (tablesById, e) -> {
+                    if (e != null) {
+                        return failedFuture(e);
+                    }
+
+                    TableImpl table = tablesById.get(parameters.tableId());
+
+                    // TODO: revisit this approach, see 
https://issues.apache.org/jira/browse/IGNITE-21235.
+                    table.name(parameters.newTableName());
+
+                    return completedFuture(tablesById);
+                })
+        );
+    }
+
     /**
      * Updates or creates partition raft groups and storages.
      *
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/storage/InternalTableImpl.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/storage/InternalTableImpl.java
index f2b37329f4..6d35322694 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/storage/InternalTableImpl.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/storage/InternalTableImpl.java
@@ -136,7 +136,7 @@ public class InternalTableImpl implements InternalTable {
     private final int partitions;
 
     /** Table name. */
-    private final String tableName;
+    private volatile String tableName;
 
     /** Table identifier. */
     private final int tableId;
@@ -244,6 +244,11 @@ public class InternalTableImpl implements InternalTable {
         return tableName;
     }
 
+    @Override
+    public void name(String newName) {
+        this.tableName = newName;
+    }
+
     /**
      * Enlists a single row into a transaction.
      *

Reply via email to