This is an automated email from the ASF dual-hosted git repository.

ppa 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 b0e37f0b316 IGNITE-27730 Sql. Add validation that a not null column 
must have a default value (#7640)
b0e37f0b316 is described below

commit b0e37f0b316858e388c3131cb2d3f9335d204da6
Author: Pavel Pereslegin <[email protected]>
AuthorDate: Wed Feb 25 10:04:27 2026 +0300

    IGNITE-27730 Sql. Add validation that a not null column must have a default 
value (#7640)
---
 .../commands/AlterTableAddColumnCommand.java       | 11 ++++-
 .../ignite/internal/catalog/CatalogTableTest.java  | 10 ++--
 .../AlterTableAddColumnCommandValidationTest.java  | 47 ++++++++++++++++---
 .../schemacompat/SchemaCompatibilityValidator.java | 11 ++++-
 .../SchemaCompatibilityValidatorTest.java          | 12 ++++-
 .../ItThinClientSchemaSynchronizationTest.java     | 16 +++----
 .../sql/engine/ItAlterTableAlterColumnTest.java    | 53 ++++++++++++++++++++++
 .../internal/sql/engine/ItAlterTableDdlTest.java   | 22 +++++++++
 .../ignite/internal/sql/engine/ItDmlTest.java      |  4 +-
 .../sql/engine/exec/SqlOutdatedPlanTest.java       |  2 +-
 .../ignite/internal/table/TableTestUtils.java      |  2 +-
 11 files changed, 161 insertions(+), 29 deletions(-)

diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommand.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommand.java
index 195ee1b9512..db1cf6cc33b 100644
--- 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommand.java
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommand.java
@@ -33,6 +33,8 @@ import org.apache.ignite.internal.catalog.Catalog;
 import org.apache.ignite.internal.catalog.CatalogCommand;
 import org.apache.ignite.internal.catalog.CatalogValidationException;
 import org.apache.ignite.internal.catalog.UpdateContext;
+import org.apache.ignite.internal.catalog.commands.DefaultValue.ConstantValue;
+import org.apache.ignite.internal.catalog.commands.DefaultValue.Type;
 import org.apache.ignite.internal.catalog.descriptors.CatalogSchemaDescriptor;
 import 
org.apache.ignite.internal.catalog.descriptors.CatalogTableColumnDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
@@ -123,8 +125,15 @@ public class AlterTableAddColumnCommand extends 
AbstractTableCommand {
                 throw new CatalogValidationException("Column with name '{}' 
specified more than once.", column.name());
             }
 
+            DefaultValue defaultValue = column.defaultValueDefinition();
+
             ensureTypeCanBeStored(column.name(), column.type());
-            ensureNonFunctionalDefault(column.name(), 
column.defaultValueDefinition());
+            ensureNonFunctionalDefault(column.name(), defaultValue);
+
+            if (!column.nullable() && (defaultValue == null
+                    || (defaultValue.type() == Type.CONSTANT && 
((ConstantValue) defaultValue).value() == null))) {
+                throw new CatalogValidationException("Non-nullable column '{}' 
must have the default value.", column.name());
+            }
         }
     }
 
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 6a0b7428595..8d9f6d1d876 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
@@ -515,7 +515,7 @@ public class CatalogTableTest extends 
BaseCatalogManagerTest {
 
     @Test
     public void testAddColumnWithNotExistingTable() {
-        assertThat(manager.execute(addColumnParams(TABLE_NAME, 
columnParams("key", INT32))),
+        assertThat(manager.execute(addColumnParams(TABLE_NAME, 
columnParams("key", INT32, true))),
                 willThrowFast(CatalogValidationException.class, "Table with 
name 'PUBLIC.test_table' not found."));
     }
 
@@ -523,7 +523,7 @@ public class CatalogTableTest extends 
BaseCatalogManagerTest {
     public void testAddColumnWithExistingName() {
         tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
 
-        assertThat(manager.execute(addColumnParams(TABLE_NAME, 
columnParams("ID", INT32))),
+        assertThat(manager.execute(addColumnParams(TABLE_NAME, 
columnParams("ID", INT32, true))),
                 willThrowFast(CatalogValidationException.class, "Column with 
name 'ID' already exists."));
     }
 
@@ -693,7 +693,7 @@ public class CatalogTableTest extends 
BaseCatalogManagerTest {
     public void addColumnIncrementsTableVersion() {
         createSomeTable(TABLE_NAME);
 
-        tryApplyAndExpectApplied(addColumnParams(TABLE_NAME, 
columnParams("val2", INT32)));
+        tryApplyAndExpectApplied(addColumnParams(TABLE_NAME, 
columnParams("val2", INT32, true)));
 
         CatalogTableDescriptor table = actualTable(TABLE_NAME);
 
@@ -751,7 +751,7 @@ public class CatalogTableTest extends 
BaseCatalogManagerTest {
         manager.listen(CatalogEvent.TABLE_ALTER, eventListener);
 
         // Try to add column without table.
-        assertThat(manager.execute(addColumnParams(TABLE_NAME, 
columnParams(NEW_COLUMN_NAME, INT32))),
+        assertThat(manager.execute(addColumnParams(TABLE_NAME, 
columnParams(NEW_COLUMN_NAME, INT32, true))),
                 willThrow(CatalogValidationException.class, "Table with name 
'PUBLIC.test_table' not found."));
         verifyNoInteractions(eventListener);
 
@@ -759,7 +759,7 @@ public class CatalogTableTest extends 
BaseCatalogManagerTest {
         tryApplyAndExpectApplied(simpleTable(TABLE_NAME));
 
         // Add column.
-        tryApplyAndExpectApplied(addColumnParams(TABLE_NAME, 
columnParams(NEW_COLUMN_NAME, INT32)));
+        tryApplyAndExpectApplied(addColumnParams(TABLE_NAME, 
columnParams(NEW_COLUMN_NAME, INT32, true)));
         verify(eventListener).notify(any(AddColumnEventParameters.class));
 
         // Drop column.
diff --git 
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandValidationTest.java
 
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandValidationTest.java
index e3df89d26f0..4fe6091e2a4 100644
--- 
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandValidationTest.java
+++ 
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandValidationTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.catalog.commands;
 
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.columnParams;
 import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
 import static org.apache.ignite.sql.ColumnType.INT32;
 import static org.apache.ignite.sql.ColumnType.STRING;
@@ -34,7 +35,7 @@ import org.junit.jupiter.params.provider.MethodSource;
 /**
  * Tests to verify validation of {@link AlterTableAddColumnCommand}.
  */
-@SuppressWarnings({"DataFlowIssue", "ThrowableNotThrown"})
+@SuppressWarnings("ThrowableNotThrown")
 public class AlterTableAddColumnCommandValidationTest extends 
AbstractCommandValidationTest {
     @ParameterizedTest(name = "[{index}] ''{argumentsWithNames}''")
     @MethodSource("nullAndBlankStrings")
@@ -91,6 +92,7 @@ public class AlterTableAddColumnCommandValidationTest extends 
AbstractCommandVal
         ColumnParams column = ColumnParams.builder()
                 .name("C")
                 .type(INT32)
+                .nullable(true)
                 .build();
 
         builder = fillProperties(builder).columns(List.of(column, column));
@@ -110,6 +112,7 @@ public class AlterTableAddColumnCommandValidationTest 
extends AbstractCommandVal
                         ColumnParams.builder()
                                 .name("NEW_C")
                                 .type(INT32)
+                                .nullable(true)
                                 .build()
                 ));
     }
@@ -152,18 +155,18 @@ public class AlterTableAddColumnCommandValidationTest 
extends AbstractCommandVal
     void exceptionIsThrownIfColumnWithGivenNameAlreadyExists() {
         String tableName = "TEST";
         String columnName = "TEST";
-        ColumnParams columnParams = 
ColumnParams.builder().name(columnName).type(INT32).build();
+
         Catalog catalog = catalogWithTable(builder -> builder
                 .schemaName(SCHEMA_NAME)
                 .tableName(tableName)
-                .columns(List.of(columnParams))
+                .columns(List.of(columnParams(columnName, INT32)))
                 .primaryKey(primaryKey(columnName))
         );
 
         AlterTableAddColumnCommandBuilder builder = 
AlterTableAddColumnCommand.builder()
                 .schemaName(SCHEMA_NAME)
                 .tableName(tableName)
-                .columns(List.of(columnParams));
+                .columns(List.of(columnParams(columnName, INT32, true)));
 
         assertThrowsWithCause(
                 () -> builder.build().get(new UpdateContext(catalog)),
@@ -176,18 +179,18 @@ public class AlterTableAddColumnCommandValidationTest 
extends AbstractCommandVal
     void 
exceptionNotThrownIfColumnWithGivenNameAlreadyExistsWithIfColumnNotExists() {
         String tableName = "TEST";
         String columnName = "TEST";
-        ColumnParams columnParams = 
ColumnParams.builder().name(columnName).type(INT32).build();
+
         Catalog catalog = catalogWithTable(builder -> builder
                 .schemaName(SCHEMA_NAME)
                 .tableName(tableName)
-                .columns(List.of(columnParams))
+                .columns(List.of(columnParams(columnName, INT32)))
                 .primaryKey(primaryKey(columnName))
         );
 
         AlterTableAddColumnCommandBuilder builder = 
AlterTableAddColumnCommand.builder()
                 .schemaName(SCHEMA_NAME)
                 .tableName(tableName)
-                .columns(List.of(columnParams))
+                .columns(List.of(columnParams(columnName, INT32, true)))
                 .ifColumnNotExists(true);
 
         assertDoesNotThrow(() -> builder.build().get(new 
UpdateContext(catalog)));
@@ -219,6 +222,36 @@ public class AlterTableAddColumnCommandValidationTest 
extends AbstractCommandVal
         );
     }
 
+    @Test
+    void cannotAddNonNullableColumnWithoutDefault() {
+        String tableName = "TEST";
+        String columnName = "TEST";
+        Catalog catalog = catalogWithTable(builder -> builder
+                .schemaName(SCHEMA_NAME)
+                .tableName(tableName)
+                .columns(List.of(columnParams("ID", INT32, false)))
+                .primaryKey(primaryKey("ID"))
+        );
+
+        ColumnParams columnParams = ColumnParams.builder()
+                .name(columnName)
+                .type(STRING)
+                .length(10)
+                .nullable(false)
+                .build();
+
+        AlterTableAddColumnCommandBuilder builder = 
AlterTableAddColumnCommand.builder()
+                .schemaName(SCHEMA_NAME)
+                .tableName(tableName)
+                .columns(List.of(columnParams));
+
+        assertThrowsWithCause(
+                () -> builder.build().get(new UpdateContext(catalog)),
+                CatalogValidationException.class,
+                "Non-nullable column 'TEST' must have the default value"
+        );
+    }
+
     @ParameterizedTest
     @MethodSource("reservedSchemaNames")
     void exceptionIsThrownIfSchemaIsReserved(String schema) {
diff --git 
a/modules/partition-replicator/src/main/java/org/apache/ignite/internal/partition/replicator/schemacompat/SchemaCompatibilityValidator.java
 
b/modules/partition-replicator/src/main/java/org/apache/ignite/internal/partition/replicator/schemacompat/SchemaCompatibilityValidator.java
index 4dedbcb3541..c83e440674b 100644
--- 
a/modules/partition-replicator/src/main/java/org/apache/ignite/internal/partition/replicator/schemacompat/SchemaCompatibilityValidator.java
+++ 
b/modules/partition-replicator/src/main/java/org/apache/ignite/internal/partition/replicator/schemacompat/SchemaCompatibilityValidator.java
@@ -24,6 +24,9 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import org.apache.ignite.internal.catalog.CatalogService;
+import org.apache.ignite.internal.catalog.commands.DefaultValue;
+import org.apache.ignite.internal.catalog.commands.DefaultValue.ConstantValue;
+import org.apache.ignite.internal.catalog.commands.DefaultValue.Type;
 import 
org.apache.ignite.internal.catalog.descriptors.CatalogTableColumnDescriptor;
 import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
 import org.apache.ignite.internal.hlc.HybridTimestamp;
@@ -355,8 +358,12 @@ public class SchemaCompatibilityValidator {
             }
 
             for (CatalogTableColumnDescriptor column : diff.addedColumns()) {
-                if (!column.nullable() && column.defaultValue() == null) {
-                    return new ValidationResult(ValidatorVerdict.INCOMPATIBLE, 
"Not null column added without default value");
+                if (!column.nullable()) {
+                    DefaultValue defaultValue = column.defaultValue();
+
+                    if (defaultValue == null || (defaultValue.type() == 
Type.CONSTANT && ((ConstantValue) defaultValue).value() == null)) {
+                        return new 
ValidationResult(ValidatorVerdict.INCOMPATIBLE, "Not null column added without 
default value");
+                    }
                 }
             }
 
diff --git 
a/modules/partition-replicator/src/test/java/org/apache/ignite/internal/partition/replicator/schemacompat/SchemaCompatibilityValidatorTest.java
 
b/modules/partition-replicator/src/test/java/org/apache/ignite/internal/partition/replicator/schemacompat/SchemaCompatibilityValidatorTest.java
index 3048a74be0c..92397dcdc33 100644
--- 
a/modules/partition-replicator/src/test/java/org/apache/ignite/internal/partition/replicator/schemacompat/SchemaCompatibilityValidatorTest.java
+++ 
b/modules/partition-replicator/src/test/java/org/apache/ignite/internal/partition/replicator/schemacompat/SchemaCompatibilityValidatorTest.java
@@ -406,7 +406,7 @@ class SchemaCompatibilityValidatorTest extends 
BaseIgniteAbstractTest {
         return new CatalogTableColumnDescriptor(columnName, INT32, true, 
DEFAULT_PRECISION, DEFAULT_SCALE, DEFAULT_LENGTH, null);
     }
 
-    private static CatalogTableColumnDescriptor intColumnWithDefault(String 
columnName, int defaultValue) {
+    private static CatalogTableColumnDescriptor intColumnWithDefault(String 
columnName, @Nullable Integer defaultValue) {
         return new CatalogTableColumnDescriptor(
                 columnName,
                 INT32,
@@ -556,6 +556,16 @@ class SchemaCompatibilityValidatorTest extends 
BaseIgniteAbstractTest {
                 ),
                 "Not null column added without default value"
         ),
+        NON_NULL_WITH_DEFAULT_NULL(
+                List.of(
+                        tableSchema(1, List.of(
+                        )),
+                        tableSchema(2, List.of(
+                                
intColumnWithDefault("NON_NULL_WITHOUT_DEFAULT_COL", null)
+                        ))
+                ),
+                "Not null column added without default value"
+        ),
         TYPE_CHANGED(
                 List.of(
                         tableSchema(1, List.of(
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSchemaSynchronizationTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSchemaSynchronizationTest.java
index cf6f5ec4a92..c403d646144 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSchemaSynchronizationTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSchemaSynchronizationTest.java
@@ -19,7 +19,6 @@ package org.apache.ignite.internal.runner.app.client;
 
 import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.apache.ignite.client.IgniteClient;
@@ -89,7 +88,7 @@ public class ItThinClientSchemaSynchronizationTest extends 
ItAbstractThinClientT
     }
 
     @Test
-    void testClientUsesLatestSchemaOnReadWithNotNullColumn() {
+    void testClientUsesLatestSchemaOnReadWithNotNullColumnWithDefault() {
         IgniteClient client = client();
         IgniteSql sql = client.sql();
 
@@ -103,9 +102,8 @@ public class ItThinClientSchemaSynchronizationTest extends 
ItAbstractThinClientT
         recordView.insert(null, rec);
 
         // Modify table and get old row.
-        // It still has null value in the old column, even though it is not 
allowed by the new schema.
-        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL");
-        assertNull(recordView.get(null, rec).stringValue(1));
+        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL DEFAULT '1'");
+        assertEquals("1", recordView.get(null, rec).stringValue(1));
     }
 
     @Test
@@ -151,7 +149,7 @@ public class ItThinClientSchemaSynchronizationTest extends 
ItAbstractThinClientT
 
         // Modify table, insert again - client will use old schema, throw 
ClientSchemaMismatchException,
         // reload schema, retry with new schema and succeed.
-        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL");
+        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL DEFAULT '1'");
         action.run();
 
         assertEquals("name", recordView.get(null, rec).stringValue(1));
@@ -181,7 +179,7 @@ public class ItThinClientSchemaSynchronizationTest extends 
ItAbstractThinClientT
 
         // Modify table, insert again - client will use old schema, throw 
ClientSchemaMismatchException,
         // reload schema, retry with new schema and succeed.
-        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL");
+        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL DEFAULT '1'");
         action.run();
 
         assertEquals("name", kvView.get(null, key).stringValue(0));
@@ -210,7 +208,7 @@ public class ItThinClientSchemaSynchronizationTest extends 
ItAbstractThinClientT
 
         // Modify table, insert again - client will use old schema, throw 
ClientSchemaMismatchException,
         // reload schema, retry with new schema and succeed.
-        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL");
+        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL DEFAULT '1'");
         action.run();
 
         assertEquals("name", recordView.get(null, rec).name);
@@ -242,7 +240,7 @@ public class ItThinClientSchemaSynchronizationTest extends 
ItAbstractThinClientT
 
         // Modify table, insert again - client will use old schema, throw 
ClientSchemaMismatchException,
         // reload schema, retry with new schema and succeed.
-        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL");
+        sql.execute("ALTER TABLE " + tableName + " ADD COLUMN NAME VARCHAR NOT 
NULL DEFAULT '1'");
         action.run();
 
         assertEquals("name", kvView.get(null, key).name);
diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAlterTableAlterColumnTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAlterTableAlterColumnTest.java
index 56b9ce01048..4232e6a0722 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAlterTableAlterColumnTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAlterTableAlterColumnTest.java
@@ -275,6 +275,59 @@ public class ItAlterTableAlterColumnTest extends 
BaseSqlIntegrationTest {
         }
     }
 
+    @Test
+    public void dropDefaultNonNullableColumn() {
+        sql("CREATE TABLE t (id INT PRIMARY KEY)");
+        sql("INSERT INTO t VALUES (0)");
+        sql("ALTER TABLE t ADD COLUMN C1 VARCHAR NOT NULL DEFAULT 'a'");
+        sql("ALTER TABLE t ADD COLUMN C2 VARCHAR NOT NULL DEFAULT 'b'");
+
+        sql("ALTER TABLE t ALTER COLUMN C1 DROP DEFAULT");
+        sql("ALTER TABLE t ALTER COLUMN C2 SET DEFAULT NULL");
+
+        assertThrowsSqlException(Sql.CONSTRAINT_VIOLATION_ERR, "Column 'C1' 
does not allow NULL",
+                () -> sql("INSERT INTO t (id, c2) VALUES (1, 'c')"));
+        assertThrowsSqlException(Sql.CONSTRAINT_VIOLATION_ERR, "Column 'C2' 
does not allow NULL",
+                () -> sql("INSERT INTO t (id, c1) VALUES (1, 'c')"));
+
+        sql("INSERT INTO t (id, c1, c2) VALUES (1, 'a1', 'b1')");
+
+        sql("ALTER TABLE t ALTER COLUMN C1 SET DEFAULT 'a2'");
+        sql("ALTER TABLE t ALTER COLUMN C2 SET DEFAULT 'b2'");
+
+        sql("INSERT INTO t (id) VALUES (2)");
+
+        assertQuery("SELECT id, c1, c2 FROM t ORDER BY id")
+                .returns(0, "a", "b")
+                .returns(1, "a1", "b1")
+                .returns(2, "a2", "b2")
+                .check();
+    }
+
+    @Test
+    public void dropDefaultNullableColumn() {
+        sql("CREATE TABLE t (id INT PRIMARY KEY)");
+        sql("INSERT INTO t VALUES (0)");
+        sql("ALTER TABLE t ADD COLUMN C1 VARCHAR DEFAULT 'a'");
+        sql("ALTER TABLE t ADD COLUMN C2 VARCHAR DEFAULT 'b'");
+
+        sql("ALTER TABLE t ALTER COLUMN C1 DROP DEFAULT");
+        sql("ALTER TABLE t ALTER COLUMN C2 SET DEFAULT NULL");
+
+        sql("INSERT INTO t (id) VALUES (1)");
+
+        sql("ALTER TABLE t ALTER COLUMN C1 SET DEFAULT 'a2'");
+        sql("ALTER TABLE t ALTER COLUMN C2 SET DEFAULT 'b2'");
+
+        sql("INSERT INTO t (id) VALUES (2)");
+
+        assertQuery("SELECT id, c1, c2 FROM t ORDER BY id")
+                .returns(0, "a", "b")
+                .returns(1, null, null)
+                .returns(2, "a2", "b2")
+                .check();
+    }
+
     @Test
     public void setDataTypeSetDefault() {
         sql("CREATE TABLE t (id int PRIMARY KEY, val int)");
diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAlterTableDdlTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAlterTableDdlTest.java
index 2fdd9310cea..c3481999f64 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAlterTableDdlTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItAlterTableDdlTest.java
@@ -240,6 +240,28 @@ public class ItAlterTableDdlTest extends 
BaseSqlIntegrationTest {
         );
     }
 
+    @Test
+    public void cannotAddNonNullableColumnWithoutDefault() {
+        sql("CREATE TABLE t (id VARCHAR PRIMARY KEY)");
+
+        assertThrowsSqlException(
+                STMT_VALIDATION_ERR,
+                "Non-nullable column 'VAL' must have the default value",
+                () -> sql("ALTER TABLE t ADD COLUMN val VARCHAR NOT NULL")
+        );
+
+        // Should not throw an exception since default value is provided.
+        sql("ALTER TABLE t ADD COLUMN val VARCHAR NOT NULL DEFAULT 'a'");
+
+        assertThrowsSqlException(
+                STMT_VALIDATION_ERR,
+                "Non-nullable column 'VAL2' must have the default value",
+                () -> sql("ALTER TABLE t ADD COLUMN val2 VARCHAR NOT NULL 
DEFAULT NULL")
+        );
+
+        sql("ALTER TABLE t ADD COLUMN val2 VARCHAR DEFAULT NULL");
+    }
+
     @Test
     public void uuidDefault() {
         UUID defaultUuid = UUID.randomUUID();
diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
index 6b7ea900f03..1e39144ac78 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
@@ -797,8 +797,6 @@ public class ItDmlTest extends BaseSqlIntegrationTest {
             try {
                 sql(format("CREATE TABLE test (id INT PRIMARY KEY, val {} 
DEFAULT {})", arg.sqlType, arg.sqlVal));
                 sql("INSERT INTO test (id) VALUES (1)");
-                assertQuery("SELECT val FROM test WHERE id = 
1").returns(arg.expectedVal).check();
-
                 sql("ALTER TABLE test ALTER COLUMN val DROP DEFAULT");
 
                 if (arg.sqlType.endsWith("NOT NULL")) {
@@ -808,6 +806,8 @@ public class ItDmlTest extends BaseSqlIntegrationTest {
                     sql("INSERT INTO test (id) VALUES (2)");
                     assertQuery("SELECT val FROM test WHERE id = 
2").returns(null).check();
                 }
+
+                assertQuery("SELECT val FROM test WHERE id = 
1").returns(arg.expectedVal).check();
             } finally {
                 sql("DROP TABLE IF EXISTS test");
             }
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/SqlOutdatedPlanTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/SqlOutdatedPlanTest.java
index a4f18e5d128..f06e0dccf07 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/SqlOutdatedPlanTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/SqlOutdatedPlanTest.java
@@ -180,7 +180,7 @@ public class SqlOutdatedPlanTest extends 
BaseIgniteAbstractTest {
         return AlterTableAddColumnCommand.builder()
                 .schemaName(DEFAULT_SCHEMA_NAME)
                 .tableName("T1")
-                .columns(List.of(columnParams(columnName, INT32)))
+                .columns(List.of(columnParams(columnName, INT32, true)))
                 .build();
     }
 
diff --git 
a/modules/table/src/testFixtures/java/org/apache/ignite/internal/table/TableTestUtils.java
 
b/modules/table/src/testFixtures/java/org/apache/ignite/internal/table/TableTestUtils.java
index eef93d46a1b..f4acf416e40 100644
--- 
a/modules/table/src/testFixtures/java/org/apache/ignite/internal/table/TableTestUtils.java
+++ 
b/modules/table/src/testFixtures/java/org/apache/ignite/internal/table/TableTestUtils.java
@@ -442,7 +442,7 @@ public class TableTestUtils {
         CatalogCommand command = AlterTableAddColumnCommand.builder()
                 .schemaName(schemaName)
                 .tableName(tableName)
-                
.columns(List.of(ColumnParams.builder().name(columnName).type(columnType).build()))
+                
.columns(List.of(ColumnParams.builder().name(columnName).type(columnType).nullable(true).build()))
                 .build();
 
         assertThat(catalogManager.execute(command), 
willCompleteSuccessfully());

Reply via email to