This is an automated email from the ASF dual-hosted git repository.
korlov 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 4fafbd01162 IGNITE-28040 Improve test coverage for alter table add
columns (#7725)
4fafbd01162 is described below
commit 4fafbd01162a230e89d94371908d3d747542c148
Author: Ivan Zlenko <[email protected]>
AuthorDate: Wed Mar 11 11:54:15 2026 +0500
IGNITE-28040 Improve test coverage for alter table add columns (#7725)
---
.../ignite/internal/catalog/CatalogTableTest.java | 417 +++++++++++++++++++++
.../internal/sql/engine/sql/SqlDdlParserTest.java | 188 ++++++++++
2 files changed, 605 insertions(+)
diff --git
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogTableTest.java
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogTableTest.java
index 8d9f6d1d876..090e38fd8b4 100644
---
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogTableTest.java
+++
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogTableTest.java
@@ -83,11 +83,14 @@ import it.unimi.dsi.fastutil.ints.IntList;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.function.Supplier;
+import org.apache.ignite.internal.catalog.commands.AlterTableAddColumnCommand;
import
org.apache.ignite.internal.catalog.commands.AlterTableAlterColumnCommand;
import
org.apache.ignite.internal.catalog.commands.AlterTableAlterColumnCommandBuilder;
+import org.apache.ignite.internal.catalog.commands.AlterTableDropColumnCommand;
import
org.apache.ignite.internal.catalog.commands.AlterTableSetPropertyCommand;
import org.apache.ignite.internal.catalog.commands.CatalogUtils;
import org.apache.ignite.internal.catalog.commands.ColumnParams;
@@ -513,6 +516,79 @@ public class CatalogTableTest extends
BaseCatalogManagerTest {
);
}
+ @Test
+ public void testDropMultipleColumns() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogTableDescriptor tableBefore = actualTable(TABLE_NAME);
+ int colCountBefore = tableBefore.columns().size();
+
+ tryApplyAndExpectApplied(dropColumnParams(TABLE_NAME, "VAL", "DEC",
"STR"));
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+
+ assertNull(table.column("VAL"));
+ assertNull(table.column("DEC"));
+ assertNull(table.column("STR"));
+ assertEquals(colCountBefore - 3, table.columns().size());
+ }
+
+ @Test
+ public void testDropMultipleColumnsWithMissingColumn() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ assertThat(
+ manager.execute(dropColumnParams(TABLE_NAME, "VAL", "fake")),
+ willThrowFast(CatalogValidationException.class, "Column with
name 'fake' not found in table 'PUBLIC.test_table'.")
+ );
+
+ // Validate no column was dropped.
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table.column("VAL"));
+ }
+
+ @Test
+ public void testDropMultipleColumnsWithPrimaryKeyColumn() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ assertThat(
+ manager.execute(dropColumnParams(TABLE_NAME, "VAL", "ID")),
+ willThrowFast(CatalogValidationException.class, "Deleting
column `ID` belonging to primary key is not allowed")
+ );
+
+ // Validate no column was dropped.
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table.column("VAL"));
+ assertNotNull(table.column("ID"));
+ }
+
+ @Test
+ public void testDropMultipleColumnsWithIndexColumn() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+ tryApplyAndExpectApplied(simpleIndex());
+
+ assertThat(
+ manager.execute(dropColumnParams(TABLE_NAME, "VAL", "DEC")),
+ willThrowFast(
+ CatalogValidationException.class,
+ "Deleting column 'VAL' used by index(es) [myIndex], it
is not allowed"
+ )
+ );
+
+ // Validate no column was dropped.
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table.column("VAL"));
+ assertNotNull(table.column("DEC"));
+ }
+
+ @Test
+ public void testDropMultipleColumnsFromNonExistingTable() {
+ assertThat(
+ manager.execute(dropColumnParams(TABLE_NAME, "VAL", "DEC")),
+ willThrowFast(CatalogValidationException.class, "Table with
name 'PUBLIC.test_table' not found.")
+ );
+ }
+
@Test
public void testAddColumnWithNotExistingTable() {
assertThat(manager.execute(addColumnParams(TABLE_NAME,
columnParams("key", INT32, true))),
@@ -1534,6 +1610,347 @@ public class CatalogTableTest extends
BaseCatalogManagerTest {
}
}
+ @Test
+ public void testAddMultipleColumnsAssignsSequentialIds() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogTableDescriptor tableBefore = actualTable(TABLE_NAME);
+ assertNotNull(tableBefore);
+ int maxId =
tableBefore.columns().stream().mapToInt(CatalogTableColumnDescriptor::id).max().orElse(0);
+
+ tryApplyAndExpectApplied(addColumnParams(TABLE_NAME,
+ columnParams("COL_A", INT32, true),
+ columnParams("COL_B", STRING, 100, true),
+ columnParams("COL_C", DECIMAL, true, DFLT_TEST_PRECISION, 2)
+ ));
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table);
+ assertEquals(maxId + 1, table.column("COL_A").id());
+ assertEquals(maxId + 2, table.column("COL_B").id());
+ assertEquals(maxId + 3, table.column("COL_C").id());
+ }
+
+ @Test
+ public void testAddMultipleColumnsPreservesProperties() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ tryApplyAndExpectApplied(addColumnParams(TABLE_NAME,
+ columnParamsBuilder("COL_INT", INT32,
true).defaultValue(constant(42)).build(),
+ columnParamsBuilder("COL_STR",
STRING).length(200).defaultValue(constant("hello")).build(),
+ columnParams("COL_DEC", DECIMAL, true, 15, 5)
+ ));
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table);
+
+ CatalogTableColumnDescriptor colInt = table.column("COL_INT");
+ assertNotNull(colInt);
+ assertEquals(INT32, colInt.type());
+ assertTrue(colInt.nullable());
+ assertEquals(constant(42), colInt.defaultValue());
+
+ CatalogTableColumnDescriptor colStr = table.column("COL_STR");
+ assertNotNull(colStr);
+ assertEquals(STRING, colStr.type());
+ assertEquals(200, colStr.length());
+ assertEquals(constant("hello"), colStr.defaultValue());
+
+ CatalogTableColumnDescriptor colDec = table.column("COL_DEC");
+ assertNotNull(colDec);
+ assertEquals(DECIMAL, colDec.type());
+ assertTrue(colDec.nullable());
+ assertEquals(15, colDec.precision());
+ assertEquals(5, colDec.scale());
+ }
+
+ @Test
+ public void testAddMultipleColumnsPreservesOrder() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ tryApplyAndExpectApplied(addColumnParams(TABLE_NAME,
+ columnParams("COL_A", INT32, true),
+ columnParams("COL_B", INT32, true),
+ columnParams("COL_C", INT32, true)
+ ));
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table);
+ List<CatalogTableColumnDescriptor> columns = table.columns();
+
+ // simpleTable creates 6 columns, new ones should be at indices 6, 7, 8
+ assertEquals("COL_A", columns.get(6).name());
+ assertEquals("COL_B", columns.get(7).name());
+ assertEquals("COL_C", columns.get(8).name());
+
+ assertEquals(6, table.columnIndex("COL_A"));
+ assertEquals(7, table.columnIndex("COL_B"));
+ assertEquals(8, table.columnIndex("COL_C"));
+ }
+
+ @Test
+ public void testAddMultipleColumnsIncrementsTableVersionOnce() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogTableDescriptor tableBefore = actualTable(TABLE_NAME);
+ assertNotNull(tableBefore);
+ assertEquals(1, tableBefore.latestSchemaVersion());
+
+ tryApplyAndExpectApplied(addColumnParams(TABLE_NAME,
+ columnParams("COL_A", INT32, true),
+ columnParams("COL_B", INT32, true),
+ columnParams("COL_C", INT32, true)
+ ));
+
+ CatalogTableDescriptor tableAfter = actualTable(TABLE_NAME);
+ assertNotNull(tableAfter);
+ assertEquals(2, tableAfter.latestSchemaVersion());
+ }
+
+ @Test
+ public void testAddMultipleColumnsTimeTravelVisibility() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ long timestampBeforeAdd = clock.nowLong();
+
+ tryApplyAndExpectApplied(addColumnParams(TABLE_NAME,
+ columnParams("COL_A", INT32, true),
+ columnParams("COL_B", INT32, true)
+ ));
+
+ // At the old timestamp, the new columns should not be visible.
+ CatalogTableDescriptor oldTable =
manager.activeCatalog(timestampBeforeAdd).table(SCHEMA_NAME, TABLE_NAME);
+ assertNotNull(oldTable);
+ assertNull(oldTable.column("COL_A"));
+ assertNull(oldTable.column("COL_B"));
+
+ // At the latest timestamp, the new columns should be visible.
+ CatalogTableDescriptor newTable = actualTable(TABLE_NAME);
+ assertNotNull(newTable);
+ assertNotNull(newTable.column("COL_A"));
+ assertNotNull(newTable.column("COL_B"));
+ }
+
+ @Test
+ public void testAddMultipleColumnsFiresEventWithAllColumns() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ var fireEventFuture = new CompletableFuture<Void>();
+
+ manager.listen(CatalogEvent.TABLE_ALTER, fromConsumer(fireEventFuture,
(AddColumnEventParameters parameters) -> {
+ List<CatalogTableColumnDescriptor> descriptors =
parameters.descriptors();
+
+ assertThat(descriptors, hasSize(2));
+ assertEquals("COL_A", descriptors.get(0).name());
+ assertEquals("COL_B", descriptors.get(1).name());
+ }));
+
+ tryApplyAndExpectApplied(addColumnParams(TABLE_NAME,
+ columnParams("COL_A", INT32, true),
+ columnParams("COL_B", INT32, true)
+ ));
+
+ assertThat(fireEventFuture, willCompleteSuccessfully());
+ }
+
+ @Test
+ public void testAddSingleColumnIfNotExistsColumnExists() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableAddColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(List.of(columnParams("VAL", INT32, true)))
+ .ifColumnNotExists(true)
+ .build();
+
+ tryApplyAndExpectNotApplied(command);
+ }
+
+ @Test
+ public void testAddSingleColumnIfNotExistsColumnDoesNotExist() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableAddColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(List.of(columnParams(NEW_COLUMN_NAME, INT32, true)))
+ .ifColumnNotExists(true)
+ .build();
+
+ tryApplyAndExpectApplied(command);
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table);
+ assertNotNull(table.column(NEW_COLUMN_NAME));
+ }
+
+ @Test
+ public void testAddMultipleColumnsIfNotExistsAllNew() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableAddColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(List.of(
+ columnParams(NEW_COLUMN_NAME, INT32, true),
+ columnParams(NEW_COLUMN_NAME_2, INT32, true)
+ ))
+ .ifColumnNotExists(true)
+ .build();
+
+ tryApplyAndExpectApplied(command);
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table);
+ assertNotNull(table.column(NEW_COLUMN_NAME));
+ assertNotNull(table.column(NEW_COLUMN_NAME_2));
+ }
+
+ @Test
+ public void testAddMultipleColumnsIfNotExistsPartialOverlap() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableAddColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(List.of(
+ columnParams("VAL", INT32, true),
+ columnParams(NEW_COLUMN_NAME, INT32, true)
+ ))
+ .ifColumnNotExists(true)
+ .build();
+
+ tryApplyAndExpectApplied(command);
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table);
+ assertNotNull(table.column(NEW_COLUMN_NAME));
+ // VAL should still have its original type (INT32) and be unchanged.
+ assertNotNull(table.column("VAL"));
+ }
+
+ @Test
+ public void testAddMultipleColumnsIfNotExistsAllExist() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableAddColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(List.of(
+ columnParams("VAL", INT32, true),
+ columnParams("STR", STRING, 100, true)
+ ))
+ .ifColumnNotExists(true)
+ .build();
+
+ tryApplyAndExpectNotApplied(command);
+ }
+
+ @Test
+ public void testAddMultipleColumnsFailsAtomicallyWhenOneAlreadyExists() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ // Try to add columns where "VAL" already exists — without
ifColumnNotExists, this should fail.
+ assertThat(
+ manager.execute(addColumnParams(TABLE_NAME,
+ columnParams(NEW_COLUMN_NAME, INT32, true),
+ columnParams("VAL", INT32, true)
+ )),
+ willThrow(CatalogValidationException.class)
+ );
+
+ // Verify NEWCOL was NOT added (atomic rollback).
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNotNull(table);
+ assertNull(table.column(NEW_COLUMN_NAME));
+ }
+
+ @Test
+ public void testDropMultipleColumnsIfExistsAllExist() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableDropColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(Set.of("VAL", "DEC"))
+ .ifColumnExists(true)
+ .build();
+
+ tryApplyAndExpectApplied(command);
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNull(table.column("VAL"));
+ assertNull(table.column("DEC"));
+ }
+
+ @Test
+ public void testDropMultipleColumnsIfExistsPartialOverlap() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableDropColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(Set.of("VAL", "fake"))
+ .ifColumnExists(true)
+ .build();
+
+ tryApplyAndExpectApplied(command);
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNull(table.column("VAL"));
+ }
+
+ @Test
+ public void testDropMultipleColumnsIfExistsNoneExist() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableDropColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(Set.of("fake1", "fake2"))
+ .ifColumnExists(true)
+ .build();
+
+ tryApplyAndExpectNotApplied(command);
+ }
+
+ @Test
+ public void testDropSingleColumnIfExists() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableDropColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(Set.of("fake"))
+ .ifColumnExists(true)
+ .build();
+
+ tryApplyAndExpectNotApplied(command);
+
+ // Verify table is unchanged.
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertEquals(6, table.columns().size());
+ }
+
+ @Test
+ public void testDropSingleColumnIfExistsColumnExists() {
+ tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
+
+ CatalogCommand command = AlterTableDropColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(TABLE_NAME)
+ .columns(Set.of("VAL"))
+ .ifColumnExists(true)
+ .build();
+
+ tryApplyAndExpectApplied(command);
+
+ CatalogTableDescriptor table = actualTable(TABLE_NAME);
+ assertNull(table.column("VAL"));
+ assertEquals(5, table.columns().size());
+ }
+
private @Nullable CatalogTableDescriptor actualTable(String tableName) {
return manager.activeCatalog(clock.nowLong()).table(SCHEMA_NAME,
tableName);
}
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
index 3eb7745d6fa..3b3914d47d8 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
@@ -796,6 +796,87 @@ public class SqlDdlParserTest extends AbstractParserTest {
() -> parse(stmt));
}
+ @ParameterizedTest
+ @CsvSource(delimiter = ';', value = {
+ // ADD COLUMN missing column definition
+ "alter table t add column;"
+ + " Failed to parse query: Encountered \"<EOF>\" at line
1, column 24",
+ "alter table t add;"
+ + " Failed to parse query: Encountered \"<EOF>\" at line
1, column 17",
+ "alter table t add column if not exists;"
+ + " Failed to parse query: Encountered \"<EOF>\" at line
1, column 38",
+ "alter table t add if not exists;"
+ + " Failed to parse query: Encountered \"<EOF>\" at line
1, column 31",
+
+ // ADD COLUMN with wrong IF EXISTS (should be IF NOT EXISTS)
+ "alter table t add column if exists c int;"
+ + " Failed to parse query: Encountered \"exists\" at line
1, column 29",
+ "alter table if exists t add column if exists c int;"
+ + " Failed to parse query: Encountered \"exists\" at line
1, column 39",
+
+ // DROP COLUMN missing column name
+ "alter table t drop column;"
+ + " Failed to parse query: Encountered \"<EOF>\" at line
1, column 25",
+ "alter table t drop;"
+ + " Failed to parse query: Encountered \"<EOF>\" at line
1, column 18",
+ "alter table t drop column if exists;"
+ + " Failed to parse query: Encountered \"<EOF>\" at line
1, column 35",
+ "alter table t drop if exists;"
+ + " Failed to parse query: Encountered \"<EOF>\" at line
1, column 28",
+
+ // DROP COLUMN with wrong IF NOT EXISTS (should be IF EXISTS)
+ "alter table t drop column if not exists c;"
+ + " Failed to parse query: Encountered \"not\" at line 1,
column 30",
+ "alter table if exists t drop column if not exists c;"
+ + " Failed to parse query: Encountered \"not\" at line 1,
column 40",
+
+ // ADD single column with reserved word as name
+ "alter table t add column select int;"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 26",
+ "alter table t add select int;"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 19",
+ "alter table t add column if not exists select int;"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 40",
+
+ // ADD multiple columns with reserved word as name
+ "alter table t add column (select int, b varchar);"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 27",
+ "alter table t add column (a int, select varchar);"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 34",
+ "alter table t add column if not exists (select int, b varchar);"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 41",
+ "alter table t add (select int, b varchar);"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 20",
+
+ // ADD column with missing type
+ "alter table t add column a;"
+ + " Failed to parse query: Encountered \"<EOF>\" at line
1, column 26",
+ "alter table t add column (a, b varchar);"
+ + " Failed to parse query: Encountered \",\" at line 1,
column 28",
+ "alter table t add column (a int, b);"
+ + " Failed to parse query: Encountered \")\" at line 1,
column 35",
+
+ // DROP column with reserved word as name
+ "alter table t drop column select;"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 27",
+ "alter table t drop select;"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 20",
+ "alter table t drop column if exists select;"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 37",
+
+ // DROP multiple columns with reserved word as name
+ "alter table t drop column (select, b);"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 28",
+ "alter table t drop column (a, select);"
+ + " Failed to parse query: Encountered \"select\" at line
1, column 31",
+ })
+ public void alterTableAddDropColumnParsingErrors(String stmt, String
error) {
+ assertThrowsSqlException(
+ Sql.STMT_PARSE_ERR,
+ error,
+ () -> parse(stmt));
+ }
+
@Test
public void createIndexSimpleCase() {
var query = "create index my_index on my_table (col)";
@@ -1169,6 +1250,113 @@ public class SqlDdlParserTest extends
AbstractParserTest {
expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN \"C\" INTEGER
NOT NULL");
}
+ @Test
+ public void alterTableAddMultipleColumns() {
+ SqlNode sqlNode = parse("ALTER TABLE t ADD COLUMN (a INT, b VARCHAR, c
DECIMAL(10, 2))");
+
+ IgniteSqlAlterTableAddColumn addColumn =
assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode);
+
+ assertThat(addColumn.name.names, is(List.of("T")));
+ assertThat(addColumn.ifColumnNotExists(), is(false));
+ assertThat(addColumn.columns().size(), is(3));
+
+ SqlColumnDeclaration col0 = (SqlColumnDeclaration)
addColumn.columns().get(0);
+ SqlColumnDeclaration col1 = (SqlColumnDeclaration)
addColumn.columns().get(1);
+ SqlColumnDeclaration col2 = (SqlColumnDeclaration)
addColumn.columns().get(2);
+
+ expectColumnBasic(col0, "A", ColumnStrategy.NULLABLE, "INTEGER", true);
+ expectColumnBasic(col1, "B", ColumnStrategy.NULLABLE, "VARCHAR", true);
+ expectColumnBasic(col2, "C", ColumnStrategy.NULLABLE, "DECIMAL", true);
+
+ expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN \"A\" INTEGER,
\"B\" VARCHAR, \"C\" DECIMAL(10, 2)");
+ }
+
+ @Test
+ public void alterTableAddMultipleColumnsIfNotExists() {
+ SqlNode sqlNode = parse("ALTER TABLE t ADD COLUMN IF NOT EXISTS (a
INT, b VARCHAR NOT NULL)");
+
+ IgniteSqlAlterTableAddColumn addColumn =
assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode);
+
+ assertThat(addColumn.name.names, is(List.of("T")));
+ assertThat(addColumn.ifColumnNotExists(), is(true));
+ assertThat(addColumn.columns().size(), is(2));
+
+ SqlColumnDeclaration col0 = (SqlColumnDeclaration)
addColumn.columns().get(0);
+ SqlColumnDeclaration col1 = (SqlColumnDeclaration)
addColumn.columns().get(1);
+
+ expectColumnBasic(col0, "A", ColumnStrategy.NULLABLE, "INTEGER", true);
+ expectColumnBasic(col1, "B", ColumnStrategy.NOT_NULLABLE, "VARCHAR",
false);
+
+ expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN IF NOT EXISTS
\"A\" INTEGER, \"B\" VARCHAR NOT NULL");
+ }
+
+ @Test
+ public void alterTableAddMultipleColumnsWithDefaults() {
+ SqlNode sqlNode = parse("ALTER TABLE t ADD COLUMN (a INT DEFAULT 1, b
VARCHAR DEFAULT 'hello')");
+
+ IgniteSqlAlterTableAddColumn addColumn =
assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode);
+
+ assertThat(addColumn.columns().size(), is(2));
+
+ SqlColumnDeclaration col0 = (SqlColumnDeclaration)
addColumn.columns().get(0);
+ SqlColumnDeclaration col1 = (SqlColumnDeclaration)
addColumn.columns().get(1);
+
+ assertNotNull(col0.expression);
+ assertNotNull(col1.expression);
+
+ expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN \"A\" INTEGER
DEFAULT (1), \"B\" VARCHAR DEFAULT ('hello')");
+ }
+
+ @Test
+ public void alterTableAddMultipleColumnsWithoutColumnKeyword() {
+ SqlNode sqlNode = parse("ALTER TABLE t ADD (a INT, b VARCHAR)");
+
+ IgniteSqlAlterTableAddColumn addColumn =
assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode);
+
+ assertThat(addColumn.name.names, is(List.of("T")));
+ assertThat(addColumn.columns().size(), is(2));
+
+ SqlColumnDeclaration col0 = (SqlColumnDeclaration)
addColumn.columns().get(0);
+ SqlColumnDeclaration col1 = (SqlColumnDeclaration)
addColumn.columns().get(1);
+
+ expectColumnBasic(col0, "A", ColumnStrategy.NULLABLE, "INTEGER", true);
+ expectColumnBasic(col1, "B", ColumnStrategy.NULLABLE, "VARCHAR", true);
+
+ expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN \"A\" INTEGER,
\"B\" VARCHAR");
+ }
+
+ @Test
+ public void alterTableAddMultipleColumnsWithoutColumnKeywordIfNotExists() {
+ SqlNode sqlNode = parse("ALTER TABLE t ADD IF NOT EXISTS (a INT, b
VARCHAR)");
+
+ IgniteSqlAlterTableAddColumn addColumn =
assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode);
+
+ assertThat(addColumn.name.names, is(List.of("T")));
+ assertThat(addColumn.ifColumnNotExists(), is(true));
+ assertThat(addColumn.columns().size(), is(2));
+
+ SqlColumnDeclaration col0 = (SqlColumnDeclaration)
addColumn.columns().get(0);
+ SqlColumnDeclaration col1 = (SqlColumnDeclaration)
addColumn.columns().get(1);
+
+ expectColumnBasic(col0, "A", ColumnStrategy.NULLABLE, "INTEGER", true);
+ expectColumnBasic(col1, "B", ColumnStrategy.NULLABLE, "VARCHAR", true);
+
+ expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN IF NOT EXISTS
\"A\" INTEGER, \"B\" VARCHAR");
+ }
+
+ @Test
+ public void alterTableAddMultipleColumnsIfTableExists() {
+ SqlNode sqlNode = parse("ALTER TABLE IF EXISTS t ADD COLUMN (a INT, b
VARCHAR)");
+
+ IgniteSqlAlterTableAddColumn addColumn =
assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode);
+
+ assertThat(addColumn.name.names, is(List.of("T")));
+ assertThat(addColumn.ifExists(), is(true));
+ assertThat(addColumn.columns().size(), is(2));
+
+ expectUnparsed(addColumn, "ALTER TABLE IF EXISTS \"T\" ADD COLUMN
\"A\" INTEGER, \"B\" VARCHAR");
+ }
+
@Test
public void alterTableDropColumn() {
SqlNode sqlNode = parse("ALTER TABLE t DROP COLUMN c");