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 50ad9453c8 IGNITE-20905 Make it possible to add an explicitly NULL column via ADD COLUMN 50ad9453c8 is described below commit 50ad9453c81b00147393e06e66d624a53aa46d93 Author: Max Zhuravkov <shh...@gmail.com> AuthorDate: Wed Jan 10 14:53:52 2024 +0200 IGNITE-20905 Make it possible to add an explicitly NULL column via ADD COLUMN --- .../internal/sql/engine/ItCreateTableDdlTest.java | 14 +++++ .../src/main/codegen/includes/parserImpls.ftl | 4 ++ .../prepare/ddl/DdlSqlToCommandConverter.java | 3 +- .../internal/sql/engine/sql/SqlDdlParserTest.java | 59 ++++++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java index 0f7ed762e5..f2548291cf 100644 --- a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java +++ b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java @@ -199,6 +199,20 @@ public class ItCreateTableDdlTest extends BaseSqlIntegrationTest { .check(); } + /** Test that adding nullable column via ALTER TABLE ADD name type NULL works. */ + @Test + public void testNullableColumn() { + sql("CREATE TABLE my (c1 INT PRIMARY KEY, c2 INT)"); + sql("INSERT INTO my VALUES (1, 1)"); + sql("ALTER TABLE my ADD COLUMN c3 INT NULL"); + sql("INSERT INTO my VALUES (2, 2, NULL)"); + + assertQuery("SELECT * FROM my ORDER by c1 ASC") + .returns(1, 1, null) + .returns(2, 2, null) + .check(); + } + /** * Adds columns of all supported types and checks that the row * created on the old schema version is read correctly. diff --git a/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl b/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl index ba18c9c40b..933c8c4789 100644 --- a/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl +++ b/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl @@ -378,6 +378,10 @@ SqlNode ColumnWithType() : <NOT> <NULL> { nullable = false; } + | + <NULL> { + nullable = true; + } ] ( <DEFAULT_> { s.add(this); } dflt = Literal() { diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java index 8455b69071..2e226debb0 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java @@ -390,7 +390,8 @@ public class DdlSqlToCommandConverter { assert col.name.isSimple(); - RelDataType relType = ctx.planner().convert(col.dataType, true); + Boolean nullable = col.dataType.getNullable(); + RelDataType relType = ctx.planner().convert(col.dataType, nullable != null ? nullable : true); DefaultValueDefinition dflt = convertDefault(col.expression, relType); String name = col.name.getSimple(); 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 340d00ab43..8c07f714ab 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 @@ -24,6 +24,8 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNull; import java.util.List; @@ -31,6 +33,7 @@ import java.util.Objects; import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; +import org.apache.calcite.schema.ColumnStrategy; import org.apache.calcite.sql.SqlBasicCall; import org.apache.calcite.sql.SqlIdentifier; import org.apache.calcite.sql.SqlKind; @@ -650,6 +653,51 @@ public class SqlDdlParserTest extends AbstractDdlParserTest { return (IgniteSqlCreateTable) node; } + @Test + public void alterTableAddColumn() { + SqlNode sqlNode = parse("ALTER TABLE t ADD COLUMN c INT"); + + IgniteSqlAlterTableAddColumn addColumn = assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode); + SqlColumnDeclaration declaration = (SqlColumnDeclaration) addColumn.columns().get(0); + + assertThat(addColumn.name.names, is(List.of("T"))); + + expectColumnBasic(declaration, "C", ColumnStrategy.NULLABLE, "INTEGER", true); + assertThat(declaration.expression, is(nullValue())); + + expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN \"C\" INTEGER"); + } + + @Test + public void alterTableAddColumnNull() { + SqlNode sqlNode = parse("ALTER TABLE t ADD COLUMN c INT NULL"); + + IgniteSqlAlterTableAddColumn addColumn = assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode); + SqlColumnDeclaration column = (SqlColumnDeclaration) addColumn.columns().get(0); + + assertThat(addColumn.name.names, is(List.of("T"))); + + expectColumnBasic(column, "C", ColumnStrategy.NULLABLE, "INTEGER", true); + assertThat(column.expression, is(nullValue())); + + expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN \"C\" INTEGER"); + } + + @Test + public void alterTableAddColumnNotNull() { + SqlNode sqlNode = parse("ALTER TABLE t ADD COLUMN c INT NOT NULL"); + + IgniteSqlAlterTableAddColumn addColumn = assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode); + SqlColumnDeclaration column = (SqlColumnDeclaration) addColumn.columns().get(0); + + assertThat(addColumn.name.names, is(List.of("T"))); + + expectColumnBasic(column, "C", ColumnStrategy.NOT_NULLABLE, "INTEGER", false); + assertThat(column.expression, is(nullValue())); + + expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN \"C\" INTEGER NOT NULL"); + } + /** * Matcher to verify name in the column declaration. * @@ -667,6 +715,17 @@ public class SqlDdlParserTest extends AbstractDdlParserTest { }; } + /** Checks basic column properties such as name, type name and type's nullability. */ + private static void expectColumnBasic(SqlColumnDeclaration declaration, + String columnName, ColumnStrategy columnStrategy, + String typeName, Boolean nullable) { + + assertThat(List.of(columnName), is(declaration.name.names)); + assertThat(columnStrategy, is(declaration.strategy)); + assertThat(List.of(typeName), is(declaration.dataType.getTypeName().names)); + assertThat(nullable, is(declaration.dataType.getNullable())); + } + private void assertThatOptionPresent(List<SqlNode> optionList, String option, Object expVal) { assertThat(optionList, hasItem(ofTypeMatching( option + "=" + expVal,