rpuch commented on code in PR #2493:
URL: https://github.com/apache/ignite-3/pull/2493#discussion_r1305249846


##########
modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogManagerImpl.java:
##########
@@ -947,14 +836,45 @@ private static void 
ensureNoTableOrIndexExistsWithSameName(CatalogSchemaDescript
     }
 
     private static void validateIndexColumns(CatalogTableDescriptor table, 
AbstractCreateIndexCommandParams params) {
-        for (String indexColumn : params.columns()) {
-            if (table.columnDescriptor(indexColumn) == null) {
-                throw new ColumnNotFoundException(indexColumn);
-            }
-        }
+        validateColumnsExistsInTable(table, params.columns());
 
         if (params.unique() && 
!params.columns().containsAll(table.colocationColumns())) {
             throw new IgniteException(Index.INVALID_INDEX_DEFINITION_ERR, 
"Unique index must include all colocation columns");
         }
     }
+
+    private static void ensureColumnCanBeDropped(
+            CatalogSchemaDescriptor schema,
+            CatalogTableDescriptor table,
+            AlterTableDropColumnParams params
+    ) {
+        validateColumnsExistsInTable(table, params.columns());
+
+        List<String> inPrimaryKeyColumns = params.columns().stream()
+                .filter(table::isPrimaryKeyColumn)
+                .collect(toList());
+
+        if (!inPrimaryKeyColumns.isEmpty()) {
+            throw new IgniteException(Table.TABLE_DEFINITION_ERR, "Can't drop 
primary key columns: " + inPrimaryKeyColumns);
+        }
+
+        Arrays.stream(schema.indexes())
+                .filter(index -> index.tableId() == table.id())
+                .forEach(index -> params.columns().stream()
+                        .filter(index::hasColumn)
+                        .findAny()
+                        .ifPresent(columnName -> {
+                            throw new SqlException(

Review Comment:
   Special validation exception?



##########
modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogManagerImpl.java:
##########
@@ -947,14 +836,45 @@ private static void 
ensureNoTableOrIndexExistsWithSameName(CatalogSchemaDescript
     }
 
     private static void validateIndexColumns(CatalogTableDescriptor table, 
AbstractCreateIndexCommandParams params) {
-        for (String indexColumn : params.columns()) {
-            if (table.columnDescriptor(indexColumn) == null) {
-                throw new ColumnNotFoundException(indexColumn);
-            }
-        }
+        validateColumnsExistsInTable(table, params.columns());
 
         if (params.unique() && 
!params.columns().containsAll(table.colocationColumns())) {
             throw new IgniteException(Index.INVALID_INDEX_DEFINITION_ERR, 
"Unique index must include all colocation columns");
         }
     }
+
+    private static void ensureColumnCanBeDropped(
+            CatalogSchemaDescriptor schema,
+            CatalogTableDescriptor table,
+            AlterTableDropColumnParams params
+    ) {
+        validateColumnsExistsInTable(table, params.columns());
+
+        List<String> inPrimaryKeyColumns = params.columns().stream()
+                .filter(table::isPrimaryKeyColumn)
+                .collect(toList());
+
+        if (!inPrimaryKeyColumns.isEmpty()) {
+            throw new IgniteException(Table.TABLE_DEFINITION_ERR, "Can't drop 
primary key columns: " + inPrimaryKeyColumns);

Review Comment:
   Should not special validation exception be thrown here instead of a generic 
`IgniteException`?



##########
modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogManagerImpl.java:
##########
@@ -947,14 +836,45 @@ private static void 
ensureNoTableOrIndexExistsWithSameName(CatalogSchemaDescript
     }
 
     private static void validateIndexColumns(CatalogTableDescriptor table, 
AbstractCreateIndexCommandParams params) {
-        for (String indexColumn : params.columns()) {
-            if (table.columnDescriptor(indexColumn) == null) {
-                throw new ColumnNotFoundException(indexColumn);
-            }
-        }
+        validateColumnsExistsInTable(table, params.columns());
 
         if (params.unique() && 
!params.columns().containsAll(table.colocationColumns())) {
             throw new IgniteException(Index.INVALID_INDEX_DEFINITION_ERR, 
"Unique index must include all colocation columns");
         }
     }
+
+    private static void ensureColumnCanBeDropped(
+            CatalogSchemaDescriptor schema,
+            CatalogTableDescriptor table,
+            AlterTableDropColumnParams params
+    ) {
+        validateColumnsExistsInTable(table, params.columns());
+
+        List<String> inPrimaryKeyColumns = params.columns().stream()
+                .filter(table::isPrimaryKeyColumn)
+                .collect(toList());
+
+        if (!inPrimaryKeyColumns.isEmpty()) {
+            throw new IgniteException(Table.TABLE_DEFINITION_ERR, "Can't drop 
primary key columns: " + inPrimaryKeyColumns);
+        }
+
+        Arrays.stream(schema.indexes())
+                .filter(index -> index.tableId() == table.id())
+                .forEach(index -> params.columns().stream()
+                        .filter(index::hasColumn)
+                        .findAny()
+                        .ifPresent(columnName -> {
+                            throw new SqlException(
+                                    STMT_VALIDATION_ERR,
+                                    format("Can't drop indexed column: 
[columnName={}, indexName={}]", columnName, index.name()));
+                        }));
+    }
+
+    private static void validateColumnsExistsInTable(CatalogTableDescriptor 
table, Collection<String> columns) {

Review Comment:
   ```suggestion
       private static void validateColumnsExistInTable(CatalogTableDescriptor 
table, Collection<String> columns) {
   ```



##########
modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java:
##########
@@ -1938,19 +1622,81 @@ void testDropNotExistingIndex() {
         
assertThat(manager.dropIndex(DropIndexParams.builder().indexName(INDEX_NAME).build()),
 willThrowFast(IndexNotFoundException.class));
     }
 
-    private void createSomeTable(String tableName) {
-        CreateTableParams params = CreateTableParams.builder()
-                .schemaName(SCHEMA_NAME)
-                .tableName(tableName)
-                .zone(ZONE_NAME)
-                .columns(List.of(
-                        
ColumnParams.builder().name("key1").type(ColumnType.INT32).build(),
-                        
ColumnParams.builder().name("val1").type(ColumnType.INT32).build()
-                ))
-                .primaryKeyColumns(List.of("key1"))
-                .build();
+    @Test
+    void testDropNotExistingTable() {
+        assertThat(manager.dropTable(dropTableParams(TABLE_NAME)), 
willThrowFast(TableNotFoundException.class));
+    }
+
+    @Test
+    void testCreateTableWithAlreadyExistingName() {
+        assertThat(manager.createTable(simpleTable(TABLE_NAME)), 
willCompleteSuccessfully());
 
-        assertThat(manager.createTable(params), willCompleteSuccessfully());
+        assertThat(manager.createTable(simpleTable(TABLE_NAME)), 
willThrowFast(TableAlreadyExistsException.class));
+    }
+
+    @Test
+    void testCreateTableWithSameNameAsExistingIndex() {
+        assertThat(manager.createTable(simpleTable(TABLE_NAME)), 
willCompleteSuccessfully());
+        assertThat(manager.createIndex(simpleIndex()), 
willCompleteSuccessfully());
+
+        assertThat(manager.createTable(simpleTable(INDEX_NAME)), 
willThrowFast(IndexAlreadyExistsException.class));
+    }
+
+    @Test
+    void testDropColumnWithNotExistingTable() {
+        assertThat(manager.dropColumn(dropColumnParams("key")), 
willThrowFast(TableNotFoundException.class));
+    }
+
+    @Test
+    void testDropColumnWithMissingTableColumns() {
+        assertThat(manager.createTable(simpleTable(TABLE_NAME)), 
willCompleteSuccessfully());
+
+        assertThat(manager.dropColumn(dropColumnParams("fake")), 
willThrowFast(ColumnNotFoundException.class));
+    }
+
+    @Test
+    void testDropColumnWithPrimaryKeyColumns() {
+        assertThat(manager.createTable(simpleTable(TABLE_NAME)), 
willCompleteSuccessfully());
+
+        assertThat(
+                manager.dropColumn(dropColumnParams("ID")),
+                willThrowFast(IgniteException.class, "Can't drop primary key 
columns: [ID]")
+        );
+    }
+
+    @Test
+    void testDropColumnWithIndexColumns() {
+        assertThat(manager.createTable(simpleTable(TABLE_NAME)), 
willCompleteSuccessfully());
+        assertThat(manager.createIndex(simpleIndex()), 
willCompleteSuccessfully());
+
+        assertThat(
+                manager.dropColumn(dropColumnParams("VAL")),
+                willThrowFast(IgniteException.class, String.format("Can't drop 
indexed column: [columnName=VAL, indexName=%s]", INDEX_NAME))
+        );
+    }
+
+    @Test
+    void testAddColumnWithNotExistingTable() {
+        assertThat(manager.addColumn(addColumnParams(columnParams("key", 
INT32))), willThrowFast(TableNotFoundException.class));
+    }
+
+    @Test
+    void testAddColumnWithExistsColumn() {

Review Comment:
   ```suggestion
       void testAddColumnWithExistingName() {
   ```



##########
modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java:
##########
@@ -1631,123 +1446,6 @@ void testGetTableIdOnDropIndexEvent() {
         assertEquals(tableId, eventParameters.tableId());
     }
 
-    @Test
-    void testCreateTableErrors() {

Review Comment:
   Was this moved elsewhere?



##########
modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogParamsValidationUtils.java:
##########
@@ -206,25 +295,68 @@ private static void 
validateCommonCreateIndexParams(AbstractCreateIndexCommandPa
 
         validateNameField(params.tableName(), 
Index.INVALID_INDEX_DEFINITION_ERR, "Missing table name");
 
-        if (CollectionUtils.nullOrEmpty(params.columns())) {
-            throw new 
CatalogValidationException(Index.INVALID_INDEX_DEFINITION_ERR, "Columns not 
specified");
-        }
-
-        params.columns().stream()
-                .filter(Predicate.not(new HashSet<>()::add))
-                .findAny()
-                .ifPresent(columnName -> {
-                    throw new CatalogValidationException(
-                            Index.INVALID_INDEX_DEFINITION_ERR,
-                            "Duplicate columns are present: {}",
-                            params.columns()
-                    );
-                });
+        validateColumns(
+                params.columns(),
+                Index.INVALID_INDEX_DEFINITION_ERR,
+                "Columns not specified",
+                "Duplicate columns are present: {}"
+        );
     }
 
     private static void validateNameField(String name, int errorCode, String 
errorMessage) {
         if (StringUtils.nullOrBlank(name)) {
             throw new CatalogValidationException(errorCode, errorMessage);
         }
     }
+
+    private static void validateCollectionIsNotEmpty(Collection<?> collection, 
int errorCode, String errorMessage) {
+        if (CollectionUtils.nullOrEmpty(collection)) {
+            throw new CatalogValidationException(errorCode, errorMessage);
+        }
+    }
+
+    private static void validateColumns(
+            List<String> columns,
+            int errorCode,
+            String emptyColumnsErrorMessage,
+            String duplicateColumnsErrorMessageFormat
+    ) {
+        validateCollectionIsNotEmpty(columns, errorCode, 
emptyColumnsErrorMessage);
+
+        List<String> duplicates = columns.stream()
+                .filter(Predicate.not(new HashSet<>()::add))
+                .collect(toList());
+
+        if (!duplicates.isEmpty()) {
+            throw new CatalogValidationException(errorCode, 
duplicateColumnsErrorMessageFormat, duplicates);
+        }
+    }
+
+    private static void validateColumnsContainsInAnotherColumns(
+            List<String> columns,

Review Comment:
   I suggest to rename `columns` to `columnsToCheck` to make it easier to see 
what is being validated and what is the context of the validation



##########
modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateTableParams.java:
##########
@@ -113,8 +99,9 @@ public Builder primaryKeyColumns(List<String> pkCols) {
          *
          * @param colocationCols Colocation column names.
          * @return {@code this}.
+         * @throws NullPointerException If the colocation column names is 
{@code null} or one of its elements.
          */
-        public Builder colocationColumns(@Nullable List<String> 
colocationCols) {
+        public Builder colocationColumns(List<String> colocationCols) {
             params.colocationCols = colocationCols;

Review Comment:
   Let's add a defensive copy here as well



##########
modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogParamsValidationUtils.java:
##########
@@ -206,25 +295,68 @@ private static void 
validateCommonCreateIndexParams(AbstractCreateIndexCommandPa
 
         validateNameField(params.tableName(), 
Index.INVALID_INDEX_DEFINITION_ERR, "Missing table name");
 
-        if (CollectionUtils.nullOrEmpty(params.columns())) {
-            throw new 
CatalogValidationException(Index.INVALID_INDEX_DEFINITION_ERR, "Columns not 
specified");
-        }
-
-        params.columns().stream()
-                .filter(Predicate.not(new HashSet<>()::add))
-                .findAny()
-                .ifPresent(columnName -> {
-                    throw new CatalogValidationException(
-                            Index.INVALID_INDEX_DEFINITION_ERR,
-                            "Duplicate columns are present: {}",
-                            params.columns()
-                    );
-                });
+        validateColumns(
+                params.columns(),
+                Index.INVALID_INDEX_DEFINITION_ERR,
+                "Columns not specified",
+                "Duplicate columns are present: {}"
+        );
     }
 
     private static void validateNameField(String name, int errorCode, String 
errorMessage) {
         if (StringUtils.nullOrBlank(name)) {
             throw new CatalogValidationException(errorCode, errorMessage);
         }
     }
+
+    private static void validateCollectionIsNotEmpty(Collection<?> collection, 
int errorCode, String errorMessage) {
+        if (CollectionUtils.nullOrEmpty(collection)) {
+            throw new CatalogValidationException(errorCode, errorMessage);
+        }
+    }
+
+    private static void validateColumns(
+            List<String> columns,
+            int errorCode,
+            String emptyColumnsErrorMessage,
+            String duplicateColumnsErrorMessageFormat
+    ) {
+        validateCollectionIsNotEmpty(columns, errorCode, 
emptyColumnsErrorMessage);
+
+        List<String> duplicates = columns.stream()
+                .filter(Predicate.not(new HashSet<>()::add))
+                .collect(toList());
+
+        if (!duplicates.isEmpty()) {
+            throw new CatalogValidationException(errorCode, 
duplicateColumnsErrorMessageFormat, duplicates);
+        }
+    }
+
+    private static void validateColumnsContainsInAnotherColumns(
+            List<String> columns,
+            List<String> anotherColumns,
+            int errorCode,
+            String errorMessageFormat
+    ) {
+        List<String> notContains = columns.stream()

Review Comment:
   `notContained`



##########
modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogParamsValidationUtils.java:
##########
@@ -206,25 +295,68 @@ private static void 
validateCommonCreateIndexParams(AbstractCreateIndexCommandPa
 
         validateNameField(params.tableName(), 
Index.INVALID_INDEX_DEFINITION_ERR, "Missing table name");
 
-        if (CollectionUtils.nullOrEmpty(params.columns())) {
-            throw new 
CatalogValidationException(Index.INVALID_INDEX_DEFINITION_ERR, "Columns not 
specified");
-        }
-
-        params.columns().stream()
-                .filter(Predicate.not(new HashSet<>()::add))
-                .findAny()
-                .ifPresent(columnName -> {
-                    throw new CatalogValidationException(
-                            Index.INVALID_INDEX_DEFINITION_ERR,
-                            "Duplicate columns are present: {}",
-                            params.columns()
-                    );
-                });
+        validateColumns(
+                params.columns(),
+                Index.INVALID_INDEX_DEFINITION_ERR,
+                "Columns not specified",
+                "Duplicate columns are present: {}"
+        );
     }
 
     private static void validateNameField(String name, int errorCode, String 
errorMessage) {
         if (StringUtils.nullOrBlank(name)) {
             throw new CatalogValidationException(errorCode, errorMessage);
         }
     }
+
+    private static void validateCollectionIsNotEmpty(Collection<?> collection, 
int errorCode, String errorMessage) {
+        if (CollectionUtils.nullOrEmpty(collection)) {
+            throw new CatalogValidationException(errorCode, errorMessage);
+        }
+    }
+
+    private static void validateColumns(
+            List<String> columns,
+            int errorCode,
+            String emptyColumnsErrorMessage,
+            String duplicateColumnsErrorMessageFormat
+    ) {
+        validateCollectionIsNotEmpty(columns, errorCode, 
emptyColumnsErrorMessage);
+
+        List<String> duplicates = columns.stream()
+                .filter(Predicate.not(new HashSet<>()::add))
+                .collect(toList());
+
+        if (!duplicates.isEmpty()) {
+            throw new CatalogValidationException(errorCode, 
duplicateColumnsErrorMessageFormat, duplicates);
+        }
+    }
+
+    private static void validateColumnsContainsInAnotherColumns(

Review Comment:
   ```suggestion
       private static void validateColumnsAreContainedInAnotherColumns(
   ```



##########
modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateTableParams.java:
##########
@@ -20,67 +20,51 @@
 import java.util.List;
 import org.jetbrains.annotations.Nullable;
 
-/**
- * CREATE TABLE statement.
- */
+/** CREATE TABLE statement. */
 public class CreateTableParams extends AbstractTableCommandParams {
     /** Creates parameters builder. */
     public static Builder builder() {
         return new Builder();
     }
 
+    private CreateTableParams() {
+        // No-op.
+    }
+
     /** Primary key columns. */
-    @Nullable
     private List<String> pkCols;
 
     /** Colocation columns. */
-    @Nullable
     private List<String> colocationCols;
 
-    /** Columns. */
-    private List<ColumnParams> cols;
+    /** Columns, {@code null} if not set. */
+    private @Nullable List<ColumnParams> cols;

Review Comment:
   When can it be null? Is it possible to create a table without any columns?



##########
modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerValidationTest.java:
##########
@@ -685,4 +854,17 @@ private static AlterZoneParams alterZoneParams(@Nullable 
Integer autoAdjust, @Nu
                 .dataNodesAutoAdjustScaleDown(scaleDown)
                 .build();
     }
+
+    private CreateTableParams simpleTableParamsWithoutPrimaryKeys(@Nullable 
List<String> primaryKeys) {

Review Comment:
   ```suggestion
       private CreateTableParams simpleTableParamsWithPrimaryKeys(@Nullable 
List<String> primaryKeys) {
   ```



##########
modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerValidationTest.java:
##########
@@ -685,4 +854,17 @@ private static AlterZoneParams alterZoneParams(@Nullable 
Integer autoAdjust, @Nu
                 .dataNodesAutoAdjustScaleDown(scaleDown)
                 .build();
     }
+
+    private CreateTableParams simpleTableParamsWithoutPrimaryKeys(@Nullable 
List<String> primaryKeys) {
+        return createTableParams(TABLE_NAME, List.of(columnParams("key", 
INT32), columnParams("val", INT64)), primaryKeys, null);
+    }
+
+    private CreateTableParams 
simpleTableParamsWithoutColocationColumns(@Nullable List<String> 
colocationColumns) {

Review Comment:
   ```suggestion
       private CreateTableParams 
simpleTableParamsWithColocationColumns(@Nullable List<String> 
colocationColumns) {
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to