bool filterBlockWithQuery(ASTPtr query, Block & block, const Context & context) { query = query->clone(); const ASTSelectQuery & select = typeid_cast<ASTSelectQuery & >(*query); if (!select.where_expression && !select.prewhere_expression) return false; NameSet columns; for (const auto & it : block.getColumnsList()) columns.insert(it.name); /// Составим выражение, вычисляющее выражения в WHERE и PREWHERE, зависящие только от имеющихся столбцов. std::vector<ASTPtr> functions; if (select.where_expression) extractFunctions(select.where_expression, columns, functions); if (select.prewhere_expression) extractFunctions(select.prewhere_expression, columns, functions); ASTPtr expression_ast = buildWhereExpression(functions); if (!expression_ast) return false; /// Распарсим и вычислим выражение. ExpressionAnalyzer analyzer(expression_ast, context, {}, block.getColumnsList()); ExpressionActionsPtr actions = analyzer.getActions(false); actions->execute(block); /// Отфильтруем блок. String filter_column_name = expression_ast->getColumnName(); ColumnPtr filter_column = block.getByName(filter_column_name).column; if (auto converted = filter_column->convertToFullColumnIfConst()) filter_column = converted; const IColumn::Filter & filter = dynamic_cast<ColumnUInt8 &>(*filter_column).getData(); if (std::accumulate(filter.begin(), filter.end(), 0ul) == filter.size()) return false; for (size_t i = 0; i < block.columns(); ++i) { ColumnPtr & column = block.safeGetByPosition(i).column; column = column->filter(filter, -1); } return true; }
bool filterBlockWithQuery(const ASTPtr & query, Block & block, const Context & context) { const ASTSelectQuery & select = typeid_cast<const ASTSelectQuery & >(*query); if (!select.where_expression && !select.prewhere_expression) return false; NameSet columns; for (const auto & it : block.getColumnsList()) 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<ASTPtr> functions; if (select.where_expression) extractFunctions(select.where_expression, columns, functions); if (select.prewhere_expression) extractFunctions(select.prewhere_expression, columns, functions); ASTPtr expression_ast = buildWhereExpression(functions); if (!expression_ast) return false; /// Let's parse and calculate the expression. ExpressionAnalyzer analyzer(expression_ast, context, {}, block.getColumnsList()); ExpressionActionsPtr actions = analyzer.getActions(false); actions->execute(block); /// Filter the block. String filter_column_name = expression_ast->getColumnName(); ColumnPtr filter_column = block.getByName(filter_column_name).column; if (auto converted = filter_column->convertToFullColumnIfConst()) filter_column = converted; const IColumn::Filter & filter = dynamic_cast<ColumnUInt8 &>(*filter_column).getData(); if (countBytesInFilter(filter) == 0) return false; for (size_t i = 0; i < block.columns(); ++i) { ColumnPtr & column = block.safeGetByPosition(i).column; column = column->filter(filter, -1); } return true; }
int main(int argc, char ** argv) { using namespace DB; try { std::string input = "SELECT x, s1, s2, " "/*" "2 + x * 2, x * 2, x % 3 == 1, " "s1 == 'abc', s1 == s2, s1 != 'abc', s1 != s2, " "s1 < 'abc', s1 < s2, s1 > 'abc', s1 > s2, " "s1 <= 'abc', s1 <= s2, s1 >= 'abc', s1 >= s2, " "*/" "s1 < s2 AND x % 3 < x % 5"; ParserSelectQuery parser; ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "", 0); formatAST(*ast, std::cerr); std::cerr << std::endl; Context context = Context::createGlobal(); NamesAndTypesList columns { {"x", std::make_shared<DataTypeInt16>()}, {"s1", std::make_shared<DataTypeString>()}, {"s2", std::make_shared<DataTypeString>()} }; auto syntax_result = SyntaxAnalyzer(context, {}).analyze(ast, columns); ExpressionAnalyzer analyzer(ast, syntax_result, context); ExpressionActionsChain chain(context); analyzer.appendSelect(chain, false); analyzer.appendProjectResult(chain); chain.finalize(); ExpressionActionsPtr expression = chain.getLastActions(); size_t n = argc == 2 ? atoi(argv[1]) : 10; Block block; { ColumnWithTypeAndName column; column.name = "x"; column.type = std::make_shared<DataTypeInt16>(); auto col = ColumnInt16::create(); auto & vec_x = col->getData(); vec_x.resize(n); for (size_t i = 0; i < n; ++i) vec_x[i] = i % 9; column.column = std::move(col); block.insert(column); } const char * strings[] = {"abc", "def", "abcd", "defg", "ac"}; { ColumnWithTypeAndName column; column.name = "s1"; column.type = std::make_shared<DataTypeString>(); auto col = ColumnString::create(); for (size_t i = 0; i < n; ++i) col->insert(std::string(strings[i % 5])); column.column = std::move(col); block.insert(column); } { ColumnWithTypeAndName column; column.name = "s2"; column.type = std::make_shared<DataTypeString>(); auto col = ColumnString::create(); for (size_t i = 0; i < n; ++i) col->insert(std::string(strings[i % 3])); column.column = std::move(col); block.insert(column); } { Stopwatch stopwatch; stopwatch.start(); expression->execute(block); stopwatch.stop(); std::cout << std::fixed << std::setprecision(2) << "Elapsed " << stopwatch.elapsedSeconds() << " sec." << ", " << n / stopwatch.elapsedSeconds() << " rows/sec." << std::endl; } auto is = std::make_shared<OneBlockInputStream>(block); LimitBlockInputStream lis(is, 20, std::max(0, static_cast<int>(n) - 20)); WriteBufferFromOStream out_buf(std::cout); BlockOutputStreamPtr out = FormatFactory::instance().getOutput("TabSeparated", out_buf, block, context); copyData(lis, *out); } catch (const Exception & e) { std::cerr << e.displayText() << std::endl; } return 0; }