@@ -51,7 +51,8 @@ TExprNode::TPtr ApplyExtractMembersToExtend(const TExprNode::TPtr& node, const T
5151 return ctx.NewCallable (node->Pos (), node->Content (), std::move (inputs));
5252}
5353
54- TExprNode::TPtr ApplyExtractMembersToSkipNullMembers (const TExprNode::TPtr& node, const TExprNode::TPtr& members, TExprContext& ctx, TStringBuf logSuffix) {
54+ namespace {
55+ TExprNode::TPtr ApplyExtractMembersToSkipNullMembersLegacy (const TExprNode::TPtr& node, const TExprNode::TPtr& members, TExprContext& ctx, TStringBuf logSuffix) {
5556 TCoSkipNullMembers skipNullMembers (node);
5657 const auto & filtered = skipNullMembers.Members ();
5758 if (!filtered) {
@@ -85,9 +86,7 @@ TExprNode::TPtr ApplyExtractMembersToSkipNullMembers(const TExprNode::TPtr& node
8586 .Done ().Ptr ();
8687}
8788
88- TExprNode::TPtr ApplyExtractMembersToFilterNullMembers (const TExprNode::TPtr& node, const TExprNode::TPtr& members, TExprContext& ctx,
89- TOptimizeContext& optCtx, TStringBuf logSuffix)
90- {
89+ TExprNode::TPtr ApplyExtractMembersToFilterNullMembersLegacy (const TExprNode::TPtr& node, const TExprNode::TPtr& members, TExprContext& ctx, TStringBuf logSuffix) {
9190 TCoFilterNullMembers filterNullMembers (node);
9291 if (!filterNullMembers.Input ().Maybe <TCoAssumeAllMembersNullableAtOnce>()) {
9392 return {};
@@ -156,31 +155,100 @@ TExprNode::TPtr ApplyExtractMembersToFilterNullMembers(const TExprNode::TPtr& no
156155
157156 YQL_CLOG (DEBUG, Core) << " Move ExtractMembers over " << node->Content () << logSuffix;
158157
159- static const char optName[] = " MemberNthOverFlatMap" ;
160- YQL_ENSURE (optCtx.Types );
161- const bool keepAssume = !IsOptimizerDisabled<optName>(*optCtx.Types );
162-
163- auto innerExtract = Build<TCoExtractMembers>(ctx, filterNullMembers.Pos ())
164- .Input (input)
165- .Members (extendedMembers ? extendedMembers : members)
166- .Done ().Ptr ();
167-
168158 if (extendedMembers) {
169159 return Build<TCoExtractMembers>(ctx, filterNullMembers.Pos ())
170160 .Input <TCoFilterNullMembers>()
171- .Input (ctx.WrapByCallableIf (keepAssume, TCoAssumeAllMembersNullableAtOnce::CallableName (), std::move (innerExtract)))
161+ .Input <TCoExtractMembers>()
162+ .Input (input)
163+ .Members (extendedMembers)
164+ .Build ()
172165 .Members (filteredMembers)
173166 .Build ()
174167 .Members (members)
175168 .Done ().Ptr ();
176169 }
177170
178171 return Build<TCoFilterNullMembers>(ctx, filterNullMembers.Pos ())
179- .Input (ctx.WrapByCallableIf (keepAssume, TCoAssumeAllMembersNullableAtOnce::CallableName (), std::move (innerExtract)))
172+ .Input <TCoExtractMembers>()
173+ .Input (input)
174+ .Members (members)
175+ .Build ()
180176 .Members (filteredMembers)
181177 .Done ().Ptr ();
182178}
183179
180+ } // namespace
181+
182+ TExprNode::TPtr ApplyExtractMembersToFilterSkipNullMembers (const TExprNode::TPtr& node, const TExprNode::TPtr& members, TExprContext& ctx,
183+ TOptimizeContext& optCtx, TStringBuf logSuffix)
184+ {
185+ static const char optName[] = " MemberNthOverFlatMap" ;
186+ YQL_ENSURE (optCtx.Types );
187+ if (IsOptimizerDisabled<optName>(*optCtx.Types )) {
188+ return node->IsCallable (" FilterNullMembers" ) ?
189+ ApplyExtractMembersToFilterNullMembersLegacy (node, members, ctx, logSuffix) :
190+ ApplyExtractMembersToSkipNullMembersLegacy (node, members, ctx, logSuffix);
191+ }
192+
193+ TCoFilterNullMembersBase self (node);
194+ TSet<TStringBuf> filteredMembers = GetFilteredMembers (self);
195+ YQL_ENSURE (!filteredMembers.empty ());
196+ TSet<TStringBuf> extractedMembers;
197+ for (const auto & atom : members->ChildrenList ()) {
198+ extractedMembers.insert (atom->Content ());
199+ }
200+
201+ TSet<TStringBuf> filteredAndExtracted;
202+ std::set_intersection (filteredMembers.begin (), filteredMembers.end (),
203+ extractedMembers.begin (), extractedMembers.end (),
204+ std::inserter (filteredAndExtracted, filteredAndExtracted.end ()));
205+
206+ auto filterInput = self.Input ();
207+ bool hasAssume = false ;
208+ if (auto maybeAssume = filterInput.Maybe <TCoAssumeAllMembersNullableAtOnce>()) {
209+ filterInput = maybeAssume.Cast ().Input ();
210+ hasAssume = true ;
211+ }
212+
213+ if (filteredAndExtracted == filteredMembers || (hasAssume && !filteredAndExtracted.empty ())) {
214+ // simple pushdown
215+ YQL_CLOG (DEBUG, Core) << " Move ExtractMembers over " << self.CallableName () << logSuffix;
216+ auto newInput = ctx.NewCallable (self.Pos (), " ExtractMembers" , { filterInput.Ptr (), members });
217+ return ctx.NewCallable (self.Pos (), self.CallableName (), {
218+ ctx.WrapByCallableIf (hasAssume, TCoAssumeAllMembersNullableAtOnce::CallableName (), std::move (newInput)),
219+ MakeAtomList (self.Pos (), filteredAndExtracted, ctx)
220+ });
221+ }
222+
223+ TSet<TStringBuf> innerExtracted = extractedMembers;
224+ if (hasAssume) {
225+ YQL_ENSURE (filteredAndExtracted.empty ());
226+ // just leave single member
227+ filteredMembers = { *filteredMembers.begin () };
228+ }
229+ innerExtracted.insert (filteredMembers.begin (), filteredMembers.end ());
230+
231+ const auto inputType = GetSequenceItemType (filterInput, false );
232+ YQL_ENSURE (inputType);
233+ const size_t inputWidth = inputType->Cast <TStructExprType>()->GetSize ();
234+ YQL_ENSURE (inputWidth >= innerExtracted.size ());
235+
236+ if (inputWidth == innerExtracted.size ()) {
237+ return {};
238+ }
239+
240+ YQL_CLOG (DEBUG, Core) << " Push ExtractMembers over " << self.CallableName () << logSuffix;
241+ auto newInput = ctx.NewCallable (self.Pos (), " ExtractMembers" , { filterInput.Ptr (), MakeAtomList (self.Pos (), innerExtracted, ctx) });
242+ auto newFilter = ctx.Builder (self.Pos ())
243+ .Callable (self.CallableName ())
244+ .Add (0 , ctx.WrapByCallableIf (hasAssume, TCoAssumeAllMembersNullableAtOnce::CallableName (), std::move (newInput)))
245+ .Add (1 , MakeAtomList (self.Pos (), filteredMembers, ctx))
246+ .Seal ()
247+ .Build ();
248+ return ctx.NewCallable (self.Pos (), " ExtractMembers" , { newFilter, members });
249+ }
250+
251+
184252TExprNode::TPtr ApplyExtractMembersToSortOrPruneKeys (const TExprNode::TPtr& node, const TExprNode::TPtr& members, const TParentsMap& parentsMap, TExprContext& ctx, TStringBuf logSuffix) {
185253 auto nodeIsPruneKeys = node->IsCallable (" PruneKeys" ) || node->IsCallable (" PruneAdjacentKeys" );
186254 auto nodeIsSort = !nodeIsPruneKeys;
0 commit comments