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 83224d76e3 IGNITE-21862 Rename PK index when renaming a table (#3518)
83224d76e3 is described below

commit 83224d76e35a736c8dd754550432ecf0cdfd4f8b
Author: Alexander Polovtcev <[email protected]>
AuthorDate: Fri Mar 29 13:08:26 2024 +0200

    IGNITE-21862 Rename PK index when renaming a table (#3518)
---
 .../internal/catalog/commands/CatalogUtils.java    |  38 +++++-
 .../catalog/commands/RenameTableCommand.java       |  15 ++-
 .../internal/catalog/storage/RenameIndexEntry.java | 139 +++++++++++++++++++++
 .../CatalogEntrySerializerProvider.java            |   2 +
 .../serialization/MarshallableEntryType.java       |   3 +-
 .../internal/catalog/CatalogManagerSelfTest.java   |  20 +++
 .../commands/RenameTableCommandValidationTest.java |  22 ++++
 .../storage/CatalogEntrySerializationTest.java     |  12 ++
 8 files changed, 247 insertions(+), 4 deletions(-)

diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
index 5864113624..84d397f97e 100644
--- 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
@@ -413,6 +413,23 @@ public class CatalogUtils {
         return schema;
     }
 
+    /**
+     * Returns a schema descriptor of the schema with the a given ID.
+     *
+     * @param catalog Catalog to look up the schema in.
+     * @param schemaId Schema ID.
+     * @throws CatalogValidationException If schema does not exist.
+     */
+    public static CatalogSchemaDescriptor schemaOrThrow(Catalog catalog, int 
schemaId) throws CatalogValidationException {
+        CatalogSchemaDescriptor schema = catalog.schema(schemaId);
+
+        if (schema == null) {
+            throw new CatalogValidationException(format("Schema with ID '{}' 
not found", schemaId));
+        }
+
+        return schema;
+    }
+
     /**
      * Returns table with given name, or throws {@link 
TableNotFoundValidationException} if table with given name not exists.
      *
@@ -433,15 +450,32 @@ public class CatalogUtils {
         return table;
     }
 
+    /**
+     * Returns a table descriptor of the table with the a given ID.
+     *
+     * @param catalog Catalog to look up the table in.
+     * @param tableId Table ID.
+     * @throws TableNotFoundValidationException If table does not exist.
+     */
+    public static CatalogTableDescriptor tableOrThrow(Catalog catalog, int 
tableId) throws TableNotFoundValidationException {
+        CatalogTableDescriptor table = catalog.table(tableId);
+
+        if (table == null) {
+            throw new TableNotFoundValidationException(format("Table with ID 
'{}' not found", tableId));
+        }
+
+        return table;
+    }
+
     /**
      * Returns zone with given name, or throws {@link 
CatalogValidationException} if zone with given name not exists.
      *
      * @param catalog Catalog to look up zone in.
      * @param name Name of the zone of interest.
      * @return Zone with given name. Never null.
-     * @throws CatalogValidationException If zone with given name is not 
exists.
+     * @throws DistributionZoneNotFoundValidationException If zone with given 
name is not exists.
      */
-    public static CatalogZoneDescriptor zoneOrThrow(Catalog catalog, String 
name) throws CatalogValidationException {
+    public static CatalogZoneDescriptor zoneOrThrow(Catalog catalog, String 
name) throws DistributionZoneNotFoundValidationException {
         name = Objects.requireNonNull(name, "zoneName");
 
         CatalogZoneDescriptor zone = catalog.zone(name);
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
index 8bd014cc05..fdb9e1f7e8 100644
--- 
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
@@ -19,6 +19,8 @@ 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.indexOrThrow;
+import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.pkIndexName;
 import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.schemaOrThrow;
 import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.tableOrThrow;
 
@@ -26,8 +28,10 @@ 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.CatalogIndexDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogSchemaDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
+import org.apache.ignite.internal.catalog.storage.RenameIndexEntry;
 import org.apache.ignite.internal.catalog.storage.RenameTableEntry;
 import org.apache.ignite.internal.catalog.storage.UpdateEntry;
 
@@ -58,7 +62,16 @@ public class RenameTableCommand extends AbstractTableCommand 
{
 
         CatalogTableDescriptor table = tableOrThrow(schema, tableName);
 
-        return List.of(new RenameTableEntry(table.id(), newTableName));
+        String newPkIndexName = pkIndexName(newTableName);
+
+        ensureNoTableIndexOrSysViewExistsWithGivenName(schema, newPkIndexName);
+
+        CatalogIndexDescriptor pkIndex = indexOrThrow(catalog, 
table.primaryKeyIndexId());
+
+        return List.of(
+                new RenameTableEntry(table.id(), newTableName),
+                new RenameIndexEntry(pkIndex.id(), newPkIndexName)
+        );
     }
 
     private static class Builder implements RenameTableCommandBuilder {
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/RenameIndexEntry.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/RenameIndexEntry.java
new file mode 100644
index 0000000000..dabf422815
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/RenameIndexEntry.java
@@ -0,0 +1,139 @@
+/*
+ * 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 
org.apache.ignite.internal.catalog.commands.CatalogUtils.indexOrThrow;
+import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.replaceIndex;
+import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.replaceSchema;
+import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.schemaOrThrow;
+import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.tableOrThrow;
+import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
+
+import java.io.IOException;
+import org.apache.ignite.internal.catalog.Catalog;
+import org.apache.ignite.internal.catalog.CatalogValidationException;
+import 
org.apache.ignite.internal.catalog.descriptors.CatalogHashIndexDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.CatalogSchemaDescriptor;
+import 
org.apache.ignite.internal.catalog.descriptors.CatalogSortedIndexDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
+import 
org.apache.ignite.internal.catalog.storage.serialization.CatalogObjectSerializer;
+import 
org.apache.ignite.internal.catalog.storage.serialization.MarshallableEntryType;
+import org.apache.ignite.internal.tostring.S;
+import org.apache.ignite.internal.util.io.IgniteDataInput;
+import org.apache.ignite.internal.util.io.IgniteDataOutput;
+
+/** Entry representing a rename of an index. */
+public class RenameIndexEntry implements UpdateEntry {
+    public static final CatalogObjectSerializer<RenameIndexEntry> SERIALIZER = 
new RenameIndexEntrySerializer();
+
+    private final int indexId;
+
+    private final String newIndexName;
+
+    public RenameIndexEntry(int indexId, String newIndexName) {
+        this.indexId = indexId;
+        this.newIndexName = newIndexName;
+    }
+
+    @Override
+    public int typeId() {
+        return MarshallableEntryType.RENAME_INDEX.id();
+    }
+
+    @Override
+    public Catalog applyUpdate(Catalog catalog, long causalityToken) {
+        CatalogIndexDescriptor indexDescriptor = indexOrThrow(catalog, 
indexId);
+
+        CatalogTableDescriptor tableDescriptor = tableOrThrow(catalog, 
indexDescriptor.tableId());
+
+        CatalogSchemaDescriptor schemaDescriptor = schemaOrThrow(catalog, 
tableDescriptor.schemaId());
+
+        CatalogIndexDescriptor newIndexDescriptor = 
changeIndexName(indexDescriptor, causalityToken);
+
+        return new Catalog(
+                catalog.version(),
+                catalog.time(),
+                catalog.objectIdGenState(),
+                catalog.zones(),
+                replaceSchema(replaceIndex(schemaDescriptor, 
newIndexDescriptor), catalog.schemas())
+        );
+    }
+
+    private CatalogIndexDescriptor changeIndexName(CatalogIndexDescriptor 
indexDescriptor, long causalityToken) {
+        CatalogIndexDescriptor newIndexDescriptor;
+
+        if (indexDescriptor instanceof CatalogHashIndexDescriptor) {
+            newIndexDescriptor = 
changeHashIndexName((CatalogHashIndexDescriptor) indexDescriptor);
+        } else if (indexDescriptor instanceof CatalogSortedIndexDescriptor) {
+            newIndexDescriptor = 
changeSortedIndexName((CatalogSortedIndexDescriptor) indexDescriptor);
+        } else {
+            throw new CatalogValidationException(format("Unsupported index 
type '{}' {}", indexDescriptor.id(), indexDescriptor));
+        }
+
+        newIndexDescriptor.updateToken(causalityToken);
+
+        return newIndexDescriptor;
+    }
+
+    private CatalogIndexDescriptor 
changeHashIndexName(CatalogHashIndexDescriptor index) {
+        return new CatalogHashIndexDescriptor(
+                index.id(),
+                newIndexName,
+                index.tableId(),
+                index.unique(),
+                index.status(),
+                index.txWaitCatalogVersion(),
+                index.columns()
+        );
+    }
+
+    private CatalogIndexDescriptor 
changeSortedIndexName(CatalogSortedIndexDescriptor index) {
+        return new CatalogSortedIndexDescriptor(
+                index.id(),
+                newIndexName,
+                index.tableId(),
+                index.unique(),
+                index.status(),
+                index.txWaitCatalogVersion(),
+                index.columns()
+        );
+    }
+
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+
+    private static class RenameIndexEntrySerializer implements 
CatalogObjectSerializer<RenameIndexEntry> {
+        @Override
+        public RenameIndexEntry readFrom(IgniteDataInput input) throws 
IOException {
+            int indexId = input.readInt();
+
+            String newIndexName = input.readUTF();
+
+            return new RenameIndexEntry(indexId, newIndexName);
+        }
+
+        @Override
+        public void writeTo(RenameIndexEntry entry, IgniteDataOutput out) 
throws IOException {
+            out.writeInt(entry.indexId);
+            out.writeUTF(entry.newIndexName);
+        }
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/serialization/CatalogEntrySerializerProvider.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/serialization/CatalogEntrySerializerProvider.java
index 4b11f1af2b..4ab86fcb45 100644
--- 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/serialization/CatalogEntrySerializerProvider.java
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/serialization/CatalogEntrySerializerProvider.java
@@ -33,6 +33,7 @@ import 
org.apache.ignite.internal.catalog.storage.NewTableEntry;
 import org.apache.ignite.internal.catalog.storage.NewZoneEntry;
 import org.apache.ignite.internal.catalog.storage.ObjectIdGenUpdateEntry;
 import org.apache.ignite.internal.catalog.storage.RemoveIndexEntry;
+import org.apache.ignite.internal.catalog.storage.RenameIndexEntry;
 import org.apache.ignite.internal.catalog.storage.RenameTableEntry;
 import org.apache.ignite.internal.catalog.storage.SnapshotEntry;
 import org.apache.ignite.internal.catalog.storage.StartBuildingIndexEntry;
@@ -75,6 +76,7 @@ public interface CatalogEntrySerializerProvider {
             serializers[MarshallableEntryType.RENAME_TABLE.id()] = 
RenameTableEntry.SERIALIZER;
             serializers[MarshallableEntryType.ID_GENERATOR.id()] = 
ObjectIdGenUpdateEntry.SERIALIZER;
             serializers[MarshallableEntryType.SNAPSHOT.id()] = 
SnapshotEntry.SERIALIZER;
+            serializers[MarshallableEntryType.RENAME_INDEX.id()] = 
RenameIndexEntry.SERIALIZER;
             //noinspection ThisEscapedInObjectConstruction
             serializers[MarshallableEntryType.VERSIONED_UPDATE.id()] = new 
VersionedUpdateSerializer(this);
 
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/serialization/MarshallableEntryType.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/serialization/MarshallableEntryType.java
index 19f3b75d64..c18175d437 100644
--- 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/serialization/MarshallableEntryType.java
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/storage/serialization/MarshallableEntryType.java
@@ -38,7 +38,8 @@ public enum MarshallableEntryType {
     RENAME_TABLE(14),
     ID_GENERATOR(15),
     SNAPSHOT(16),
-    VERSIONED_UPDATE(17);
+    VERSIONED_UPDATE(17),
+    RENAME_INDEX(18);
 
     /** Type ID. */
     private final int id;
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 d469b4eb2b..6b885f03e6 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
@@ -2386,6 +2386,26 @@ public class CatalogManagerSelfTest extends 
BaseCatalogManagerTest {
         assertThat(curDescriptor.schemaId(), is(prevDescriptor.schemaId()));
     }
 
+    @Test
+    void testTableRenameAndCreateTableWithSameName() {
+        createSomeTable(TABLE_NAME);
+
+        CatalogCommand command = RenameTableCommand.builder()
+                .schemaName(SCHEMA_NAME)
+                .tableName(TABLE_NAME)
+                .newTableName(TABLE_NAME_2)
+                .build();
+
+        assertThat(manager.execute(command), willCompleteSuccessfully());
+
+        createSomeTable(TABLE_NAME);
+
+        int catalogVersion = manager.latestCatalogVersion();
+
+        assertThat(table(catalogVersion, TABLE_NAME), is(notNullValue()));
+        assertThat(table(catalogVersion, TABLE_NAME_2), is(notNullValue()));
+    }
+
     @Test
     void testTableRenameFiresEvent() {
         createSomeTable(TABLE_NAME);
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
index 891a8f2d76..ee13d1f194 100644
--- 
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
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.catalog.commands;
 
+import static 
org.apache.ignite.internal.catalog.commands.CatalogUtils.pkIndexName;
 import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrows;
 import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
 
@@ -144,4 +145,25 @@ public class RenameTableCommandValidationTest extends 
AbstractCommandValidationT
                 "Operations with reserved schemas are not allowed"
         );
     }
+
+    @Test
+    void exceptionIsThrownIfPkIndexWithNewNameExists() {
+        Catalog catalog = catalog(
+                createTableCommand("TEST"),
+                createTableCommand("TEST3"),
+                createIndexCommand("TEST3", pkIndexName("TEST2"))
+        );
+
+        CatalogCommand command = RenameTableCommand.builder()
+                .schemaName(SCHEMA_NAME)
+                .tableName("TEST")
+                .newTableName("TEST2")
+                .build();
+
+        assertThrows(
+                CatalogValidationException.class,
+                () -> command.get(catalog),
+                String.format("Index with name 'PUBLIC.%s' already exists", 
pkIndexName("TEST2"))
+        );
+    }
 }
diff --git 
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/storage/CatalogEntrySerializationTest.java
 
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/storage/CatalogEntrySerializationTest.java
index 899413dac1..ca881e1784 100644
--- 
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/storage/CatalogEntrySerializationTest.java
+++ 
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/storage/CatalogEntrySerializationTest.java
@@ -130,6 +130,10 @@ public class CatalogEntrySerializationTest extends 
BaseIgniteAbstractTest {
                 snapshotEntry();
                 break;
 
+            case RENAME_INDEX:
+                renameIndexEntry();
+                break;
+
             default:
                 throw new UnsupportedOperationException("Test not implemented 
" + type);
         }
@@ -337,6 +341,14 @@ public class CatalogEntrySerializationTest extends 
BaseIgniteAbstractTest {
         
BDDAssertions.assertThat(deserialized).usingRecursiveComparison().isEqualTo(entry);
     }
 
+    private void renameIndexEntry() {
+        var entry = new RenameIndexEntry(1, "newName");
+
+        VersionedUpdate update = newVersionedUpdate(entry);
+
+        assertVersionedUpdate(update, serialize(update));
+    }
+
     private VersionedUpdate serialize(VersionedUpdate update) {
         byte[] bytes = marshaller.marshall(update);
         return (VersionedUpdate) marshaller.unmarshall(bytes);

Reply via email to