1- #include < Processors/QueryPlan/Optimizations/Optimizations.h>
2- #include < Processors/QueryPlan/Optimizations/projectionsCommon.h>
1+ #include < Core/Settings.h>
32#include < Processors/QueryPlan/ExpressionStep.h>
43#include < Processors/QueryPlan/FilterStep.h>
4+ #include < Processors/QueryPlan/Optimizations/Optimizations.h>
5+ #include < Processors/QueryPlan/Optimizations/projectionsCommon.h>
56#include < Processors/QueryPlan/ReadFromMergeTree.h>
6- #include < Processors/QueryPlan/UnionStep.h>
77#include < Processors/QueryPlan/ReadFromPreparedSource.h>
8+ #include < Processors/QueryPlan/UnionStep.h>
89#include < Processors/Sources/NullSource.h>
9- #include < Common/logger_useful.h>
10- #include < Core/Settings.h>
10+ #include < Storages/MergeTree/MergeTreeDataSelectExecutor.h>
1111#include < Storages/ProjectionsDescription.h>
1212#include < Storages/SelectQueryInfo.h>
13- #include < Storages/MergeTree/MergeTreeDataSelectExecutor.h>
14-
15- #include < algorithm>
1613
1714namespace DB
1815{
@@ -72,18 +69,6 @@ static std::optional<ActionsDAG> makeMaterializingDAG(const Block & proj_header,
7269 return dag;
7370}
7471
75- static bool hasAllRequiredColumns (const ProjectionDescription * projection, const Names & required_columns)
76- {
77- for (const auto & col : required_columns)
78- {
79- if (!projection->sample_block .has (col))
80- return false ;
81- }
82-
83- return true ;
84- }
85-
86-
8772std::optional<String> optimizeUseNormalProjections (Stack & stack, QueryPlan::Nodes & nodes)
8873{
8974 const auto & frame = stack.back ();
@@ -100,8 +85,7 @@ std::optional<String> optimizeUseNormalProjections(Stack & stack, QueryPlan::Nod
10085 {
10186 iter = std::next (iter);
10287
103- if (!typeid_cast<FilterStep *>(iter->node ->step .get ()) &&
104- !typeid_cast<ExpressionStep *>(iter->node ->step .get ()))
88+ if (!typeid_cast<FilterStep *>(iter->node ->step .get ()) && !typeid_cast<ExpressionStep *>(iter->node ->step .get ()))
10589 break ;
10690 }
10791
@@ -124,7 +108,8 @@ std::optional<String> optimizeUseNormalProjections(Stack & stack, QueryPlan::Nod
124108 auto it = std::find_if (
125109 normal_projections.begin (),
126110 normal_projections.end (),
127- [&](const auto * projection) { return projection->name == context->getSettingsRef ()[Setting::preferred_optimize_projection_name].value ; });
111+ [&](const auto * projection)
112+ { return projection->name == context->getSettingsRef ()[Setting::preferred_optimize_projection_name].value ; });
128113
129114 if (it != normal_projections.end ())
130115 {
@@ -133,20 +118,52 @@ std::optional<String> optimizeUseNormalProjections(Stack & stack, QueryPlan::Nod
133118 normal_projections.push_back (preferred_projection);
134119 }
135120
121+ Names required_columns = reading->getAllColumnNames ();
122+
123+ // / If `with_parent_part_offset` is true and the required columns include `_part_offset`,
124+ // / we need to remap it to `_parent_part_offset`. This ensures that the projection's
125+ // / ActionsDAG reads from the correct column and generates `_part_offset` in the output.
126+ bool with_parent_part_offset = std::any_of (
127+ normal_projections.begin (), normal_projections.end (), [](const auto & projection) { return projection->with_parent_part_offset ; });
128+ bool need_parent_part_offset = false ;
129+ if (with_parent_part_offset)
130+ {
131+ for (auto & name : required_columns)
132+ {
133+ if (name == " _part_offset" )
134+ {
135+ name = " _parent_part_offset" ;
136+ need_parent_part_offset = true ;
137+ }
138+ }
139+ }
140+
136141 QueryDAG query;
137142 {
138143 auto & child = iter->node ->children [iter->next_child - 1 ];
139144 if (!query.build (*child))
140145 return {};
141146
147+ if (need_parent_part_offset)
148+ {
149+ ActionsDAG rename_dag;
150+ const auto * node = &rename_dag.addInput (" _parent_part_offset" , std::make_shared<DataTypeUInt64>());
151+ node = &rename_dag.addAlias (*node, " _part_offset" );
152+ rename_dag.getOutputs () = {node};
153+
154+ if (query.dag )
155+ query.dag = ActionsDAG::merge (std::move (rename_dag), *std::move (query.dag ));
156+ else
157+ query.dag = std::move (rename_dag);
158+ }
159+
142160 if (query.dag )
143161 query.dag ->removeUnusedActions ();
144162 }
145163
146164 std::list<NormalProjectionCandidate> candidates;
147165 NormalProjectionCandidate * best_candidate = nullptr ;
148166
149- const Names & required_columns = reading->getAllColumnNames ();
150167 const auto & query_info = reading->getQueryInfo ();
151168 MergeTreeDataSelectExecutor reader (reading->getMergeTreeData ());
152169
@@ -168,9 +185,21 @@ std::optional<String> optimizeUseNormalProjections(Stack & stack, QueryPlan::Nod
168185
169186 auto logger = getLogger (" optimizeUseNormalProjections" );
170187
188+ auto projection_virtuals = reading->getMergeTreeData ().getProjectionVirtualsPtr ();
189+ auto has_all_required_columns = [&](const ProjectionDescription * projection)
190+ {
191+ for (const auto & col : required_columns)
192+ {
193+ if (!projection->sample_block .has (col) && !projection_virtuals->has (col))
194+ return false ;
195+ }
196+
197+ return true ;
198+ };
199+
171200 for (const auto * projection : normal_projections)
172201 {
173- if (!hasAllRequiredColumns (projection, required_columns ))
202+ if (!has_all_required_columns (projection))
174203 continue ;
175204
176205 auto & candidate = candidates.emplace_back ();
@@ -237,7 +266,7 @@ std::optional<String> optimizeUseNormalProjections(Stack & stack, QueryPlan::Nod
237266 query_info_copy.prewhere_info = nullptr ;
238267
239268 auto projection_reading = reader.readFromParts (
240- /* parts=*/ {},
269+ /* parts=*/ {},
241270 reading->getMutationsSnapshot ()->cloneEmpty (),
242271 required_columns,
243272 proj_snapshot,
@@ -280,15 +309,11 @@ std::optional<String> optimizeUseNormalProjections(Stack & stack, QueryPlan::Nod
280309 if (query.filter_node )
281310 {
282311 expr_or_filter_node.step = std::make_unique<FilterStep>(
283- projection_reading_node.step ->getOutputHeader (),
284- std::move (*query.dag ),
285- query.filter_node ->result_name ,
286- true );
312+ projection_reading_node.step ->getOutputHeader (), std::move (*query.dag ), query.filter_node ->result_name , true );
287313 }
288314 else
289- expr_or_filter_node.step = std::make_unique<ExpressionStep>(
290- projection_reading_node.step ->getOutputHeader (),
291- std::move (*query.dag ));
315+ expr_or_filter_node.step
316+ = std::make_unique<ExpressionStep>(projection_reading_node.step ->getOutputHeader (), std::move (*query.dag ));
292317
293318 expr_or_filter_node.children .push_back (&projection_reading_node);
294319 next_node = &expr_or_filter_node;
0 commit comments