#include #include #include #include #include #include #include #include #include #include namespace DB { static bool isCompatible(const IAST & node) { if (const ASTFunction * function = typeid_cast(&node)) { String name = function->name; if (!(name == "and" || name == "or" || name == "not" || name == "equals" || name == "notEquals" || name == "greater" || name == "less" || name == "lessOrEquals" || name == "greaterOrEquals")) return false; for (const auto & expr : function->arguments->children) if (!isCompatible(*expr.get())) return false; return true; } if (const ASTLiteral * literal = typeid_cast(&node)) { /// Foreign databases often have no support for Array and Tuple literals. if (literal->value.getType() == Field::Types::Array || literal->value.getType() == Field::Types::Tuple) return false; return true; } if (typeid_cast(&node)) return true; return false; } String transformQueryForExternalDatabase( const IAST & query, const NamesAndTypesList & available_columns, const String & database, const String & table, const Context & context) { ExpressionAnalyzer analyzer(query.clone(), context, {}, available_columns); const Names & used_columns = analyzer.getRequiredColumns(); auto select = std::make_shared(); select->replaceDatabaseAndTable(database, table); auto select_expr_list = std::make_shared(); for (const auto & name : used_columns) select_expr_list->children.push_back(std::make_shared(StringRange(), name)); select->select_expression_list = std::move(select_expr_list); /** If there was WHERE, * copy it to transformed query if it is compatible, * or if it is AND expression, * copy only compatible parts of it. */ const ASTPtr & original_where = typeid_cast(query).where_expression; if (original_where) { if (isCompatible(*original_where)) { select->where_expression = original_where; } else if (const ASTFunction * function = typeid_cast(original_where.get())) { if (function->name == "and") { auto new_function_and = std::make_shared(); auto new_function_and_arguments = std::make_shared(); new_function_and->arguments = new_function_and_arguments; new_function_and->children.push_back(new_function_and_arguments); for (const auto & elem : function->arguments->children) if (isCompatible(*elem)) new_function_and_arguments->children.push_back(elem); select->where_expression = std::move(new_function_and); } } } return queryToString(select); } }