diff --git a/src/Analyzer/QueryTreeBuilder.cpp b/src/Analyzer/QueryTreeBuilder.cpp index 05b643aa6af..57b1ae1c994 100644 --- a/src/Analyzer/QueryTreeBuilder.cpp +++ b/src/Analyzer/QueryTreeBuilder.cpp @@ -233,6 +233,17 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_q auto select_settings = select_query_typed.settings(); SettingsChanges settings_changes; + if (is_subquery) + { + if (const Settings & settings_ref = updated_context->getSettingsRef(); settings_ref.limit || settings_ref.offset) + { + Settings settings = updated_context->getSettings(); + settings.limit = 0; + settings.offset = 0; + updated_context->setSettings(settings); + } + } + if (select_settings) { auto & set_query = select_settings->as(); diff --git a/src/Planner/Planner.cpp b/src/Planner/Planner.cpp index f0fe44e368f..7c2a3ffed78 100644 --- a/src/Planner/Planner.cpp +++ b/src/Planner/Planner.cpp @@ -216,12 +216,17 @@ public: limit_length = query_node.getLimit()->as().getValue().safeGet(); } + if (settings.limit) + limit_length = limit_length ? std::min(limit_length, settings.limit.value) : settings.limit; + if (query_node.hasOffset()) { /// Constness of offset is validated during query analysis stage limit_offset = query_node.getOffset()->as().getValue().safeGet(); } + limit_offset += settings.offset; + /// Partial sort can be done if there is LIMIT, but no DISTINCT, LIMIT WITH TIES, LIMIT BY, ARRAY JOIN if (limit_length != 0 && !query_node.isDistinct() && @@ -720,7 +725,7 @@ bool addPreliminaryLimitOptimizationStepIfNeeded(QueryPlan & query_plan, bool apply_limit = query_processing_info.getToStage() != QueryProcessingStage::WithMergeableStateAfterAggregation; bool apply_prelimit = apply_limit && - query_node.hasLimit() && + query_analysis_result.limit_length && !query_node.isLimitWithTies() && !query_node.isGroupByWithTotals() && !query_analysis_result.query_has_with_totals_in_any_subquery_in_join_tree && @@ -767,7 +772,7 @@ void addPreliminarySortOrDistinctOrLimitStepsIfNeeded(QueryPlan & query_plan, * Otherwise we can take several equal values from different streams * according to limit and skip some distinct values. */ - if (query_node.hasLimit() && query_node.isDistinct()) + if (query_analysis_result.limit_length && query_node.isDistinct()) { addDistinctStep(query_plan, query_analysis_result, @@ -785,7 +790,7 @@ void addPreliminarySortOrDistinctOrLimitStepsIfNeeded(QueryPlan & query_plan, addLimitByStep(query_plan, limit_by_analysis_result, query_node); } - if (query_node.hasLimit()) + if (query_analysis_result.limit_length) addPreliminaryLimitStep(query_plan, query_analysis_result, planner_context, true /*do_not_skip_offset*/); } @@ -1420,7 +1425,7 @@ void Planner::buildPlanForQueryNode() bool apply_offset = query_processing_info.getToStage() != QueryProcessingStage::WithMergeableStateAfterAggregationAndLimit; - if (query_node.hasLimit() && query_node.isLimitWithTies() && apply_offset) + if (query_analysis_result.limit_length && query_node.isLimitWithTies() && apply_offset) addLimitStep(query_plan, query_analysis_result, planner_context, query_node); addExtremesStepIfNeeded(query_plan, planner_context); @@ -1434,9 +1439,9 @@ void Planner::buildPlanForQueryNode() * This is the case for various optimizations for distributed queries, * and when LIMIT cannot be applied it will be applied on the initiator anyway. */ - if (query_node.hasLimit() && apply_limit && !limit_applied && apply_offset) + if (query_analysis_result.limit_length && apply_limit && !limit_applied && apply_offset) addLimitStep(query_plan, query_analysis_result, planner_context, query_node); - else if (!limit_applied && apply_offset && query_node.hasOffset()) + else if (!limit_applied && apply_offset && query_analysis_result.limit_length) addOffsetStep(query_plan, query_analysis_result); /// Project names is not done on shards, because initiator will not find columns in blocks diff --git a/src/Storages/StorageView.cpp b/src/Storages/StorageView.cpp index 1a7050b4dff..d3a2ec470cf 100644 --- a/src/Storages/StorageView.cpp +++ b/src/Storages/StorageView.cpp @@ -95,6 +95,8 @@ ContextPtr getViewContext(ContextPtr context) view_settings.max_result_rows = 0; view_settings.max_result_bytes = 0; view_settings.extremes = false; + view_settings.limit = 0; + view_settings.offset = 0; view_context->setSettings(view_settings); return view_context; } diff --git a/tests/queries/0_stateless/02667_analyzer_limit_settings.reference b/tests/queries/0_stateless/02667_analyzer_limit_settings.reference new file mode 100644 index 00000000000..9e38ed9a59b --- /dev/null +++ b/tests/queries/0_stateless/02667_analyzer_limit_settings.reference @@ -0,0 +1,54 @@ +-- { echoOn } +SET limit = 0; +SELECT * FROM numbers(10); +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +SELECT * FROM numbers(10) SETTINGS limit=5, offset=2; +2 +3 +4 +5 +6 +SELECT count(*) FROM (SELECT * FROM numbers(10)); +10 +SELECT count(*) FROM (SELECT * FROM numbers(10) SETTINGS limit=5); +5 +SELECT count(*) FROM (SELECT * FROM numbers(10)) SETTINGS limit=5; +10 +SELECT count(*) FROM view(SELECT * FROM numbers(10)); +10 +SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5); +5 +SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5; +10 +SET limit = 3; +SELECT * FROM numbers(10); +0 +1 +2 +SELECT * FROM numbers(10) SETTINGS limit=5, offset=2; +2 +3 +4 +5 +6 +SELECT count(*) FROM (SELECT * FROM numbers(10)); +10 +SELECT count(*) FROM (SELECT * FROM numbers(10) SETTINGS limit=5); +5 +SELECT count(*) FROM (SELECT * FROM numbers(10)) SETTINGS limit=5; +10 +SELECT count(*) FROM view(SELECT * FROM numbers(10)); +10 +SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5); +5 +SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5; +10 diff --git a/tests/queries/0_stateless/02667_analyzer_limit_settings.sql b/tests/queries/0_stateless/02667_analyzer_limit_settings.sql new file mode 100644 index 00000000000..35dd65ab33e --- /dev/null +++ b/tests/queries/0_stateless/02667_analyzer_limit_settings.sql @@ -0,0 +1,24 @@ +SET allow_experimental_analyzer = 1; + +-- { echoOn } +SET limit = 0; + +SELECT * FROM numbers(10); +SELECT * FROM numbers(10) SETTINGS limit=5, offset=2; +SELECT count(*) FROM (SELECT * FROM numbers(10)); +SELECT count(*) FROM (SELECT * FROM numbers(10) SETTINGS limit=5); +SELECT count(*) FROM (SELECT * FROM numbers(10)) SETTINGS limit=5; +SELECT count(*) FROM view(SELECT * FROM numbers(10)); +SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5); +SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5; + +SET limit = 3; +SELECT * FROM numbers(10); +SELECT * FROM numbers(10) SETTINGS limit=5, offset=2; +SELECT count(*) FROM (SELECT * FROM numbers(10)); +SELECT count(*) FROM (SELECT * FROM numbers(10) SETTINGS limit=5); +SELECT count(*) FROM (SELECT * FROM numbers(10)) SETTINGS limit=5; +SELECT count(*) FROM view(SELECT * FROM numbers(10)); +SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5); +SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5; +-- { echoOff }