Zoltán Borók-Nagy created IMPALA-15615:
------------------------------------------
Summary: Iceberg V3: ALTER TABLE ADD COLUMN(S) ... NOT NULL
DEFAULT adds a nullable column
Key: IMPALA-15615
URL: https://issues.apache.org/jira/browse/IMPALA-15615
Project: IMPALA
Issue Type: Bug
Components: Catalog, Frontend
Reporter: Zoltán Borók-Nagy
On Iceberg V3 tables, ALTER TABLE ... ADD COLUMN and ADD COLUMNS accept a NOT
NULL column with a DEFAULT, but the new column is optional. NOT NULL is dropped
without a warning: DESCRIBE shows the column as nullable, the Iceberg schema
has "required":false, and NULL can be inserted into it.
Repro on master:
{code:sql}
create table t (i int) stored by iceberg tblproperties('format-version'='3');
insert into t values (1);
alter table t add column c int not null default 7;
alter table t add columns (d int not null default 8);
describe t;
{code}
{noformat}
name type comment nullable
i int true
c int true
d int true
{noformat}
current-schema in DESCRIBE FORMATTED t (trimmed):
{noformat}
{\"id\":2,\"name\":\"c\",\"required\":false,\"type\":\"int\",\"initial-default\":7,\"write-default\":7},{\"id\":3,\"name\":\"d\",\"required\":false,\"type\":\"int\",\"initial-default\":8,\"write-default\":8}
{noformat}
{code:sql}
insert into t (i, c, d) values (2, NULL, NULL);
select i, c, d from t order by i;
{code}
{noformat}
Modified 1 row(s) in 0.18s
i c d
1 7 8
2 NULL NULL
{noformat}
Expected: c and d are required fields, and the INSERT fails. This is what
happens when CREATE TABLE defines the same column:
{code:sql}
create table s (i int, c int not null default 7) stored by iceberg
tblproperties('format-version'='3');
describe s;
insert into s (i, c) values (2, NULL);
{code}
{noformat}
name type comment nullable
i int true
c int false
ERROR: Query 884c335a4cc21f26:e8f205ea00000000 failed:
Column 'c' is not nullable but during writing a Parquet page we found 1 null
values.
{noformat}
(current-schema of s has {{"required":true}} for c.)
*Analysis*
AlterTableAddColsStmt passes NOT NULL to the catalog: ColumnDef.toThrift() sets
TColumn.is_nullable to false. Since IMPALA-15364, analysis rejects a NOT NULL
column without a DEFAULT ("A new non-null column must have a default value:
..."), and a DEFAULT needs 'format-version' >= 3. So a NOT NULL column reaches
the catalog only on V3 tables, and always with a DEFAULT.
CatalogOpExecutor.alterIcebergTable() then calls
IcebergCatalogOpExecutor.addColumns(). That method ignores is_nullable and
always calls UpdateSchema.addColumn(), with or without a default (the default
branch came with IMPALA-14589), which adds an optional field. CREATE TABLE is
not affected: IcebergSchemaConverter.createIcebergField() uses
NestedField.required() when is_nullable is false.
The IMPALA-15364 commit message suggests {{ALTER TABLE t ADD COLUMNS (j INT NOT
NULL DEFAULT 0)}} on a V3 table as the way to add a NOT NULL column. Right now
that statement adds a nullable column. The IMPALA-15364 tests cover only the
case without a default, and no Iceberg test covers ADD COLUMN(S) with NOT NULL
DEFAULT.
*Suggested fix*
In IcebergCatalogOpExecutor.addColumns(), call
UpdateSchema.addRequiredColumn(name, type, doc, defaultValue) when
column.isSetIs_nullable() && !column.isIs_nullable(), and keep addColumn() for
the other columns. Analysis already guarantees that such a column has a
default. With a default, Iceberg allows adding a required column without
allowIncompatibleChanges(): in Iceberg 1.11.0, SchemaUpdate fails with
"Incompatible change: cannot add required column without a default value" only
when the default is null.
*Testing*
Add V3 end-to-end cases for ADD COLUMN and ADD COLUMNS with NOT NULL DEFAULT.
They should check that DESCRIBE shows nullable false, old rows read the initial
default, an INSERT that omits the column gets the write default, and an INSERT
of NULL fails.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)