detect cycles, deduce and check types. [#METR-12739]

This commit is contained in:
Andrey Mironov 2014-09-29 17:32:16 +04:00
parent 1d04061a0e
commit 529674ce6a
4 changed files with 87 additions and 49 deletions

View File

@ -98,4 +98,21 @@ ASTPtr makeASTFunction(const String & name, Args &&... args)
return result;
}
template <typename... Args>
ASTPtr makeASTFunction(const String & name, const StringRange & function_range,
const StringRange & arguments_range, Args &&... args)
{
const auto function = new ASTFunction{function_range};
ASTPtr result{function};
function->name = name;
function->arguments = new ASTExpressionList{arguments_range};
function->children.push_back(function->arguments);
function->arguments->children = { std::forward<Args>(args)... };
return result;
}
}

View File

@ -117,6 +117,10 @@ bool IParserColumnDeclaration<NameParser>::parseImpl(Pos & pos, Pos end, ASTPtr
ParserExpressionElement expr_parser;
const auto begin = pos;
const auto reset_pos_and_return = [&pos, begin] {
pos = begin;
return false;
};
/// mandatory column name
ASTPtr name;
@ -153,17 +157,10 @@ bool IParserColumnDeclaration<NameParser>::parseImpl(Pos & pos, Pos end, ASTPtr
ws.ignore(pos, end, expected);
if (!expr_parser.parse(pos, end, default_expression, expected))
{
pos = begin;
return false;
}
return reset_pos_and_return();
}
else if (!type)
{
/// reject sole column name without type
pos = begin;
return false;
}
return reset_pos_and_return(); /// reject sole column name without type
const auto column_declaration = new ASTColumnDeclaration{StringRange{begin, pos}};
node = column_declaration;

View File

@ -239,63 +239,93 @@ NamesAndTypesList InterpreterCreateQuery::parseColumns(ASTPtr expression_list, c
{
/// list of table columns in correct order
NamesAndTypesList columns{};
/// list of processed columns for type-deduction
NamesAndTypesList processed_columns{};
auto & columns_list = typeid_cast<ASTExpressionList &>(*expression_list);
/// List of columns requiring type-deduction or default_expression type-check
using postprocess_column = std::pair<NameAndTypePair *, ASTColumnDeclaration *>;
std::vector<postprocess_column> postprocess_columns{};
/// Columns requiring type-deduction or default_expression type-check
std::vector<postprocess_column> defaulted_columns{};
/** all default_expressions as a single expression list,
* mixed with conversion-columns for each explicitly specified type */
ASTPtr default_expr_list{new ASTExpressionList};
default_expr_list->children.reserve(columns_list.children.size());
/// helper for setting aliases and chaining result to other functions
const auto set_alias = [] (ASTPtr ast, const String & alias) {
dynamic_cast<ASTWithAlias &>(*ast).alias = alias;
return ast;
};
for (auto & ast : columns_list.children)
{
auto & col_decl = typeid_cast<ASTColumnDeclaration &>(*ast);
/// deduce type from default_expression if no type specified
if (col_decl.type)
{
const auto & type_range = col_decl.type->range;
columns.emplace_back(
col_decl.name,
columns.emplace_back(col_decl.name,
data_type_factory.get({ type_range.first, type_range.second }));
processed_columns.emplace_back(columns.back());
}
else
columns.emplace_back(col_decl.name, nullptr);
/// add column to postprocess if there is either no type or a default_expression specified
if (!col_decl.type || col_decl.default_expression)
/// add column to postprocessing if there is a default_expression specified
if (col_decl.default_expression)
{
postprocess_columns.emplace_back(&columns.back(), &col_decl);
defaulted_columns.emplace_back(&columns.back(), &col_decl);
/** for columns with explicitly-specified type create two expressions:
* 1. default_expression aliased as column name with _tmp suffix
* 2. conversion of expression (1) to explicitly-specified type alias as column name */
if (col_decl.type)
{
const auto tmp_column_name = col_decl.name + "_tmp";
const auto & final_column_name = col_decl.name;
const auto conversion_function_name = "to" + columns.back().type->getName();
default_expr_list->children.emplace_back(set_alias(
makeASTFunction(conversion_function_name, ASTPtr{new ASTIdentifier{{}, tmp_column_name}}),
final_column_name));
default_expr_list->children.emplace_back(set_alias(col_decl.default_expression->clone(), tmp_column_name));
}
else
default_expr_list->children.emplace_back(set_alias(col_decl.default_expression->clone(), col_decl.name));
}
}
/// @todo check for presence of cycles in default_expressions, throw if detected
/// deduce type or wrap default_expression in conversion-function if necessary
for (auto & column : postprocess_columns)
/// set missing types and wrap default_expression's in a conversion-function if necessary
if (!defaulted_columns.empty())
{
const auto name_and_type_ptr = column.first;
const auto col_decl_ptr = column.second;
const auto actions = ExpressionAnalyzer{default_expr_list, context, columns}.getActions(true);
const auto block = actions->getSampleBlock();
/// deduce real type
auto type = deduceType(col_decl_ptr->default_expression, processed_columns);
if (!name_and_type_ptr->type)
name_and_type_ptr->type = type;
else if (typeid(*name_and_type_ptr->type) != typeid(*type))
for (auto & column : defaulted_columns)
{
/// wrap default_expression in a type-conversion function
col_decl_ptr->default_expression = makeASTFunction(
"to" + name_and_type_ptr->type->getName(),
col_decl_ptr->default_expression);
const auto name_and_type_ptr = column.first;
const auto col_decl_ptr = column.second;
col_decl_ptr->children.clear();
col_decl_ptr->children.push_back(col_decl_ptr->type);
col_decl_ptr->children.push_back(col_decl_ptr->default_expression);
if (name_and_type_ptr->type)
{
const auto & tmp_column = block.getByName(col_decl_ptr->name + "_tmp");
/// type mismatch between explicitly specified and deduced type, add conversion
if (typeid(*name_and_type_ptr->type) != typeid(*tmp_column.type))
{
col_decl_ptr->default_expression = makeASTFunction(
"to" + name_and_type_ptr->type->getName(),
col_decl_ptr->default_expression);
col_decl_ptr->children.clear();
col_decl_ptr->children.push_back(col_decl_ptr->type);
col_decl_ptr->children.push_back(col_decl_ptr->default_expression);
}
}
else
name_and_type_ptr->type = block.getByName(name_and_type_ptr->name).type;
}
processed_columns.emplace_back(*name_and_type_ptr);
}
return *DataTypeNested::expandNestedColumns(columns);

View File

@ -210,14 +210,8 @@ bool ParserVariableArityOperatorList::parseImpl(Pos & pos, Pos end, ASTPtr & nod
if (!arguments)
{
ASTFunction * function = new ASTFunction;
ASTPtr function_node = function;
arguments = new ASTExpressionList;
function->arguments = arguments;
function->children.push_back(arguments);
function->name = function_name;
arguments->children.push_back(node);
node = function_node;
node = makeASTFunction(function_name, node);
arguments = static_cast<ASTFunction &>(*node).arguments;
}
ASTPtr elem;