Better declaration and lifetime parser

This commit is contained in:
alesapin 2019-10-08 13:50:57 +03:00
parent 5f81f47637
commit db20681207
3 changed files with 136 additions and 29 deletions

View File

@ -17,8 +17,24 @@ namespace DB
bool ParserDictionaryLifetime::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
ParserLiteral literal_p;
ParserKeyValuePairsList key_value_pairs_p;
ASTPtr ast_lifetime;
auto res = std::make_shared<ASTDictionaryLifetime>();
/// simple lifetime with only maximum value e.g. LIFETIME(300)
if (literal_p.parse(pos, ast_lifetime, expected))
{
auto literal = ast_lifetime->as<const ASTLiteral &>();
if (literal.value.getType() != Field::Types::UInt64)
return false;
res->max_sec = literal.value.get<UInt64>();
node = res;
return true;
}
if (!key_value_pairs_p.parse(pos, ast_lifetime, expected))
return false;
@ -26,7 +42,7 @@ bool ParserDictionaryLifetime::parseImpl(Pos & pos, ASTPtr & node, Expected & ex
if (expr_list.children.size() != 2)
return false;
auto res = std::make_shared<ASTDictionaryLifetime>();
bool initialized_max = false;
for (const auto & elem : expr_list.children)
{
const ASTPair & pair = elem->as<const ASTPair &>();
@ -40,12 +56,15 @@ bool ParserDictionaryLifetime::parseImpl(Pos & pos, ASTPtr & node, Expected & ex
if (pair.first == "min")
res->min_sec = literal->value.get<UInt64>();
else if (pair.first == "max")
{
res->max_sec = literal->value.get<UInt64>();
initialized_max = true;
}
else
return false;
}
if (!res->max_sec || !res->min_sec)
if (!initialized_max)
return false;
node = res;

View File

@ -34,34 +34,46 @@ bool ParserDictionaryAttributeDeclaration::parseImpl(Pos & pos, ASTPtr & node, E
bool injective = false;
bool is_object_id = false;
/// TODO(alesapin) Loop here to avoid strict order
if (!s_default.check_without_moving(pos, expected) &&
!s_expression.check_without_moving(pos, expected) &&
!s_hierarchical.check_without_moving(pos, expected) &&
!s_injective.check_without_moving(pos, expected) &&
!s_is_object_id.check_without_moving(pos, expected))
if (!type_parser.parse(pos, type, expected))
return false;
while(true)
{
if (!type_parser.parse(pos, type, expected))
return false;
if (!default_value && s_default.ignore(pos, expected))
{
if (!default_parser.parse(pos, default_value, expected))
return false;
continue;
}
if (!expression && s_expression.ignore(pos, expected))
{
if (!expression_parser.parse(pos, expression, expected))
return false;
continue;
}
if (!hierarchical && s_hierarchical.ignore(pos, expected))
{
hierarchical = true;
continue;
}
if (!injective && s_injective.ignore(pos, expected))
{
injective = true;
continue;
}
if (!is_object_id && s_is_object_id.ignore(pos, expected))
{
is_object_id = true;
continue;
}
break;
}
if (s_default.ignore(pos, expected))
if (!default_parser.parse(pos, default_value, expected))
return false;
if (s_expression.ignore(pos, expected))
if (!expression_parser.parse(pos, expression, expected))
return false;
if (s_hierarchical.ignore(pos, expected))
hierarchical = true;
if (s_injective.ignore(pos, expected))
injective = true;
if (s_is_object_id.ignore(pos, expected))
is_object_id = true;
auto attribute_declaration = std::make_shared<ASTDictionaryAttributeDeclaration>();
node = attribute_declaration;
tryGetIdentifierNameInto(name, attribute_declaration->name);

View File

@ -166,10 +166,62 @@ TEST(ParserCreateDictionary, AttributesWithMultipleProperties)
EXPECT_EQ(attributes_children[2]->as<ASTDictionaryAttributeDeclaration>()->is_object_id, false);
}
TEST(ParserCreateDictionary, CustomAttributePropertiesOrder)
{
String input = " CREATE DICTIONARY dict3"
" ("
" key_column UInt64 IS_OBJECT_ID DEFAULT 100,"
" second_column UInt8 INJECTIVE HIERARCHICAL DEFAULT 1,"
" third_column UInt8 EXPRESSION rand() % 100 * 77 DEFAULT 2 INJECTIVE HIERARCHICAL"
" )"
" PRIMARY KEY key_column"
" SOURCE(CLICKHOUSE(REPLICA(HOST '127.0.0.1' PRIORITY 1)))"
" LIFETIME(300)";
ParserCreateDictionaryQuery parser;
ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "", 0);
ASTCreateQuery * create = ast->as<ASTCreateQuery>();
/// test attributes
EXPECT_NE(create->dictionary_attributes_list, nullptr);
auto attributes_children = create->dictionary_attributes_list->children;
EXPECT_EQ(attributes_children[0]->as<ASTDictionaryAttributeDeclaration>()->name, "key_column");
EXPECT_EQ(attributes_children[1]->as<ASTDictionaryAttributeDeclaration>()->name, "second_column");
EXPECT_EQ(attributes_children[2]->as<ASTDictionaryAttributeDeclaration>()->name, "third_column");
EXPECT_EQ(attributes_children[0]->as<ASTDictionaryAttributeDeclaration>()->default_value->as<ASTLiteral>()->value.get<UInt64>(), 100);
EXPECT_EQ(attributes_children[1]->as<ASTDictionaryAttributeDeclaration>()->default_value->as<ASTLiteral>()->value.get<UInt64>(), 1);
EXPECT_EQ(attributes_children[2]->as<ASTDictionaryAttributeDeclaration>()->default_value->as<ASTLiteral>()->value.get<UInt64>(), 2);
EXPECT_EQ(attributes_children[0]->as<ASTDictionaryAttributeDeclaration>()->expression, nullptr);
EXPECT_EQ(attributes_children[1]->as<ASTDictionaryAttributeDeclaration>()->expression, nullptr);
EXPECT_EQ(serializeAST(*attributes_children[2]->as<ASTDictionaryAttributeDeclaration>()->expression, true), "(rand() % 100) * 77");
EXPECT_EQ(attributes_children[0]->as<ASTDictionaryAttributeDeclaration>()->hierarchical, false);
EXPECT_EQ(attributes_children[1]->as<ASTDictionaryAttributeDeclaration>()->hierarchical, true);
EXPECT_EQ(attributes_children[2]->as<ASTDictionaryAttributeDeclaration>()->hierarchical, true);
EXPECT_EQ(attributes_children[0]->as<ASTDictionaryAttributeDeclaration>()->injective, false);
EXPECT_EQ(attributes_children[1]->as<ASTDictionaryAttributeDeclaration>()->injective, true);
EXPECT_EQ(attributes_children[2]->as<ASTDictionaryAttributeDeclaration>()->injective, true);
EXPECT_EQ(attributes_children[0]->as<ASTDictionaryAttributeDeclaration>()->is_object_id, true);
EXPECT_EQ(attributes_children[1]->as<ASTDictionaryAttributeDeclaration>()->is_object_id, false);
EXPECT_EQ(attributes_children[2]->as<ASTDictionaryAttributeDeclaration>()->is_object_id, false);
/// lifetime test
auto lifetime = create->dictionary->lifetime;
EXPECT_EQ(lifetime->min_sec, 0);
EXPECT_EQ(lifetime->max_sec, 300);
}
TEST(ParserCreateDictionary, NestedSource)
{
String input = " CREATE DICTIONARY dict3"
String input = " CREATE DICTIONARY dict4"
" ("
" key_column UInt64,"
" second_column UInt8,"
@ -184,7 +236,7 @@ TEST(ParserCreateDictionary, NestedSource)
ParserCreateDictionaryQuery parser;
ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "", 0);
ASTCreateQuery * create = ast->as<ASTCreateQuery>();
EXPECT_EQ(create->table, "dict3");
EXPECT_EQ(create->table, "dict4");
EXPECT_EQ(create->database, "");
/// source test
@ -212,3 +264,27 @@ TEST(ParserCreateDictionary, NestedSource)
EXPECT_EQ(children[4]->as<ASTPair>()->first, "password");
EXPECT_EQ(children[4]->as<ASTPair>()->second->as<ASTLiteral>()->value.get<String>(), "");
}
TEST(ParserCreateDictionary, Formatting)
{
String input = " CREATE DICTIONARY test.dict5"
" ("
" key_column1 UInt64 DEFAULT 1 HIERARCHICAL INJECTIVE,"
" key_column2 String DEFAULT '',"
" second_column UInt8 EXPRESSION intDiv(50, rand() % 1000),"
" third_column UInt8"
" )"
" PRIMARY KEY key_column1, key_column2"
" SOURCE(MYSQL(HOST 'localhost' PORT 9000 USER 'default' REPLICA(HOST '127.0.0.1' PRIORITY 1) PASSWORD ''))"
" LAYOUT(CACHE(size_in_cells 50))"
" LIFETIME(MIN 1 MAX 10)"
" RANGE(MIN second_column MAX third_column)";
ParserCreateDictionaryQuery parser;
ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "", 0);
ASTCreateQuery * create = ast->as<ASTCreateQuery>();
auto str = serializeAST(*create, true);
EXPECT_EQ(str, "CREATE DICTIONARY test.dict5 (`key_column1` UInt64 DEFAULT 1 HIERARCHICAL INJECTIVE, `key_column2` String DEFAULT '', `second_column` UInt8 EXPRESSION intDiv(50, rand() % 1000), `third_column` UInt8) PRIMARY KEY key_column1, key_column2 MYSQL(HOST 'localhost' PORT 9000 USER 'default' REPLICA (HOST '127.0.0.1' PRIORITY 1) PASSWORD '') LIFETIME(MIN 1, MAX 10) LAYOUT(CACHE(SIZE_IN_CELLS 50)) RANGE(MIN second_column, MAX third_column)");
}