mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-17 20:02:05 +00:00
commit
20b8e1e9ec
@ -376,6 +376,7 @@ struct Settings : public SettingsCollection<Settings>
|
||||
M(SettingBool, materialize_ttl_after_modify, true, "Apply TTL for old data, after ALTER MODIFY TTL query", 0) \
|
||||
\
|
||||
M(SettingBool, allow_experimental_geo_types, false, "Allow geo data types such as Point, Ring, Polygon, MultiPolygon", 0) \
|
||||
M(SettingBool, data_type_default_nullable, false, "Data types without NULL or NOT NULL will make Nullable", 0) \
|
||||
\
|
||||
/** Obsolete settings that do nothing but left for compatibility reasons. Remove each one after half a year of obsolescence. */ \
|
||||
\
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
#include <Core/Defines.h>
|
||||
#include <Core/Settings.h>
|
||||
|
||||
#include <IO/WriteBufferFromFile.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
@ -71,6 +72,7 @@ namespace ErrorCodes
|
||||
extern const int BAD_DATABASE_FOR_TEMPORARY_TABLE;
|
||||
extern const int SUSPICIOUS_TYPE_FOR_LOW_CARDINALITY;
|
||||
extern const int DICTIONARY_ALREADY_EXISTS;
|
||||
extern const int ILLEGAL_SYNTAX_FOR_DATA_TYPE;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
}
|
||||
|
||||
@ -276,6 +278,7 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription(
|
||||
|
||||
/** all default_expressions as a single expression list,
|
||||
* mixed with conversion-columns for each explicitly specified type */
|
||||
|
||||
ASTPtr default_expr_list = std::make_shared<ASTExpressionList>();
|
||||
NamesAndTypesList column_names_and_types;
|
||||
|
||||
@ -284,9 +287,23 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription(
|
||||
const auto & col_decl = ast->as<ASTColumnDeclaration &>();
|
||||
|
||||
DataTypePtr column_type = nullptr;
|
||||
|
||||
if (col_decl.type)
|
||||
{
|
||||
column_type = DataTypeFactory::instance().get(col_decl.type);
|
||||
|
||||
if (col_decl.null_modifier)
|
||||
{
|
||||
if (column_type->isNullable())
|
||||
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);
|
||||
}
|
||||
else if (context.getSettingsRef().data_type_default_nullable)
|
||||
{
|
||||
column_type = makeNullable(column_type);
|
||||
}
|
||||
|
||||
column_names_and_types.emplace_back(col_decl.name, column_type);
|
||||
}
|
||||
else
|
||||
|
@ -61,6 +61,12 @@ void ASTColumnDeclaration::formatImpl(const FormatSettings & settings, FormatSta
|
||||
type->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (null_modifier)
|
||||
{
|
||||
settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "")
|
||||
<< (*null_modifier ? "" : "NOT ") << "NULL" << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
|
||||
if (default_expression)
|
||||
{
|
||||
settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << default_specifier << (settings.hilite ? hilite_none : "") << ' ';
|
||||
|
@ -13,6 +13,7 @@ class ASTColumnDeclaration : public IAST
|
||||
public:
|
||||
String name;
|
||||
ASTPtr type;
|
||||
std::optional<bool> null_modifier;
|
||||
String default_specifier;
|
||||
ASTPtr default_expression;
|
||||
ASTPtr comment;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -92,7 +92,8 @@ template <typename NameParser>
|
||||
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<ParserIdentifier>;
|
||||
@ -115,6 +117,8 @@ bool IParserColumnDeclaration<NameParser>::parseImpl(Pos & pos, ASTPtr & node, E
|
||||
NameParser name_parser;
|
||||
ParserIdentifierWithOptionalParameters type_parser;
|
||||
ParserKeyword s_default{"DEFAULT"};
|
||||
ParserKeyword s_null{"NULL"};
|
||||
ParserKeyword s_not{"NOT"};
|
||||
ParserKeyword s_materialized{"MATERIALIZED"};
|
||||
ParserKeyword s_alias{"ALIAS"};
|
||||
ParserKeyword s_comment{"COMMENT"};
|
||||
@ -135,6 +139,7 @@ bool IParserColumnDeclaration<NameParser>::parseImpl(Pos & pos, ASTPtr & node, E
|
||||
*/
|
||||
ASTPtr type;
|
||||
String default_specifier;
|
||||
std::optional<bool> null_modifier;
|
||||
ASTPtr default_expression;
|
||||
ASTPtr comment_expression;
|
||||
ASTPtr codec_expression;
|
||||
@ -163,6 +168,17 @@ 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 (s_not.ignore(pos, expected))
|
||||
{
|
||||
if (!s_null.ignore(pos, expected))
|
||||
return false;
|
||||
null_modifier.emplace(false);
|
||||
}
|
||||
else if (s_null.ignore(pos, expected))
|
||||
null_modifier.emplace(true);
|
||||
}
|
||||
|
||||
if (s_comment.ignore(pos, expected))
|
||||
{
|
||||
@ -193,6 +209,8 @@ bool IParserColumnDeclaration<NameParser>::parseImpl(Pos & pos, ASTPtr & node, E
|
||||
column_declaration->children.push_back(std::move(type));
|
||||
}
|
||||
|
||||
column_declaration->null_modifier = null_modifier;
|
||||
|
||||
if (default_expression)
|
||||
{
|
||||
column_declaration->default_specifier = default_specifier;
|
||||
|
@ -0,0 +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()
|
50
tests/queries/0_stateless/01269_create_with_null.sql
Normal file
50
tests/queries/0_stateless/01269_create_with_null.sql
Normal file
@ -0,0 +1,50 @@
|
||||
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,
|
||||
c Nullable(INT),
|
||||
d INT
|
||||
) engine=Memory();
|
||||
|
||||
|
||||
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_error (
|
||||
a Nullable(INT) NULL,
|
||||
b INT NOT NULL,
|
||||
c Nullable(INT)
|
||||
) engine=Memory(); --{serverError 377}
|
||||
|
||||
|
||||
CREATE TABLE data_null_error (
|
||||
a INT NULL,
|
||||
b Nullable(INT) NOT NULL,
|
||||
c Nullable(INT)
|
||||
) engine=Memory(); --{serverError 377}
|
||||
|
||||
SET data_type_default_nullable='true';
|
||||
|
||||
CREATE TABLE set_null (
|
||||
a INT NULL,
|
||||
b INT NOT NULL,
|
||||
c Nullable(INT),
|
||||
d INT
|
||||
) engine=Memory();
|
||||
|
||||
|
||||
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;
|
Loading…
Reference in New Issue
Block a user