#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace VirtualColumnUtils { String chooseSuffix(const NamesAndTypesList & columns, const String & name) { int id = 0; String current_suffix; while (true) { bool done = true; for (const auto & it : columns) if (it.name == name + current_suffix) { done = false; break; } if (done) break; ++id; current_suffix = toString(id); } return current_suffix; } String chooseSuffixForSet(const NamesAndTypesList & columns, const std::vector & names) { int id = 0; String current_suffix; while (true) { bool done = true; for (const auto & it : columns) { for (size_t i = 0; i < names.size(); ++i) { if (it.name == names[i] + current_suffix) { done = false; break; } } if (!done) break; } if (done) break; ++id; current_suffix = toString(id); } return current_suffix; } void rewriteEntityInAst(ASTPtr ast, const String & column_name, const Field & value) { auto & select = ast->as(); if (!select.with()) select.setExpression(ASTSelectQuery::Expression::WITH, std::make_shared()); auto literal = std::make_shared(value); literal->alias = column_name; literal->prefer_alias_to_column_name = true; select.with()->children.push_back(literal); } /// Verifying that the function depends only on the specified columns static bool isValidFunction(const ASTPtr & expression, const NameSet & columns) { for (size_t i = 0; i < expression->children.size(); ++i) if (!isValidFunction(expression->children[i], columns)) return false; if (auto opt_name = IdentifierSemantic::getColumnName(expression)) return columns.count(*opt_name); return true; } /// Extract all subfunctions of the main conjunction, but depending only on the specified columns static void extractFunctions(const ASTPtr & expression, const NameSet & columns, std::vector & result) { const auto * function = expression->as(); if (function && function->name == "and") { for (size_t i = 0; i < function->arguments->children.size(); ++i) extractFunctions(function->arguments->children[i], columns, result); } else if (isValidFunction(expression, columns)) { result.push_back(expression->clone()); } } /// Construct a conjunction from given functions static ASTPtr buildWhereExpression(const ASTs & functions) { if (functions.size() == 0) return nullptr; if (functions.size() == 1) return functions[0]; ASTPtr new_query = std::make_shared(); auto & new_function = new_query->as(); new_function.name = "and"; new_function.arguments = std::make_shared(); new_function.arguments->children = functions; new_function.children.push_back(new_function.arguments); return new_query; } void filterBlockWithQuery(const ASTPtr & query, Block & block, const Context & context) { const auto & select = query->as(); if (!select.where() && !select.prewhere()) return; NameSet columns; for (const auto & it : block.getNamesAndTypesList()) columns.insert(it.name); /// We will create an expression that evaluates the expressions in WHERE and PREWHERE, depending only on the existing columns. std::vector functions; if (select.where()) extractFunctions(select.where(), columns, functions); if (select.prewhere()) extractFunctions(select.prewhere(), columns, functions); ASTPtr expression_ast = buildWhereExpression(functions); if (!expression_ast) return; /// Let's analyze and calculate the expression. auto syntax_result = SyntaxAnalyzer(context).analyze(expression_ast, block.getNamesAndTypesList()); ExpressionAnalyzer analyzer(expression_ast, syntax_result, context); ExpressionActionsPtr actions = analyzer.getActions(false); Block block_with_filter = block; actions->execute(block_with_filter); /// Filter the block. String filter_column_name = expression_ast->getColumnName(); ColumnPtr filter_column = block_with_filter.getByName(filter_column_name).column->convertToFullColumnIfConst(); const IColumn::Filter & filter = typeid_cast(*filter_column).getData(); for (size_t i = 0; i < block.columns(); ++i) { ColumnPtr & column = block.safeGetByPosition(i).column; column = column->filter(filter, -1); } } } }