aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authora-romanov <Anton.Romanov@ydb.tech>2023-03-24 20:17:48 +0300
committera-romanov <Anton.Romanov@ydb.tech>2023-03-24 20:17:48 +0300
commitd8cddd218c5dd781ad9f5b6a0d1966e27a16a8bb (patch)
treeb63d748950459b55820b920406a4d415a20b6bfd
parent8d1337f3c063061366114a566c2b50fd3474b48c (diff)
downloadydb-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.cpp17
-rw-r--r--ydb/library/yql/core/expr_nodes/yql_expr_nodes.json5
-rw-r--r--ydb/library/yql/core/peephole_opt/yql_opt_peephole_physical.cpp6
-rw-r--r--ydb/library/yql/core/type_ann/type_ann_core.cpp1
-rw-r--r--ydb/library/yql/core/type_ann/type_ann_list.cpp15
-rw-r--r--ydb/library/yql/core/type_ann/type_ann_list.h1
-rw-r--r--ydb/library/yql/core/yql_expr_constraint.cpp15
-rw-r--r--ydb/library/yql/core/yql_opt_utils.cpp16
-rw-r--r--ydb/library/yql/core/yql_opt_utils.h1
-rw-r--r--ydb/library/yql/providers/common/mkql/yql_provider_mkql.cpp17
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);