@@ -5285,6 +5285,142 @@ IGraphTransformer::TStatus PgLikeWrapper(const TExprNode::TPtr& input, TExprNode
52855285 return IGraphTransformer::TStatus::Ok;
52865286}
52875287
5288+ TExprNodePtr BuildPgIn (TExprNodeList&& args, ui32 targetTypeId, bool castRequired, TContext& ctx) {
5289+ auto lhs = args[0 ];
5290+ if (castRequired) {
5291+ const auto lhsType = lhs->GetTypeAnn ()->Cast <TPgExprType>();
5292+ if (lhsType->GetId () != targetTypeId) {
5293+ lhs = WrapWithPgCast (std::move (lhs), targetTypeId, ctx.Expr );
5294+ }
5295+ }
5296+ std::swap (args[0 ], args.back ());
5297+ args.pop_back ();
5298+
5299+ if (castRequired) {
5300+ for (size_t i = 0 ; i < args.size (); ++i) {
5301+ const auto argType = args[i]->GetTypeAnn ()->Cast <TPgExprType>();
5302+ if (argType->GetId () != targetTypeId) {
5303+ args[i] = WrapWithPgCast (std::move (args[i]), targetTypeId, ctx.Expr );
5304+ }
5305+ }
5306+ }
5307+
5308+ const auto rhs = ctx.Expr .Builder (args[1 ]->Pos ())
5309+ .Callable (" AsList" )
5310+ .Add (std::move (args))
5311+ .Seal ()
5312+ .Build ();
5313+
5314+ return ctx.Expr .Builder (lhs->Pos ())
5315+ .Callable (" PgIn" )
5316+ .Add (0 , lhs)
5317+ .Add (1 , rhs)
5318+ .Seal ()
5319+ .Build ();
5320+ }
5321+
5322+ IGraphTransformer::TStatus PgMixedInWrapper (const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx) {
5323+ if (!EnsureMinArgsCount (*input, 2 , ctx.Expr )) {
5324+ ctx.Expr .AddError (TIssue (ctx.Expr .GetPosition (input->Pos ()), " IN expects at least one element" ));
5325+ return IGraphTransformer::TStatus::Error;
5326+ }
5327+
5328+ TVector<ui32> pgTypes (input->ChildrenSize ());
5329+ {
5330+ TExprNodeList convertedChildren;
5331+ convertedChildren.reserve (input->ChildrenSize ());
5332+ bool convertionRequired = false ;
5333+ bool hasConvertions = false ;
5334+ for (size_t i = 0 ; i < input->ChildrenSize (); ++i) {
5335+ const auto child = input->Child (i);
5336+ if (!ExtractPgType (child->GetTypeAnn (), pgTypes[i], convertionRequired, child->Pos (), ctx.Expr )) {
5337+ return IGraphTransformer::TStatus::Error;
5338+ }
5339+ if (convertionRequired) {
5340+ hasConvertions = true ;
5341+
5342+ auto convertedChild = ctx.Expr .Builder (child->Pos ())
5343+ .Callable (" ToPg" )
5344+ .Add (0 , child)
5345+ .Seal ()
5346+ .Build ();
5347+ convertedChildren.push_back (std::move (convertedChild));
5348+ } else {
5349+ convertedChildren.push_back (std::move (child));
5350+ }
5351+ }
5352+ if (hasConvertions) {
5353+ output = ctx.Expr .Builder (input->Pos ())
5354+ .Callable (" PgMixedIn" )
5355+ .Add (std::move (convertedChildren))
5356+ .Seal ()
5357+ .Build ();
5358+
5359+ return IGraphTransformer::TStatus::Repeat;
5360+ }
5361+ }
5362+
5363+ auto posGetter = [&input, &ctx](size_t i) {
5364+ return ctx.Expr .GetPosition (input->Child (i)->Pos ());
5365+ };
5366+
5367+ struct TPgListCommonTypeConversion {
5368+ bool conversionRequired = false ;
5369+ ui32 targetType = 0 ;
5370+ TExprNodeList items;
5371+ };
5372+
5373+ bool castRequired = false ;
5374+ const NPg::TTypeDesc* commonType;
5375+ if (NPg::LookupCommonType (pgTypes, posGetter, commonType, castRequired))
5376+ {
5377+ THashMap<ui32, TPgListCommonTypeConversion> elemsByType;
5378+ for (size_t i = 1 ; i < input->ChildrenSize (); ++i) {
5379+ auto & elemsOfType = elemsByType[pgTypes[i]];
5380+ if (elemsOfType.items .empty ()) {
5381+ const NPg::TTypeDesc* elemCommonType;
5382+ if (const auto issue = NPg::LookupCommonType ({pgTypes[0 ], pgTypes[i]},
5383+ posGetter, elemCommonType, elemsOfType.conversionRequired ))
5384+ {
5385+ ctx.Expr .AddError (*issue);
5386+ return IGraphTransformer::TStatus::Error;
5387+ }
5388+ elemsOfType.targetType = elemCommonType->TypeId ;
5389+ // Clone IN's lhs expression as the leftmost elem in the new type-associated list
5390+ elemsOfType.items .push_back (ctx.Expr .ShallowCopy (input->Head ()));
5391+ elemsOfType.items .back ()->SetTypeAnn (input->Head ().GetTypeAnn ());
5392+ }
5393+ elemsOfType.items .push_back (input->Child (i));
5394+ }
5395+ TExprNodeList orClausesOfIn;
5396+ orClausesOfIn.reserve (elemsByType.size ());
5397+
5398+ for (auto & elemsOfType: elemsByType) {
5399+ auto & conversion = elemsOfType.second ;
5400+ orClausesOfIn.push_back (BuildPgIn (std::move (conversion.items ), conversion.targetType , conversion.conversionRequired , ctx));
5401+ }
5402+ output = ctx.Expr .Builder (input->Pos ())
5403+ .Callable (" Fold" )
5404+ .Callable (0 , " AsList" )
5405+ .Add (std::move (orClausesOfIn))
5406+ .Seal ()
5407+ .Add (1 , MakePgBool (input->Pos (), false , ctx.Expr ))
5408+ .Lambda (2 )
5409+ .Param (" item" )
5410+ .Param (" state" )
5411+ .Callable (" PgOr" )
5412+ .Arg (0 , " state" )
5413+ .Arg (1 , " item" )
5414+ .Seal ()
5415+ .Seal ()
5416+ .Seal ()
5417+ .Build ();
5418+ } else {
5419+ output = BuildPgIn (std::move (input->ChildrenList ()), commonType->TypeId , castRequired, ctx);
5420+ }
5421+ return IGraphTransformer::TStatus::Repeat;
5422+ }
5423+
52885424IGraphTransformer::TStatus PgInWrapper (const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx) {
52895425 if (!EnsureArgsCount (*input, 2 , ctx.Expr )) {
52905426 return IGraphTransformer::TStatus::Error;
0 commit comments