#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace Setting { extern const SettingsBool transform_null_in; } namespace ErrorCodes { extern const int UNSUPPORTED_METHOD; } namespace { class CollectSetsVisitor : public ConstInDepthQueryTreeVisitor { public: explicit CollectSetsVisitor(PlannerContext & planner_context_) : planner_context(planner_context_) {} void visitImpl(const QueryTreeNodePtr & node) { if (const auto * constant_node = node->as()) /// Collect sets from source expression as well. /// Most likely we will not build them, but those sets could be requested during analysis. if (constant_node->hasSourceExpression()) collectSets(constant_node->getSourceExpression(), planner_context); auto * function_node = node->as(); if (!function_node || !isNameOfInFunction(function_node->getFunctionName())) return; auto in_first_argument = function_node->getArguments().getNodes().at(0); auto in_second_argument = function_node->getArguments().getNodes().at(1); auto in_second_argument_node_type = in_second_argument->getNodeType(); const auto & settings = planner_context.getQueryContext()->getSettingsRef(); auto & sets = planner_context.getPreparedSets(); /// Tables and table functions are replaced with subquery at Analysis stage, except special Set table. auto * second_argument_table = in_second_argument->as(); StorageSet * storage_set = second_argument_table != nullptr ? dynamic_cast(second_argument_table->getStorage().get()) : nullptr; if (storage_set) { /// Handle storage_set as ready set. auto set_key = in_second_argument->getTreeHash(); if (sets.findStorage(set_key)) return; sets.addFromStorage(set_key, storage_set->getSet()); } else if (const auto * constant_node = in_second_argument->as()) { auto set = getSetElementsForConstantValue( in_first_argument->getResultType(), constant_node->getValue(), constant_node->getResultType(), settings[Setting::transform_null_in]); DataTypes set_element_types = {in_first_argument->getResultType()}; const auto * left_tuple_type = typeid_cast(set_element_types.front().get()); if (left_tuple_type && left_tuple_type->getElements().size() != 1) set_element_types = left_tuple_type->getElements(); set_element_types = Set::getElementTypes(std::move(set_element_types), settings[Setting::transform_null_in]); auto set_key = in_second_argument->getTreeHash(); if (sets.findTuple(set_key, set_element_types)) return; sets.addFromTuple(set_key, std::move(set), settings); } else if (in_second_argument_node_type == QueryTreeNodeType::QUERY || in_second_argument_node_type == QueryTreeNodeType::UNION || in_second_argument_node_type == QueryTreeNodeType::TABLE) { auto set_key = in_second_argument->getTreeHash(); if (sets.findSubquery(set_key)) return; auto subquery_to_execute = in_second_argument; if (in_second_argument->as()) subquery_to_execute = buildSubqueryToReadColumnsFromTableExpression(subquery_to_execute, planner_context.getQueryContext()); sets.addFromSubquery(set_key, std::move(subquery_to_execute), settings); } else { throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "Function '{}' is supported only if second argument is constant or table expression", function_node->getFunctionName()); } } static bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child_node) { auto child_node_type = child_node->getNodeType(); return !(child_node_type == QueryTreeNodeType::QUERY || child_node_type == QueryTreeNodeType::UNION); } private: PlannerContext & planner_context; }; } void collectSets(const QueryTreeNodePtr & node, PlannerContext & planner_context) { CollectSetsVisitor visitor(planner_context); visitor.visit(node); } }