Column declaration: [NOT] NULL right after type

+ fixed: data_type_default_nullable=true, it didn't make columns nullable
         if the column declaration contains default expression w/o type

Issue #37229
This commit is contained in:
Igor Nikonov 2022-05-16 22:09:23 +00:00
parent bc145294a6
commit 838a6c6f61
6 changed files with 127 additions and 11 deletions

View File

@ -578,7 +578,12 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription(
if (col_decl.type)
column.type = name_type_it->type;
else
{
column.type = defaults_sample_block.getByName(column.name).type;
/// set nullability for case of column declaration w/o type but with default expression
if ((col_decl.null_modifier && *col_decl.null_modifier) || make_columns_nullable)
column.type = makeNullable(column.type);
}
column.default_desc.kind = columnDefaultKindFromString(col_decl.default_specifier);
column.default_desc.expression = default_expr;

View File

@ -105,9 +105,9 @@ protected:
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
bool require_type = true;
bool allow_null_modifiers = false;
bool check_keywords_after_name = false;
const bool require_type = true;
const bool allow_null_modifiers = false;
const bool check_keywords_after_name = false;
/// just for ALTER TABLE ALTER COLUMN use
bool check_type_keyword = false;
};
@ -175,7 +175,22 @@ bool IParserColumnDeclaration<NameParser>::parseImpl(Pos & pos, ASTPtr & node, E
ASTPtr ttl_expression;
ASTPtr collation_expression;
if (!s_default.checkWithoutMoving(pos, expected)
auto null_check_without_moving = [&]() -> bool
{
if (!allow_null_modifiers)
return false;
if (s_null.checkWithoutMoving(pos, expected))
return true;
Pos before_null = pos;
bool res = s_not.check(pos, expected) && s_null.checkWithoutMoving(pos, expected);
pos = before_null;
return res;
};
if (!null_check_without_moving()
&& !s_default.checkWithoutMoving(pos, expected)
&& !s_materialized.checkWithoutMoving(pos, expected)
&& !s_ephemeral.checkWithoutMoving(pos, expected)
&& !s_alias.checkWithoutMoving(pos, expected)
@ -195,6 +210,18 @@ bool IParserColumnDeclaration<NameParser>::parseImpl(Pos & pos, ASTPtr & node, E
}
}
if (allow_null_modifiers)
{
if (s_not.check(pos, expected))
{
if (!s_null.check(pos, expected))
return false;
null_modifier.emplace(false);
}
else if (s_null.check(pos, expected))
null_modifier.emplace(true);
}
Pos pos_before_specifier = pos;
if (s_default.ignore(pos, expected) || s_materialized.ignore(pos, expected) || s_alias.ignore(pos, expected))
{
@ -230,7 +257,7 @@ bool IParserColumnDeclaration<NameParser>::parseImpl(Pos & pos, ASTPtr & node, E
if (require_type && !type && !default_expression)
return false; /// reject column name without type
if (type && allow_null_modifiers)
if ((type || default_expression) && allow_null_modifiers && !null_modifier.has_value())
{
if (s_not.ignore(pos, expected))
{

View File

@ -1,7 +1,7 @@
Nullable(Int32) Int32 Nullable(Int32) Int32
CREATE TABLE default.data_null\n(\n `a` Nullable(Int32),\n `b` Int32,\n `c` Nullable(Int32),\n `d` Int32\n)\nENGINE = Memory
Nullable(Int32) Int32 Nullable(Int32) Nullable(Int32)
CREATE TABLE default.set_null\n(\n `a` Nullable(Int32),\n `b` Int32,\n `c` Nullable(Int32),\n `d` Nullable(Int32)\n)\nENGINE = Memory
CREATE TABLE default.set_null\n(\n `a` Nullable(Int32),\n `b` Int32,\n `c` Nullable(Int32),\n `d` Nullable(Int32)\n)\nENGINE = Memory
Nullable(Int32) Int32 Nullable(Int32) Nullable(Int32) Nullable(UInt8)
CREATE TABLE default.set_null\n(\n `a` Nullable(Int32),\n `b` Int32,\n `c` Nullable(Int32),\n `d` Nullable(Int32),\n `f` Nullable(UInt8) DEFAULT 1\n)\nENGINE = Memory
CREATE TABLE default.set_null\n(\n `a` Nullable(Int32),\n `b` Int32,\n `c` Nullable(Int32),\n `d` Nullable(Int32),\n `f` Nullable(UInt8) DEFAULT 1\n)\nENGINE = Memory
CREATE TABLE default.cannot_be_nullable\n(\n `n` Nullable(Int8),\n `a` Array(UInt8)\n)\nENGINE = Memory
CREATE TABLE default.cannot_be_nullable\n(\n `n` Nullable(Int8),\n `a` Array(UInt8)\n)\nENGINE = Memory

View File

@ -39,13 +39,14 @@ CREATE TABLE set_null (
a INT NULL,
b INT NOT NULL,
c Nullable(INT),
d INT
d INT,
f DEFAULT 1
) engine=Memory();
INSERT INTO set_null VALUES (NULL, 2, NULL, NULL);
INSERT INTO set_null VALUES (NULL, 2, NULL, NULL, NULL);
SELECT toTypeName(a), toTypeName(b), toTypeName(c), toTypeName(d) FROM set_null;
SELECT toTypeName(a), toTypeName(b), toTypeName(c), toTypeName(d), toTypeName(f) FROM set_null;
SHOW CREATE TABLE set_null;
DETACH TABLE set_null;

View File

@ -0,0 +1,22 @@
create table, column +type +NULL
id Nullable(Int32)
create table, column +type +NOT NULL
id Int32
create table, column +type +NULL +DEFAULT
id Nullable(Int32) DEFAULT 1
create table, column +type +NOT NULL +DEFAULT
id Int32 DEFAULT 1
create table, column +type +DEFAULT +NULL
id Nullable(Int32) DEFAULT 1
create table, column +type +DEFAULT +NOT NULL
id Int32 DEFAULT 1
create table, column -type +NULL +DEFAULT
id Nullable(UInt8) DEFAULT 1
create table, column -type +NOT NULL +DEFAULT
id UInt8 DEFAULT 1
create table, column -type +DEFAULT +NULL
id Nullable(UInt8) DEFAULT 1
create table, column -type +DEFAULT +NOT NULL
id UInt8 DEFAULT 1
alter column, NULL modifier is not allowed
modify column, NULL modifier is not allowed

View File

@ -0,0 +1,61 @@
select 'create table, column +type +NULL';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id INT NULL) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'create table, column +type +NOT NULL';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id INT NOT NULL) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'create table, column +type +NULL +DEFAULT';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id INT NULL DEFAULT 1) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'create table, column +type +NOT NULL +DEFAULT';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id INT NOT NULL DEFAULT 1) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'create table, column +type +DEFAULT +NULL';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id INT DEFAULT 1 NULL) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'create table, column +type +DEFAULT +NOT NULL';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id INT DEFAULT 1 NOT NULL) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'create table, column -type +NULL +DEFAULT';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id NULL DEFAULT 1) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'create table, column -type +NOT NULL +DEFAULT';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id NOT NULL DEFAULT 1) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'create table, column -type +DEFAULT +NULL';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id DEFAULT 1 NULL) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'create table, column -type +DEFAULT +NOT NULL';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id DEFAULT 1 NOT NULL) ENGINE=MergeTree() ORDER BY tuple();
DESCRIBE TABLE null_before;
select 'alter column, NULL modifier is not allowed';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id INT NOT NULL) ENGINE=MergeTree() ORDER BY tuple();
ALTER TABLE null_before ALTER COLUMN id TYPE INT NULL; -- { clientError SYNTAX_ERROR }
select 'modify column, NULL modifier is not allowed';
DROP TABLE IF EXISTS null_before SYNC;
CREATE TABLE null_before (id INT NOT NULL) ENGINE=MergeTree() ORDER BY tuple();
ALTER TABLE null_before MODIFY COLUMN id NULL DEFAULT 1; -- { serverError UNKNOWN_TYPE }
DROP TABLE IF EXISTS null_before SYNC;