diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index 993c9e595e3..5d8c43aed0d 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -287,28 +287,22 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription( const auto & col_decl = ast->as(); DataTypePtr column_type = nullptr; - if (!col_decl.is_null && col_decl.is_not) - throw Exception{"Cant use NOT without NULL", ErrorCodes::ILLEGAL_SYNTAX_FOR_DATA_TYPE}; if (col_decl.type) { column_type = DataTypeFactory::instance().get(col_decl.type); - if (col_decl.is_not && col_decl.is_null) + if (col_decl.null_modifier) { if (column_type->isNullable()) - throw Exception{"Cant use NOT NULL with Nullable", ErrorCodes::ILLEGAL_SYNTAX_FOR_DATA_TYPE}; - } - else if (col_decl.is_null && !col_decl.is_not) - { - if (column_type->isNullable()) - throw Exception{"Cant use NULL with Nullable", ErrorCodes::ILLEGAL_SYNTAX_FOR_DATA_TYPE}; - else + throw Exception("Cant use [NOT] NULL modifier with Nullable type", ErrorCodes::ILLEGAL_SYNTAX_FOR_DATA_TYPE); + if (*col_decl.null_modifier) column_type = makeNullable(column_type); } - - if (context.getSettingsRef().data_type_default_nullable && !column_type->isNullable() && !col_decl.is_not && !col_decl.is_null) + else if (context.getSettingsRef().data_type_default_nullable) + { column_type = makeNullable(column_type); + } column_names_and_types.emplace_back(col_decl.name, column_type); } diff --git a/src/Parsers/ASTColumnDeclaration.cpp b/src/Parsers/ASTColumnDeclaration.cpp index 08f7813ad06..5dd5fd7d526 100644 --- a/src/Parsers/ASTColumnDeclaration.cpp +++ b/src/Parsers/ASTColumnDeclaration.cpp @@ -18,18 +18,6 @@ ASTPtr ASTColumnDeclaration::clone() const res->children.push_back(res->type); } - if (is_null) - { - res->is_null = is_null; - res->children.push_back(res->is_null); - } - - if (is_not) - { - res->is_not = is_not; - res->children.push_back(res->is_not); - } - if (default_expression) { res->default_expression = default_expression->clone(); @@ -73,16 +61,10 @@ void ASTColumnDeclaration::formatImpl(const FormatSettings & settings, FormatSta type->formatImpl(settings, state, frame); } - if (is_not) + if (null_modifier) { - settings.ostr << ' '; - is_not->formatImpl(settings, state, frame); - } - - if (is_null) - { - settings.ostr << ' '; - is_null->formatImpl(settings, state, frame); + settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") + << (*null_modifier ? "" : "NOT ") << "NULL" << (settings.hilite ? hilite_none : ""); } if (default_expression) diff --git a/src/Parsers/ASTColumnDeclaration.h b/src/Parsers/ASTColumnDeclaration.h index 34afd771de2..ea17a8b4dfa 100644 --- a/src/Parsers/ASTColumnDeclaration.h +++ b/src/Parsers/ASTColumnDeclaration.h @@ -13,8 +13,7 @@ class ASTColumnDeclaration : public IAST public: String name; ASTPtr type; - ASTPtr is_null; - ASTPtr is_not; + std::optional null_modifier; String default_specifier; ASTPtr default_expression; ASTPtr comment; diff --git a/src/Parsers/ParserCreateQuery.cpp b/src/Parsers/ParserCreateQuery.cpp index c54033bd27d..159b19b28c6 100644 --- a/src/Parsers/ParserCreateQuery.cpp +++ b/src/Parsers/ParserCreateQuery.cpp @@ -157,7 +157,7 @@ bool ParserTablePropertyDeclaration::parseImpl(Pos & pos, ASTPtr & node, Expecte ParserIndexDeclaration index_p; ParserConstraintDeclaration constraint_p; - ParserColumnDeclaration column_p; + ParserColumnDeclaration column_p{true, true}; ASTPtr new_node = nullptr; diff --git a/src/Parsers/ParserCreateQuery.h b/src/Parsers/ParserCreateQuery.h index 9fae3d60836..a4fc60a2393 100644 --- a/src/Parsers/ParserCreateQuery.h +++ b/src/Parsers/ParserCreateQuery.h @@ -92,7 +92,8 @@ template class IParserColumnDeclaration : public IParserBase { public: - explicit IParserColumnDeclaration(bool require_type_ = true) : require_type(require_type_) + explicit IParserColumnDeclaration(bool require_type_ = true, bool allow_null_modifiers_ = false) + : require_type(require_type_), allow_null_modifiers(allow_null_modifiers_) { } @@ -104,6 +105,7 @@ protected: bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override; bool require_type = true; + bool allow_null_modifiers = false; }; using ParserColumnDeclaration = IParserColumnDeclaration; @@ -126,8 +128,6 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E ParserStringLiteral string_literal_parser; ParserCodec codec_parser; ParserExpression expression_parser; - ParserIdentifier null_parser; - ParserCompoundIdentifier not_null_parser; /// mandatory column name ASTPtr name; @@ -139,8 +139,7 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E */ ASTPtr type; String default_specifier; - ASTPtr is_null; - ASTPtr is_not; + std::optional null_modifier; ASTPtr default_expression; ASTPtr comment_expression; ASTPtr codec_expression; @@ -169,19 +168,17 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E if (require_type && !type && !default_expression) return false; /// reject column name without type - // Pos pos_before_null = pos; - - if (s_not.check(pos, expected)) - if (s_null.check(pos, expected)) + if (type && allow_null_modifiers) + { + if (s_not.ignore(pos, expected)) { - is_not = std::make_shared("NOT"); - is_null = std::make_shared("NULL"); + if (!s_null.ignore(pos, expected)) + return false; + null_modifier.emplace(false); } - else - return false; - else - if (s_null.check(pos, expected)) - is_null = std::make_shared("NULL"); + else if (s_null.ignore(pos, expected)) + null_modifier.emplace(true); + } if (s_comment.ignore(pos, expected)) { @@ -212,17 +209,7 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E column_declaration->children.push_back(std::move(type)); } - if (is_null) - { - column_declaration->is_null = is_null; - column_declaration->children.push_back(std::move(is_null)); - } - - if (is_not) - { - column_declaration->is_not = is_not; - column_declaration->children.push_back(std::move(is_not)); - } + column_declaration->null_modifier = null_modifier; if (default_expression) { diff --git a/tests/queries/0_stateless/01269_creare_with_null.reference b/tests/queries/0_stateless/01269_creare_with_null.reference deleted file mode 100644 index fa7b52d9ebf..00000000000 --- a/tests/queries/0_stateless/01269_creare_with_null.reference +++ /dev/null @@ -1 +0,0 @@ -Nullable(Int32) Int32 Nullable(Int32) \ No newline at end of file diff --git a/tests/queries/0_stateless/01269_create_with_null.reference b/tests/queries/0_stateless/01269_create_with_null.reference index 7ef113393d5..739063af67f 100644 --- a/tests/queries/0_stateless/01269_create_with_null.reference +++ b/tests/queries/0_stateless/01269_create_with_null.reference @@ -1,2 +1,4 @@ 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() diff --git a/tests/queries/0_stateless/01269_create_with_null.sql b/tests/queries/0_stateless/01269_create_with_null.sql index 68fa130e0da..856b6ea75f4 100644 --- a/tests/queries/0_stateless/01269_create_with_null.sql +++ b/tests/queries/0_stateless/01269_create_with_null.sql @@ -1,6 +1,8 @@ DROP TABLE IF EXISTS data_null; DROP TABLE IF EXISTS set_null; +SET data_type_default_nullable='false'; + CREATE TABLE data_null ( a INT NULL, b INT NOT NULL, @@ -9,19 +11,20 @@ CREATE TABLE data_null ( ) engine=Memory(); -INSERT INTO data_null VALUES (1, 2, 3, 4); +INSERT INTO data_null VALUES (NULL, 2, NULL, 4); SELECT toTypeName(a), toTypeName(b), toTypeName(c), toTypeName(d) FROM data_null; +SHOW CREATE TABLE data_null; -CREATE TABLE data_null ( +CREATE TABLE data_null_error ( a Nullable(INT) NULL, b INT NOT NULL, c Nullable(INT) ) engine=Memory(); --{serverError 377} -CREATE TABLE data_null ( +CREATE TABLE data_null_error ( a INT NULL, b Nullable(INT) NOT NULL, c Nullable(INT) @@ -37,6 +40,11 @@ CREATE TABLE set_null ( ) engine=Memory(); -INSERT INTO set_null VALUES (1, 2, 3, 4); +INSERT INTO set_null VALUES (NULL, 2, NULL, NULL); SELECT toTypeName(a), toTypeName(b), toTypeName(c), toTypeName(d) FROM set_null; + +SHOW CREATE TABLE set_null; + +DROP TABLE data_null; +DROP TABLE set_null;