@@ -451,6 +451,10 @@ std::shared_ptr<IOperator> TInlineSimpleInExistsSubplanRule::SimpleTestAndApply(
451451 return input;
452452 }
453453
454+ if (lambdaBody->IsCallable (" ToPg" )) {
455+ lambdaBody = lambdaBody->ChildPtr (0 );
456+ }
457+
454458 // Decompose the conjunction into individual conjuncts
455459 TVector<TExprNode::TPtr> conjuncts;
456460 if (TCoAnd::Match (lambdaBody.Get ())) {
@@ -470,14 +474,14 @@ std::shared_ptr<IOperator> TInlineSimpleInExistsSubplanRule::SimpleTestAndApply(
470474 for (conjunctIdx=0 ; conjunctIdx<conjuncts.size (); conjunctIdx++) {
471475 auto maybeSubplan = conjuncts[conjunctIdx];
472476
473- if (maybeSubplan->IsCallable (" ToPg" )) {
477+ while (maybeSubplan->IsCallable (" ToPg" ) || maybeSubplan-> IsCallable ( " FromPg " )) {
474478 maybeSubplan = maybeSubplan->ChildPtr (0 );
475479 }
476480 if (TCoNot::Match (maybeSubplan.Get ())){
477481 maybeSubplan = maybeSubplan->ChildPtr (0 );
478482 negated = true ;
479483 }
480- if ( maybeSubplan->IsCallable (" FromPg" )) {
484+ while (maybeSubplan-> IsCallable ( " ToPg " ) || maybeSubplan->IsCallable (" FromPg" )) {
481485 maybeSubplan = maybeSubplan->ChildPtr (0 );
482486 }
483487 if (TCoMember::Match (maybeSubplan.Get ())) {
@@ -497,11 +501,21 @@ std::shared_ptr<IOperator> TInlineSimpleInExistsSubplanRule::SimpleTestAndApply(
497501 return input;
498502 }
499503
500- // We build a semi-join or a left-only join
501- auto leftJoinInput = filter->GetInput ();
502- TString joinKind = negated ? " LeftOnly" : " LeftSemi" ;
503- TVector<std::pair<TInfoUnit, TInfoUnit>> joinKeys;
504+ std::shared_ptr<TOpJoin> join;
505+
506+ // We build a semi-join or a left-only join when processing IN subplan
504507 if (subplan.Type == ESubplanType::IN) {
508+
509+ auto leftJoinInput = filter->GetInput ();
510+ TString joinKind;
511+ if (subplan.Type == ESubplanType::IN) {
512+ joinKind = negated ? " LeftOnly" : " LeftSemi" ;
513+ } else {
514+ joinKind = " Cross" ;
515+ }
516+
517+ TVector<std::pair<TInfoUnit, TInfoUnit>> joinKeys;
518+
505519 auto planIUs = subplan.Plan ->GetOutputIUs ();
506520 Y_ENSURE (subplan.Tuple .size () == planIUs.size ());
507521
@@ -511,17 +525,21 @@ std::shared_ptr<IOperator> TInlineSimpleInExistsSubplanRule::SimpleTestAndApply(
511525
512526 auto arg = Build<TCoArgument>(ctx.ExprCtx , filter->Pos ).Name (" lambda_arg" ).Done ();
513527
528+ // clang-format off
514529 auto toPgMember = Build<TCoMember>(ctx.ExprCtx , filter->Pos )
515530 .Struct (arg)
516531 .Name <TCoAtom>().Value (subplan.Tuple [i].GetFullName ()).Build ()
517532 .Done ().Ptr ();
533+ // clang-format on
518534
519535 toPgMember = ctx.ExprCtx .NewCallable (filter->Pos , " ToPg" , {toPgMember});
520536
537+ // clang-format off
521538 auto toPgLambda = Build<TCoLambda>(ctx.ExprCtx , filter->Pos )
522539 .Args ({arg})
523540 .Body (toPgMember)
524541 .Done ().Ptr ();
542+ // clang-format on
525543
526544 auto toPgVar = TInfoUnit (" _rbo_arg_" + std::to_string (props.InternalVarIdx ++), true );
527545 std::variant<TInfoUnit, TExprNode::TPtr> toPgElement = toPgLambda;
@@ -537,11 +555,77 @@ std::shared_ptr<IOperator> TInlineSimpleInExistsSubplanRule::SimpleTestAndApply(
537555 joinKeys.push_back (std::make_pair (subplan.Tuple [i], planIUs[i]));
538556 }
539557 }
558+
559+ join = std::make_shared<TOpJoin>(leftJoinInput, subplan.Plan , input->Pos , joinKind, joinKeys);
560+ conjuncts.erase (conjuncts.begin () + conjunctIdx);
561+ }
562+
563+ // EXISTS and NOT EXISTS
564+ else {
565+
566+ auto countResult = TInfoUnit (" _rbo_arg_" + std::to_string (props.InternalVarIdx ++), true );
567+
568+ TVector<std::pair<TInfoUnit, std::variant<TInfoUnit, TExprNode::TPtr>>> countMapElements;
569+
570+ auto zero = ctx.ExprCtx .NewCallable (filter->Pos , " Uint64" , {ctx.ExprCtx .NewAtom (filter->Pos , " 0" )});
571+
572+ // clang-format off
573+ auto zeroLambda = Build<TCoLambda>(ctx.ExprCtx , filter->Pos )
574+ .Args ({" arg" })
575+ .Body (zero)
576+ .Done ().Ptr ();
577+ // clang-format on
578+
579+ countMapElements.push_back (std::make_pair (countResult, zeroLambda));
580+ auto countMap = std::make_shared<TOpMap>(subplan.Plan , filter->Pos , countMapElements, true );
581+
582+
583+ TOpAggregationTraits aggFunction (countResult, " count" );
584+ TVector<TOpAggregationTraits> aggs = {aggFunction};
585+ TVector<TInfoUnit> keyColumns;
586+
587+ auto agg = std::make_shared<TOpAggregate>(countMap, aggs, keyColumns, EAggregationPhase::Final, false , filter->Pos );
588+
589+ TVector<std::pair<TInfoUnit, std::variant<TInfoUnit, TExprNode::TPtr>>> mapElements;
590+ auto arg = Build<TCoArgument>(ctx.ExprCtx , filter->Pos ).Name (" lambda_arg" ).Done ();
591+
592+ // FIXME: Apparently count(*) on empty result return null
593+ TString compareCallable = negated ? " ==" : " !=" ;
594+
595+ // clang-format off
596+ auto member = Build<TCoMember>(ctx.ExprCtx , filter->Pos )
597+ .Struct (arg)
598+ .Name ().Value (countResult.GetFullName ()).Build ()
599+ .Done ().Ptr ();
600+ // clang-format on
601+
602+ auto body = ctx.ExprCtx .NewCallable (filter->Pos , compareCallable, {member, zero});
603+
604+ // clang-format off
605+ auto lambda = Build<TCoLambda>(ctx.ExprCtx , filter->Pos )
606+ .Args ({arg})
607+ .Body (body)
608+ .Done ().Ptr ();
609+ // clang-format on
610+
611+ auto compareResult = TInfoUnit (" _rbo_arg_" + std::to_string (props.InternalVarIdx ++), true );
612+ mapElements.push_back (std::make_pair (compareResult, lambda));
613+ auto map = std::make_shared<TOpMap>(agg, filter->Pos , mapElements, true );
614+
615+ TVector<std::pair<TInfoUnit, TInfoUnit>> joinKeys;
616+ join = std::make_shared<TOpJoin>(filter->GetInput (), map, filter->Pos , " Cross" , joinKeys);
617+
618+ // clang-format off
619+ auto resultMember = Build<TCoMember>(ctx.ExprCtx , filter->Pos )
620+ .Struct (arg)
621+ .Name ().Value (compareResult.GetFullName ()).Build ()
622+ .Done ().Ptr ();
623+ // clang-format on
624+
625+ conjuncts[conjunctIdx] = resultMember;
540626 }
541627
542- auto join = std::make_shared<TOpJoin>(leftJoinInput, subplan.Plan , input->Pos , joinKind, joinKeys);
543628 props.Subplans .Remove (iu);
544- conjuncts.erase (conjuncts.begin () + conjunctIdx);
545629
546630 // If there was a single conjunct, we can get rid of the filter completely
547631 if (conjuncts.empty ()) {
@@ -556,6 +640,9 @@ std::shared_ptr<IOperator> TInlineSimpleInExistsSubplanRule::SimpleTestAndApply(
556640 newLambdaBody = conjuncts[0 ];
557641 } else {
558642 newLambdaBody = Build<TCoAnd>(ctx.ExprCtx , input->Pos ).Add (conjuncts).Done ().Ptr ();
643+ if (props.PgSyntax ) {
644+ newLambdaBody = ctx.ExprCtx .NewCallable (filter->Pos , " ToPg" , {newLambdaBody});
645+ }
559646 }
560647 newLambdaBody = ReplaceArg (newLambdaBody, arg, ctx.ExprCtx );
561648
0 commit comments