@@ -38,25 +38,40 @@ class TKqpSinkPrecomputeTransformer : public TSyncTransformerBase {
38
38
return TStatus::Ok;
39
39
}
40
40
41
- const auto stagesUsedForPrecomputesAndSinks = FindStagesUsedForPrecomputeAndSinks (outputExpr);
42
- Y_UNUSED (stagesUsedForPrecomputesAndSinks);
43
-
44
41
TNodeOnNodeOwnedMap marked;
45
- for (const auto & [_, exprNode] : stagesUsedForPrecomputesAndSinks) {
46
- AFL_ENSURE (exprNode);
47
- TExprBase node (exprNode);
48
- const auto stage = node.Cast <TDqStage>();
49
- if (HasNonDeterministicFunction (stage)) {
50
- marked.emplace (node.Raw (), node.Ptr ());
42
+
43
+ {
44
+ const auto [precomputeStages, sinkStages] = GatherPrecomputeAndSinkStages (outputExpr, *KqpCtx);
45
+
46
+ for (const auto & [_, exprNode] : FindStagesUsedForBothStagesSets (precomputeStages, sinkStages)) {
47
+ AFL_ENSURE (exprNode);
48
+ TExprBase node (exprNode);
49
+ const auto stage = node.Cast <TDqStage>();
50
+ if (HasNonDeterministicFunction (stage) || !IsKqpPureInputs (stage.Inputs ())) {
51
+ marked.emplace (node.Raw (), node.Ptr ());
52
+ }
53
+ }
54
+
55
+ const auto resultStages = GatherResultStages (outputExpr, ctx);
56
+ if (!resultStages) {
57
+ return TStatus::Error;
58
+ }
59
+
60
+ for (const auto & [_, exprNode] : FindStagesUsedForBothStagesSets (*resultStages, sinkStages)) {
61
+ AFL_ENSURE (exprNode);
62
+ TExprBase node (exprNode);
63
+ const auto stage = node.Cast <TDqStage>();
64
+ if (!IsKqpPureInputs (stage.Inputs ())) {
65
+ marked.emplace (node.Raw (), node.Ptr ());
66
+ }
51
67
}
52
68
}
53
69
54
70
if (marked.empty ()) {
55
71
return TStatus::Ok;
56
72
}
57
73
58
- // Find all stages that depend on non-deterministic stages
59
- // that are used for sinks or precomputes.
74
+ // Find all stages that depend on marked stages
60
75
{
61
76
auto filter = [](const TExprNode::TPtr& exprNode) {
62
77
return !exprNode->IsLambda ();
@@ -108,20 +123,16 @@ class TKqpSinkPrecomputeTransformer : public TSyncTransformerBase {
108
123
|| (KqpCtx->Tables ->ExistingTable (KqpCtx->Cluster , sinkSettings.Cast ().Table ().Path ()).Metadata ->Kind == EKikimrTableKind::Olap);
109
124
if (!executedAsSingleEffect) {
110
125
AFL_ENSURE (stage.Inputs ().Size () == 1 );
126
+ AFL_ENSURE (stage.Inputs ().Item (0 ).Maybe <TDqCnUnionAll>());
127
+ AFL_ENSURE (stage.Settings ().Empty ());
111
128
112
- auto channel = Build<TDqCnUnionAll>(ctx, node.Pos ())
113
- .Output ()
114
- .Stage <TDqStage>() // no output
115
- .Inputs (stage.Inputs ())
116
- .Program (stage.Program ())
117
- .Settings (stage.Settings ())
118
- .Build ()
119
- .Index ().Build (" 0" )
120
- .Build ()
121
- .Done ();
129
+ AFL_ENSURE (stage.Program ().Args ().Size () == 1 );
130
+ AFL_ENSURE (stage.Program ().Body ().Maybe <TCoArgument>());
131
+ AFL_ENSURE (stage.Program ().Body ().Cast <TCoArgument>().Name () ==
132
+ stage.Program ().Args ().Arg (0 ).Cast <TCoArgument>().Name ());
122
133
123
134
auto inputRows = Build<TDqPhyPrecompute>(ctx, node.Pos ())
124
- .Connection (channel )
135
+ .Connection (stage. Inputs (). Item ( 0 ). Ptr () )
125
136
.Done ();
126
137
127
138
auto rowArg = Build<TCoArgument>(ctx, node.Pos ())
@@ -152,43 +163,43 @@ class TKqpSinkPrecomputeTransformer : public TSyncTransformerBase {
152
163
153
164
outputExpr = ctx.ReplaceNodes (std::move (outputExpr), replaces);
154
165
155
- return TStatus::Ok ;
166
+ return TStatus (TStatus::Repeat, true ) ;
156
167
}
157
168
158
169
void Rewind () final {
159
170
}
160
171
161
172
private:
162
- TNodeOnNodeOwnedMap FindStagesUsedForPrecomputeAndSinks (TExprNode::TPtr& expr) {
163
- const auto [precomputeStages, sinkStages] = GatherPrecomputesAndSinks (expr, *KqpCtx);
164
-
165
- TNodeSet stagesUsedForPrecomputes ;
166
- for (const auto & precomputeStage : precomputeStages ) {
167
- auto visit = [&stagesUsedForPrecomputes ](const TDqStage& stage) mutable -> bool {
168
- return stagesUsedForPrecomputes .emplace (stage.Raw ()).second ;
173
+ TNodeOnNodeOwnedMap FindStagesUsedForBothStagesSets (
174
+ const TNodeOnNodeOwnedMap& leftStages,
175
+ const TNodeOnNodeOwnedMap& rightStages) {
176
+ TNodeSet stagesUsedForLeft ;
177
+ for (const auto & leftStage : leftStages ) {
178
+ auto visit = [&stagesUsedForLeft ](const TDqStage& stage) mutable -> bool {
179
+ return stagesUsedForLeft .emplace (stage.Raw ()).second ;
169
180
};
170
181
auto postVisit = [](const TDqStage&) {};
171
- VisitStagesBackwards (precomputeStage .second , visit, postVisit);
182
+ VisitStagesBackwards (leftStage .second , visit, postVisit);
172
183
}
173
184
174
- TNodeOnNodeOwnedMap stagesUsedForPrecomputesAndSinks ;
175
- TNodeSet stagesUsedForSinks ;
176
- for (const auto & sinkStage : sinkStages ) {
177
- auto visit = [&stagesUsedForSinks , &stagesUsedForPrecomputes , &stagesUsedForPrecomputesAndSinks ](
185
+ TNodeOnNodeOwnedMap stagesUsedForLeftAndRight ;
186
+ TNodeSet stagesUsedForRight ;
187
+ for (const auto & rightStage : rightStages ) {
188
+ auto visit = [&stagesUsedForRight , &stagesUsedForLeft , &stagesUsedForLeftAndRight ](
178
189
const TDqStage& stage) mutable -> bool {
179
- if (stagesUsedForPrecomputes .contains (stage.Raw ())) {
180
- stagesUsedForPrecomputesAndSinks .emplace (stage.Raw (), stage.Ptr ());
190
+ if (stagesUsedForLeft .contains (stage.Raw ())) {
191
+ stagesUsedForLeftAndRight .emplace (stage.Raw (), stage.Ptr ());
181
192
}
182
- return stagesUsedForSinks .emplace (stage.Raw ()).second ;
193
+ return stagesUsedForRight .emplace (stage.Raw ()).second ;
183
194
};
184
195
auto postVisit = [](const TDqStage&) {};
185
- VisitStagesBackwards (sinkStage .second , visit, postVisit);
196
+ VisitStagesBackwards (rightStage .second , visit, postVisit);
186
197
}
187
198
188
- return stagesUsedForPrecomputesAndSinks ;
199
+ return stagesUsedForLeftAndRight ;
189
200
}
190
201
191
- std::pair<TNodeOnNodeOwnedMap, TNodeOnNodeOwnedMap> GatherPrecomputesAndSinks (const TExprNode::TPtr& query, const TKqpOptimizeContext& kqpCtx) {
202
+ std::pair<TNodeOnNodeOwnedMap, TNodeOnNodeOwnedMap> GatherPrecomputeAndSinkStages (const TExprNode::TPtr& query, const TKqpOptimizeContext& kqpCtx) {
192
203
TNodeOnNodeOwnedMap precomputeStages;
193
204
TNodeOnNodeOwnedMap sinkStages;
194
205
@@ -253,6 +264,25 @@ class TKqpSinkPrecomputeTransformer : public TSyncTransformerBase {
253
264
return {std::move (precomputeStages), std::move (sinkStages)};
254
265
}
255
266
267
+ std::optional<TNodeOnNodeOwnedMap> GatherResultStages (
268
+ const TExprNode::TPtr& inputExpr,
269
+ TExprContext& ctx) {
270
+ TNodeOnNodeOwnedMap resultStages;
271
+ TKqlQuery query (inputExpr);
272
+ for (const auto & result : query.Results ()) {
273
+ if (auto maybeUnionAll = result.Value ().Maybe <TDqCnUnionAll>()) {
274
+ auto resultConnection = maybeUnionAll.Cast ();
275
+ auto resultStage = resultConnection.Output ().Stage ().Cast <TDqStage>();
276
+ resultStages.emplace (resultStage.Raw (), resultStage.Ptr ());
277
+ } else if (!result.Value ().Maybe <TDqCnValue>()) {
278
+ ctx.AddError (TIssue (ctx.GetPosition (result.Pos ()), TStringBuilder ()
279
+ << " Unexpected node in results: " << KqpExprToPrettyString (result.Value (), ctx)));
280
+ return std::nullopt ;
281
+ }
282
+ }
283
+ return resultStages;
284
+ }
285
+
256
286
bool HasNonDeterministicFunction (const TDqStage& stage) {
257
287
bool hasNonDeterministicFunction = false ;
258
288
VisitExpr (stage.Program ().Ptr (), [&hasNonDeterministicFunction](const TExprNode::TPtr& exprNode) mutable {
0 commit comments