diff --git a/core/src/main/java/com/scalar/db/api/Admin.java b/core/src/main/java/com/scalar/db/api/Admin.java index 937c959aa0..dc7fa43a0e 100644 --- a/core/src/main/java/com/scalar/db/api/Admin.java +++ b/core/src/main/java/com/scalar/db/api/Admin.java @@ -3,6 +3,7 @@ import com.scalar.db.common.CoreError; import com.scalar.db.exception.storage.ExecutionException; import com.scalar.db.io.DataType; +import com.scalar.db.util.ScalarDbUtils; import java.util.Collections; import java.util.Map; import java.util.Set; @@ -441,6 +442,43 @@ default void addNewColumnToTable( } } + /** + * Adds a new column to an existing table. The new column cannot be a partition or clustering key. + *
+ * See {@link #addNewColumnToTable(String, String, String, DataType)} for more information. + * + * @param namespace the table namespace + * @param table the table name + * @param columnName the name of the new column + * @param columnType the type of the new column + * @param encrypted whether the new column should be encrypted + * @param ifNotExists if set to true, the column will be added only if it does not exist already. + * If set to false, it will throw an exception if it already exists + * @throws IllegalArgumentException if the table does not exist + * @throws ExecutionException if the operation fails + */ + default void addNewColumnToTable( + String namespace, + String table, + String columnName, + DataType columnType, + boolean encrypted, + boolean ifNotExists) + throws ExecutionException { + if (encrypted) { + throw new UnsupportedOperationException(CoreError.ENCRYPTION_NOT_ENABLED.buildMessage()); + } + TableMetadata tableMetadata = getTableMetadata(namespace, table); + if (tableMetadata == null) { + throw new IllegalArgumentException( + CoreError.TABLE_NOT_FOUND.buildMessage(ScalarDbUtils.getFullTableName(namespace, table))); + } + if (ifNotExists && tableMetadata.getColumnNames().contains(columnName)) { + return; + } + addNewColumnToTable(namespace, table, columnName, columnType); + } + /** * Imports an existing table that is not managed by ScalarDB. * diff --git a/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java b/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java index 29849b2536..9724fc937d 100644 --- a/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java +++ b/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java @@ -195,6 +195,19 @@ public void addNewColumnToTable( namespace, table, columnName, columnType, encrypted); } + @Override + public void addNewColumnToTable( + String namespace, + String table, + String columnName, + DataType columnType, + boolean encrypted, + boolean ifNotExists) + throws ExecutionException { + distributedTransactionAdmin.addNewColumnToTable( + namespace, table, columnName, columnType, encrypted, ifNotExists); + } + @Override public void importTable(String namespace, String table, Map options) throws ExecutionException { diff --git a/integration-test/src/main/java/com/scalar/db/api/DistributedStorageAdminIntegrationTestBase.java b/integration-test/src/main/java/com/scalar/db/api/DistributedStorageAdminIntegrationTestBase.java index 595558b146..761555cc4b 100644 --- a/integration-test/src/main/java/com/scalar/db/api/DistributedStorageAdminIntegrationTestBase.java +++ b/integration-test/src/main/java/com/scalar/db/api/DistributedStorageAdminIntegrationTestBase.java @@ -1010,6 +1010,19 @@ public void addNewColumnToTable_ForAlreadyExistingColumn_ShouldThrowIllegalArgum .isInstanceOf(IllegalArgumentException.class); } + @Test + public void + addNewColumnToTable_IfNotExists_ForAlreadyExistingColumn_ShouldNotThrowAnyException() { + // Arrange + + // Act Assert + assertThatCode( + () -> + admin.addNewColumnToTable( + namespace1, getTable1(), getColumnName7(), DataType.TEXT, false, true)) + .doesNotThrowAnyException(); + } + @Test public void upgrade_WhenMetadataTableExistsButNotNamespacesTable_ShouldCreateNamespacesTableAndImportExistingNamespaces() diff --git a/integration-test/src/main/java/com/scalar/db/api/DistributedTransactionAdminIntegrationTestBase.java b/integration-test/src/main/java/com/scalar/db/api/DistributedTransactionAdminIntegrationTestBase.java index bc040e9f0a..8fb7037a66 100644 --- a/integration-test/src/main/java/com/scalar/db/api/DistributedTransactionAdminIntegrationTestBase.java +++ b/integration-test/src/main/java/com/scalar/db/api/DistributedTransactionAdminIntegrationTestBase.java @@ -886,6 +886,19 @@ public void addNewColumnToTable_ForAlreadyExistingColumn_ShouldThrowIllegalArgum .isInstanceOf(IllegalArgumentException.class); } + @Test + public void + addNewColumnToTable_IfNotExists_ForAlreadyExistingColumn_ShouldNotThrowAnyException() { + // Arrange + + // Act Assert + assertThatCode( + () -> + admin.addNewColumnToTable( + namespace1, TABLE1, COL_NAME7, DataType.TEXT, false, true)) + .doesNotThrowAnyException(); + } + @Test public void createCoordinatorTables_ShouldCreateCoordinatorTablesCorrectly() throws ExecutionException {