diff --git a/src/Parsers/ASTCreateQuery.cpp b/src/Parsers/ASTCreateQuery.cpp index 8c5681c3a9c..4efe5476395 100644 --- a/src/Parsers/ASTCreateQuery.cpp +++ b/src/Parsers/ASTCreateQuery.cpp @@ -124,6 +124,8 @@ ASTPtr ASTColumns::clone() const res->set(res->indices, indices->clone()); if (constraints) res->set(res->constraints, constraints->clone()); + if (primary_key) + res->set(res->primary_key, primary_key->clone()); return res; } diff --git a/src/Parsers/ASTCreateQuery.h b/src/Parsers/ASTCreateQuery.h index 5d69d86bd61..454a3993dfd 100644 --- a/src/Parsers/ASTCreateQuery.h +++ b/src/Parsers/ASTCreateQuery.h @@ -41,6 +41,7 @@ public: ASTExpressionList * columns = nullptr; ASTExpressionList * indices = nullptr; ASTExpressionList * constraints = nullptr; + IAST * primary_key = nullptr; String getID(char) const override { return "Columns definition"; } diff --git a/src/Parsers/ParserCreateQuery.cpp b/src/Parsers/ParserCreateQuery.cpp index fb0fd20b4ed..1afdfac0461 100644 --- a/src/Parsers/ParserCreateQuery.cpp +++ b/src/Parsers/ParserCreateQuery.cpp @@ -19,6 +19,11 @@ namespace DB { +namespace ErrorCodes +{ + extern const int BAD_ARGUMENTS; +} + bool ParserNestedTable::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) { ParserToken open(TokenType::OpeningRoundBracket); @@ -150,10 +155,12 @@ bool ParserTablePropertyDeclaration::parseImpl(Pos & pos, ASTPtr & node, Expecte { ParserKeyword s_index("INDEX"); ParserKeyword s_constraint("CONSTRAINT"); + ParserKeyword s_primary_key("PRIMARY KEY"); ParserIndexDeclaration index_p; ParserConstraintDeclaration constraint_p; ParserColumnDeclaration column_p{true, true}; + ParserExpression primary_key_p; ASTPtr new_node = nullptr; @@ -167,6 +174,11 @@ bool ParserTablePropertyDeclaration::parseImpl(Pos & pos, ASTPtr & node, Expecte if (!constraint_p.parse(pos, new_node, expected)) return false; } + else if (s_primary_key.ignore(pos, expected)) + { + if (!primary_key_p.parse(pos, new_node, expected)) + return false; + } else { if (!column_p.parse(pos, new_node, expected)) @@ -201,6 +213,7 @@ bool ParserTablePropertiesDeclarationList::parseImpl(Pos & pos, ASTPtr & node, E ASTPtr columns = std::make_shared(); ASTPtr indices = std::make_shared(); ASTPtr constraints = std::make_shared(); + ASTPtr primary_key; for (const auto & elem : list->children) { @@ -210,6 +223,14 @@ bool ParserTablePropertiesDeclarationList::parseImpl(Pos & pos, ASTPtr & node, E indices->children.push_back(elem); else if (elem->as()) constraints->children.push_back(elem); + else if (elem->as() || elem->as()) + { + if (primary_key) + { + throw Exception("Multiple primary keys are not allowed.", ErrorCodes::BAD_ARGUMENTS); + } + primary_key = elem; + } else return false; } @@ -222,6 +243,8 @@ bool ParserTablePropertiesDeclarationList::parseImpl(Pos & pos, ASTPtr & node, E res->set(res->indices, indices); if (!constraints->children.empty()) res->set(res->constraints, constraints); + if (primary_key) + res->set(res->primary_key, primary_key); node = res; @@ -472,6 +495,15 @@ bool ParserCreateTableQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe query->set(query->columns_list, columns_list); query->set(query->storage, storage); + if (query->storage && query->columns_list && query->columns_list->primary_key) + { + if (query->storage->primary_key) + { + throw Exception("Multiple primary keys are not allowed.", ErrorCodes::BAD_ARGUMENTS); + } + query->storage->primary_key = query->columns_list->primary_key; + } + tryGetIdentifierNameInto(as_database, query->as_database); tryGetIdentifierNameInto(as_table, query->as_table); query->set(query->select, select); diff --git a/src/Parsers/ParserCreateQuery.h b/src/Parsers/ParserCreateQuery.h index 60933f7384d..3c20446eb15 100644 --- a/src/Parsers/ParserCreateQuery.h +++ b/src/Parsers/ParserCreateQuery.h @@ -391,6 +391,7 @@ protected: * ... * INDEX name1 expr TYPE type1(args) GRANULARITY value, * ... + * PRIMARY KEY expr * ) ENGINE = engine * * Or: diff --git a/tests/queries/0_stateless/01516_create_table_primary_key.reference b/tests/queries/0_stateless/01516_create_table_primary_key.reference new file mode 100644 index 00000000000..07e39214354 --- /dev/null +++ b/tests/queries/0_stateless/01516_create_table_primary_key.reference @@ -0,0 +1,4 @@ +1 +1 +1 1 +1 1 diff --git a/tests/queries/0_stateless/01516_create_table_primary_key.sql b/tests/queries/0_stateless/01516_create_table_primary_key.sql new file mode 100644 index 00000000000..0f7384ca1b3 --- /dev/null +++ b/tests/queries/0_stateless/01516_create_table_primary_key.sql @@ -0,0 +1,43 @@ +DROP DATABASE IF EXISTS test_01516; +CREATE DATABASE test_01516 ENGINE=Ordinary; -- Full ATTACH requires UUID with Atomic +USE test_01516; + +DROP TABLE IF EXISTS primary_key_test; + +CREATE TABLE primary_key_test(v Int32, PRIMARY KEY(v)) ENGINE=ReplacingMergeTree ORDER BY v; +INSERT INTO primary_key_test VALUES (1), (1), (1); +DETACH TABLE primary_key_test; +ATTACH TABLE primary_key_test(v Int32, PRIMARY KEY(v)) ENGINE=ReplacingMergeTree ORDER BY v; +SELECT * FROM primary_key_test FINAL; +DROP TABLE primary_key_test; + +CREATE TABLE primary_key_test(v Int32) ENGINE=ReplacingMergeTree ORDER BY v PRIMARY KEY(v); +INSERT INTO primary_key_test VALUES (1), (1), (1); +DETACH TABLE primary_key_test; +ATTACH TABLE primary_key_test(v Int32) ENGINE=ReplacingMergeTree ORDER BY v PRIMARY KEY(v); +SELECT * FROM primary_key_test FINAL; +DROP TABLE primary_key_test; + +CREATE TABLE primary_key_test(v Int32, PRIMARY KEY(v), PRIMARY KEY(v)) ENGINE=ReplacingMergeTree ORDER BY v; -- { clientError 36; } + +CREATE TABLE primary_key_test(v Int32, PRIMARY KEY(v)) ENGINE=ReplacingMergeTree ORDER BY v PRIMARY KEY(v); -- { clientError 36; } + +CREATE TABLE primary_key_test(v1 Int32, v2 Int32, PRIMARY KEY(v1, v2)) ENGINE=ReplacingMergeTree ORDER BY (v1, v2); +INSERT INTO primary_key_test VALUES (1, 1), (1, 1), (1, 1); +DETACH TABLE primary_key_test; +ATTACH TABLE primary_key_test(v1 Int32, v2 Int32, PRIMARY KEY(v1, v2)) ENGINE=ReplacingMergeTree ORDER BY (v1, v2); +SELECT * FROM primary_key_test FINAL; +DROP TABLE primary_key_test; + +CREATE TABLE primary_key_test(v1 Int32, v2 Int32) ENGINE=ReplacingMergeTree ORDER BY (v1, v2) PRIMARY KEY(v1, v2); +INSERT INTO primary_key_test VALUES (1, 1), (1, 1), (1, 1); +DETACH TABLE primary_key_test; +ATTACH TABLE primary_key_test(v1 Int32, v2 Int32) ENGINE=ReplacingMergeTree ORDER BY (v1, v2) PRIMARY KEY(v1, v2); +SELECT * FROM primary_key_test FINAL; +DROP TABLE primary_key_test; + +CREATE TABLE primary_key_test(v1 Int32, v2 Int32, PRIMARY KEY(v1, v2), PRIMARY KEY(v1, v2)) ENGINE=ReplacingMergeTree ORDER BY (v1, v2); -- { clientError 36; } + +CREATE TABLE primary_key_test(v1 Int32, v2 Int32, PRIMARY KEY(v1, v2)) ENGINE=ReplacingMergeTree ORDER BY (v1, v2) PRIMARY KEY(v1, v2); -- { clientError 36; } + +DROP DATABASE test_01516; \ No newline at end of file