String getTableDefinitionFromCreateQuery(const ASTPtr & query)
{
    ASTPtr query_clone = query->clone();
    ASTCreateQuery & create = typeid_cast<ASTCreateQuery &>(*query_clone.get());

    /// We remove everything that is not needed for ATTACH from the query.
    create.attach = true;
    create.database.clear();
    create.as_database.clear();
    create.as_table.clear();
    create.if_not_exists = false;
    create.is_populate = false;

    /// For views it is necessary to save the SELECT query itself, for the rest - on the contrary
    if (!create.is_view && !create.is_materialized_view)
        create.select = nullptr;

    create.format = nullptr;
    create.out_file = nullptr;

    std::ostringstream statement_stream;
    formatAST(create, statement_stream, false);
    statement_stream << '\n';
    return statement_stream.str();
}
/// Extract all subfunctions of the main conjunction, but depending only on the specified columns
static void extractFunctions(ASTPtr expression, const NameSet & columns, std::vector<ASTPtr> & result)
{
    const ASTFunction * function = typeid_cast<const ASTFunction *>(&*expression);
    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());
    }
}
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;
}
String getTableDefinitionFromCreateQuery(const ASTPtr & query)
{
	ASTPtr query_clone = query->clone();
	ASTCreateQuery & create = typeid_cast<ASTCreateQuery &>(*query_clone.get());

	/// Удаляем из запроса всё, что не нужно для ATTACH.
	create.attach = true;
	create.database.clear();
	create.as_database.clear();
	create.as_table.clear();
	create.if_not_exists = false;
	create.is_populate = false;

	String engine = typeid_cast<ASTFunction &>(*create.storage).name;

	/// Для engine VIEW необходимо сохранить сам селект запрос, для остальных - наоборот
	if (engine != "View" && engine != "MaterializedView")
		create.select = nullptr;

	std::ostringstream statement_stream;
	formatAST(create, statement_stream, 0, false);
	statement_stream << '\n';
	return statement_stream.str();
}
InterpreterSystemQuery::InterpreterSystemQuery(const ASTPtr & query_ptr_, Context & context_)
        : query_ptr(query_ptr_->clone()), context(context_), log(&Poco::Logger::get("InterpreterSystemQuery")) {}