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 {