diff options
author | a-romanov <Anton.Romanov@ydb.tech> | 2023-03-24 20:17:48 +0300 |
---|---|---|
committer | a-romanov <Anton.Romanov@ydb.tech> | 2023-03-24 20:17:48 +0300 |
commit | d8cddd218c5dd781ad9f5b6a0d1966e27a16a8bb (patch) | |
tree | b63d748950459b55820b920406a4d415a20b6bfd | |
parent | 8d1337f3c063061366114a566c2b50fd3474b48c (diff) | |
download | ydb-d8cddd218c5dd781ad9f5b6a0d1966e27a16a8bb.tar.gz |
YQL-15756 NothingFrom callable for keep constraints on empty collections.
-rw-r--r-- | ydb/library/yql/core/common_opt/yql_co_simple1.cpp | 17 | ||||
-rw-r--r-- | ydb/library/yql/core/expr_nodes/yql_expr_nodes.json | 5 | ||||
-rw-r--r-- | ydb/library/yql/core/peephole_opt/yql_opt_peephole_physical.cpp | 6 | ||||
-rw-r--r-- | ydb/library/yql/core/type_ann/type_ann_core.cpp | 1 | ||||
-rw-r--r-- | ydb/library/yql/core/type_ann/type_ann_list.cpp | 15 | ||||
-rw-r--r-- | ydb/library/yql/core/type_ann/type_ann_list.h | 1 | ||||
-rw-r--r-- | ydb/library/yql/core/yql_expr_constraint.cpp | 15 | ||||
-rw-r--r-- | ydb/library/yql/core/yql_opt_utils.cpp | 16 | ||||
-rw-r--r-- | ydb/library/yql/core/yql_opt_utils.h | 1 | ||||
-rw-r--r-- | ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp | 17 |
10 files changed, 63 insertions, 31 deletions
diff --git a/ydb/library/yql/core/common_opt/yql_co_simple1.cpp b/ydb/library/yql/core/common_opt/yql_co_simple1.cpp index f71c96811af..69078853a33 100644 --- a/ydb/library/yql/core/common_opt/yql_co_simple1.cpp +++ b/ydb/library/yql/core/common_opt/yql_co_simple1.cpp @@ -1117,22 +1117,7 @@ TExprNode::TPtr OptimizeContainerIf(const TExprNode::TPtr& node, TExprContext& c if (node->Head().IsCallable("Bool")) { YQL_CLOG(DEBUG, Core) << node->Content() << " over " << node->Head().Content() << " '" << node->Head().Head().Content(); const auto value = FromString<bool>(node->Head().Head().Content()); - auto res = value - ? ctx.NewCallable(node->Tail().Pos(), IsList ? "AsList" : "Just", {node->TailPtr()}) - : //TODO: ctx.NewCallable(node->Head().Pos(), IsList ? "List" : "Nothing", {ExpandType(node->Pos(), *node->GetTypeAnn(), ctx)}) - ctx.Builder(node->Head().Pos()) - .Callable(IsList ? "List" : "Nothing") - .Callable(0, IsList ? "ListType" : "OptionalType") - .Callable(0, "TypeOf") - .Add(0, node->TailPtr()) - .Seal() - .Seal() - .Seal().Build(); - if (IsList) { - res = KeepConstraints(res, *node, ctx); - } - return res; - + return ctx.WrapByCallableIf(!value, "NothingFrom", ctx.NewCallable(node->Tail().Pos(), IsList ? "AsList" : "Just", {node->TailPtr()})); } return node; } diff --git a/ydb/library/yql/core/expr_nodes/yql_expr_nodes.json b/ydb/library/yql/core/expr_nodes/yql_expr_nodes.json index fe1e3e9d6f1..238134c5d4a 100644 --- a/ydb/library/yql/core/expr_nodes/yql_expr_nodes.json +++ b/ydb/library/yql/core/expr_nodes/yql_expr_nodes.json @@ -373,6 +373,11 @@ "Match": {"Type": "Callable", "Name": "UnorderedSubquery"} }, { + "Name": "TCoNothingFrom", + "Base": "TCoInputBase", + "Match": {"Type": "Callable", "Name": "NothingFrom"} + }, + { "Name": "TCoConditionalValueBase", "Base": "TCallable", "Match": {"Type": "CallableBase"}, diff --git a/ydb/library/yql/core/peephole_opt/yql_opt_peephole_physical.cpp b/ydb/library/yql/core/peephole_opt/yql_opt_peephole_physical.cpp index f337e9650f6..5ddfeb4842b 100644 --- a/ydb/library/yql/core/peephole_opt/yql_opt_peephole_physical.cpp +++ b/ydb/library/yql/core/peephole_opt/yql_opt_peephole_physical.cpp @@ -2128,7 +2128,7 @@ TExprNode::TPtr ExpandFlatMap(const TExprNode::TPtr& node, TExprContext& ctx) { return ctx.NewCallable(node->Pos(), multimap, {node->HeadPtr(), ctx.DeepCopyLambda(lambda, body.ChildrenList())}); } - if (body.IsCallable("If") && 3U == body.ChildrenSize() && 1U == body.Tail().ChildrenSize() && body.Tail().IsCallable({"List", "Nothing"}) && ( + if (body.IsCallable("If") && 3U == body.ChildrenSize() && 1U == body.Tail().ChildrenSize() && body.Tail().IsCallable({"List", "Nothing", "NothingFrom"}) && ( (1U == body.Child(1)->ChildrenSize() && body.Child(1)->IsCallable({"AsList", "Just"})) || (2U == body.Child(1)->ChildrenSize() && body.Child(1)->IsCallable("List")))) { const bool haveSharedCallables = HaveSharedNodes(body.HeadPtr(), body.Child(1)->TailPtr(), @@ -2344,7 +2344,7 @@ template <bool Flat, bool List> TExprNode::TPtr ExpandContainerIf(const TExprNode::TPtr& input, TExprContext& ctx) { YQL_CLOG(DEBUG, CorePeepHole) << "Expand " << input->Content(); auto item = Flat ? input->TailPtr() : ctx.NewCallable(input->Tail().Pos(), List ? "AsList" : "Just", {input->TailPtr()}); - auto none = ctx.NewCallable(input->Tail().Pos(), List ? "List" : "Nothing", {ExpandType(input->Tail().Pos(), *input->GetTypeAnn(), ctx)}); + auto none = ctx.NewCallable(input->Tail().Pos(), "NothingFrom", {item}); return ctx.NewCallable(input->Pos(), "If", {input->HeadPtr(), std::move(item), std::move(none)}); } @@ -5473,7 +5473,7 @@ TExprNode::TPtr OptimizeNarrowFlatMap(const TExprNode::TPtr& node, TExprContext& const auto& lambda = node->Tail(); const auto& body = lambda.Tail(); - if (body.IsCallable("If") && 1U == body.Tail().ChildrenSize() && body.Tail().IsCallable({"List", "Nothing"})) { + if (body.IsCallable("If") && 1U == body.Tail().ChildrenSize() && body.Tail().IsCallable({"List", "Nothing", "NothingFrom"})) { const auto width = lambda.Head().ChildrenSize(); if (auto shared = FindSharedNode(body.ChildPtr(1), body.HeadPtr(), [&lambda] (const TExprNode::TPtr& node) { diff --git a/ydb/library/yql/core/type_ann/type_ann_core.cpp b/ydb/library/yql/core/type_ann/type_ann_core.cpp index 5b4c37bdb4d..c29f236aa03 100644 --- a/ydb/library/yql/core/type_ann/type_ann_core.cpp +++ b/ydb/library/yql/core/type_ann/type_ann_core.cpp @@ -11811,6 +11811,7 @@ template <NKikimr::NUdf::EDataSlot DataSlot> Functions["BuildTablePath"] = &BuildTablePathWrapper; Functions["WithOptionalArgs"] = &WithOptionalArgsWrapper; Functions["WithContext"] = &WithContextWrapper; + Functions["NothingFrom"] = &NothingFromWrapper; Functions["DecimalDiv"] = &DecimalBinaryWrapper; Functions["DecimalMod"] = &DecimalBinaryWrapper; diff --git a/ydb/library/yql/core/type_ann/type_ann_list.cpp b/ydb/library/yql/core/type_ann/type_ann_list.cpp index 6051ce2cbb5..4739cac5f58 100644 --- a/ydb/library/yql/core/type_ann/type_ann_list.cpp +++ b/ydb/library/yql/core/type_ann/type_ann_list.cpp @@ -7152,7 +7152,7 @@ namespace { } } else { auto children = input->ChildrenList(); - children.emplace_back(ctx.Expr.NewCallable(input->Pos(), "Uint64", {ctx.Expr.NewAtom(input->Pos(), "0", TNodeFlags::Default)})); + children.emplace_back(ctx.Expr.NewCallable(input->Pos(), "Uint64", {ctx.Expr.NewAtom(input->Pos(), 0U)})); output = ctx.Expr.ChangeChildren(*input, std::move(children)); return IGraphTransformer::TStatus::Repeat; } @@ -7162,6 +7162,19 @@ namespace { return IGraphTransformer::TStatus::Ok; } + IGraphTransformer::TStatus NothingFromWrapper(const TExprNode::TPtr& input, TExprNode::TPtr&, TContext& ctx) { + if (!EnsureArgsCount(*input, 1, ctx.Expr)) { + return IGraphTransformer::TStatus::Error; + } + + if (const TTypeAnnotationNode* itemType = nullptr; !EnsureNewSeqType<true>(input->Head(), ctx.Expr, &itemType)) { + return IGraphTransformer::TStatus::Error; + } + + input->SetTypeAnn(input->Head().GetTypeAnn()); + return IGraphTransformer::TStatus::Ok; + } + TExprNode::TPtr ExpandToWindowTraits(const TExprNode& input, TExprContext& ctx) { YQL_ENSURE(input.IsCallable("AggregationTraits")); return ctx.Builder(input.Pos()) diff --git a/ydb/library/yql/core/type_ann/type_ann_list.h b/ydb/library/yql/core/type_ann/type_ann_list.h index 10df53318ca..7657d41cec0 100644 --- a/ydb/library/yql/core/type_ann/type_ann_list.h +++ b/ydb/library/yql/core/type_ann/type_ann_list.h @@ -130,5 +130,6 @@ namespace NTypeAnnImpl { IGraphTransformer::TStatus ListFlattenWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus IterableWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); IGraphTransformer::TStatus SqueezeToListWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); + IGraphTransformer::TStatus NothingFromWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx); } // namespace NTypeAnnImpl } // namespace NYql diff --git a/ydb/library/yql/core/yql_expr_constraint.cpp b/ydb/library/yql/core/yql_expr_constraint.cpp index 55bebec750a..52ceb2e6471 100644 --- a/ydb/library/yql/core/yql_expr_constraint.cpp +++ b/ydb/library/yql/core/yql_expr_constraint.cpp @@ -167,6 +167,7 @@ public: Functions["ListIf"] = &TCallableConstraintTransformer::PassOrEmptyWrap<true, false>; Functions["FlatListIf"] = &TCallableConstraintTransformer::PassOrEmptyWrap<true, true>; Functions["EmptyIterator"] = &TCallableConstraintTransformer::FromEmpty; + Functions["NothingFrom"] = &TCallableConstraintTransformer::NothingFromWrap; Functions["List"] = &TCallableConstraintTransformer::ListWrap; Functions["Dict"] = &TCallableConstraintTransformer::DictWrap; Functions["EmptyList"] = &TCallableConstraintTransformer::FromEmpty; @@ -313,6 +314,20 @@ private: return TStatus::Ok; } + TStatus NothingFromWrap(const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx) const { + auto set = input->Head().GetConstraintSet(); + set.RemoveConstraint(TEmptyConstraintNode::Name()); + if (!set) { + const auto type = input->GetTypeAnn(); + output = ctx.NewCallable(input->Pos(), GetEmptyCollectionName(type), {ExpandType(input->Pos(), *type, ctx)}); + return TStatus::Repeat; + } + + set.AddConstraint(ctx.MakeConstraint<TEmptyConstraintNode>()); + input->SetConstraints(set); + return TStatus::Ok; + } + template <size_t LambdaIdx> TStatus FromFinalLambda(const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx) const { TStatus status = UpdateAllChildLambdasConstraints(*input); diff --git a/ydb/library/yql/core/yql_opt_utils.cpp b/ydb/library/yql/core/yql_opt_utils.cpp index c078253f5a1..50858868fa7 100644 --- a/ydb/library/yql/core/yql_opt_utils.cpp +++ b/ydb/library/yql/core/yql_opt_utils.cpp @@ -68,7 +68,7 @@ bool IsJustOrSingleAsList(const TExprNode& node) { } bool IsTransparentIfPresent(const TExprNode& node) { - return (node.IsCallable("FlatMap") || (3U == node.ChildrenSize() && node.IsCallable("IfPresent") && node.Tail().IsCallable("Nothing"))) + return (node.IsCallable("FlatMap") || (3U == node.ChildrenSize() && node.IsCallable("IfPresent") && node.Tail().IsCallable({"Nothing", "NothingFrom"}))) && node.Child(1U)->Tail().IsCallable("Just"); } @@ -345,13 +345,9 @@ bool IsEmpty(const TExprNode& node, const TTypeAnnotationContext& typeCtx) { return typeCtx.IsConstraintCheckEnabled<TEmptyConstraintNode>() && node.Type() != TExprNode::Argument && node.GetConstraint<TEmptyConstraintNode>() != nullptr; } -bool IsEmptyOptional(const TExprNode& node) { - return node.IsCallable("Nothing"); -} - bool IsEmptyContainer(const TExprNode& node) { return node.IsCallable({"EmptyList", "EmptyDict"}) - || (1U == node.ChildrenSize() && node.IsCallable({"List", "Nothing", "EmptyIterator", "Dict"})); + || (1U == node.ChildrenSize() && node.IsCallable({"List", "Nothing", "EmptyIterator", "Dict", "NothingFrom"})); } const TTypeAnnotationNode* RemoveOptionalType(const TTypeAnnotationNode* type) { @@ -1155,7 +1151,7 @@ TExprNode::TPtr OptimizeIfPresent(const TExprNode::TPtr& node, TExprContext& ctx .Seal().Build(); } - if (std::any_of(optionals.cbegin(), optionals.cend(), [](const TExprNode::TPtr& node) { return node->IsCallable("Nothing"); })) { + if (std::any_of(optionals.cbegin(), optionals.cend(), [](const TExprNode::TPtr& node) { return node->IsCallable({"Nothing","NothingFrom"}); })) { YQL_CLOG(DEBUG, Core) << node->Content() << " over Nothing."; return node->TailPtr(); } @@ -1224,14 +1220,14 @@ TExprNode::TPtr OptimizeIfPresent(const TExprNode::TPtr& node, TExprContext& ctx .Seal().Build(); } - if (lambda.Tail().IsCallable({"SafeCast", "StrictCast"}) && node->Tail().IsCallable("Nothing") && &lambda.Tail().Head() == &lambda.Head().Head() && + if (lambda.Tail().IsCallable({"SafeCast", "StrictCast"}) && node->Tail().IsCallable({"Nothing","NothingFrom"}) && &lambda.Tail().Head() == &lambda.Head().Head() && ETypeAnnotationKind::Optional != node->Head().GetTypeAnn()->Cast<TOptionalExprType>()->GetItemType()->GetKind()) { YQL_CLOG(DEBUG, Core) << "Drop " << node->Content() << " with " << lambda.Tail().Content() << " and " << node->Tail().Content(); return ctx.ChangeChild(lambda.Tail(), 0U, node->HeadPtr()); } if constexpr (Cannonize) { - if (node->Tail().IsCallable("Nothing") && node->Tail().GetTypeAnn()->GetKind() != ETypeAnnotationKind::Pg) { + if (node->Tail().IsCallable({"Nothing","NothingFrom"}) && node->Tail().GetTypeAnn()->GetKind() != ETypeAnnotationKind::Pg) { YQL_CLOG(DEBUG, Core) << node->Content() << " with else " << node->Tail().Content(); return ctx.NewCallable(node->Pos(), "FlatMap", { node->HeadPtr(), node->ChildPtr(1) }); } @@ -1304,7 +1300,7 @@ TExprNode::TPtr OptimizeExists(const TExprNode::TPtr& node, TExprContext& ctx) return MakeBool<true>(node->Pos(), ctx); } - if (node->Head().IsCallable("Nothing")) { + if (node->Head().IsCallable({"Nothing","NothingFrom"})) { YQL_CLOG(DEBUG, Core) << node->Content() << " over " << node->Head().Content(); return MakeBool<false>(node->Pos(), ctx); } diff --git a/ydb/library/yql/core/yql_opt_utils.h b/ydb/library/yql/core/yql_opt_utils.h index ac72e5ef666..6863df79371 100644 --- a/ydb/library/yql/core/yql_opt_utils.h +++ b/ydb/library/yql/core/yql_opt_utils.h @@ -37,7 +37,6 @@ TExprNode::TPtr AddMembersUsedInside(const TExprNode::TPtr& start, const TExprNo bool IsDepended(const TExprNode& from, const TExprNode& to); bool IsEmpty(const TExprNode& node, const TTypeAnnotationContext& typeCtx); -bool IsEmptyOptional(const TExprNode& node); bool IsEmptyContainer(const TExprNode& node); const TTypeAnnotationNode* RemoveOptionalType(const TTypeAnnotationNode* type); diff --git a/ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp b/ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp index 7ec16e840a7..0d1c3e5f5ef 100644 --- a/ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp +++ b/ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp @@ -1274,6 +1274,23 @@ TMkqlCommonCallableCompiler::TShared::TShared() { return ctx.ProgramBuilder.Unwrap(opt, message, pos.File, pos.Row, pos.Column); }); + AddCallable("NothingFrom", [](const TExprNode& node, TMkqlBuildContext& ctx) { + const auto type = BuildType(node.Head(), *node.GetTypeAnn(), ctx.ProgramBuilder); + switch (node.GetTypeAnn()->GetKind()) { + case ETypeAnnotationKind::Flow: + case ETypeAnnotationKind::Stream: + return ctx.ProgramBuilder.EmptyIterator(type); + case ETypeAnnotationKind::Optional: + return ctx.ProgramBuilder.NewEmptyOptional(type); + case ETypeAnnotationKind::List: + return ctx.ProgramBuilder.NewEmptyList(AS_TYPE(TListType, type)->GetItemType()); + case ETypeAnnotationKind::Dict: + return ctx.ProgramBuilder.NewDict(type, {}); + default: + ythrow TNodeException(node) << "Nothing from " << *node.GetTypeAnn() << " isn't supported."; + } + }); + AddCallable("Nothing", [](const TExprNode& node, TMkqlBuildContext& ctx) { const auto optType = BuildType(node.Head(), *node.Head().GetTypeAnn()->Cast<TTypeExprType>()->GetType(), ctx.ProgramBuilder); return ctx.ProgramBuilder.NewEmptyOptional(optType); |