diff options
author | Andrey Neporada <aneporada@ydb.tech> | 2024-08-12 17:18:43 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-12 17:18:43 +0300 |
commit | 1345ce6aaa0ea9d99a77d9866dd588b84b46ed2c (patch) | |
tree | 0cb56eb2e2946324799f720dd3fd8aaa7e1b1b5c | |
parent | 976e2c703afb734c8996d901b3b87e862595234e (diff) | |
download | ydb-1345ce6aaa0ea9d99a77d9866dd588b84b46ed2c.tar.gz |
Collect statistic about unsuccessful block rewrites for callables and types (#7642)
31 files changed, 422 insertions, 47 deletions
diff --git a/ydb/library/yql/core/facade/yql_facade.cpp b/ydb/library/yql/core/facade/yql_facade.cpp index f58b26f08f9..bff0ec24adc 100644 --- a/ydb/library/yql/core/facade/yql_facade.cpp +++ b/ydb/library/yql/core/facade/yql_facade.cpp @@ -30,6 +30,7 @@ #include <util/stream/file.h> #include <util/stream/null.h> +#include <util/string/join.h> #include <util/string/split.h> #include <util/generic/guid.h> #include <util/system/rusage.h> @@ -1629,6 +1630,48 @@ NThreading::TFuture<void> TProgram::Abort() return CloseLastSession(); } +TIssues TProgram::Issues() const { + TIssues result; + if (ExprCtx_) { + result.AddIssues(ExprCtx_->IssueManager.GetIssues()); + } + result.AddIssues(FinalIssues_); + return result; +} + +TIssues TProgram::CompletedIssues() const { + TIssues result; + if (ExprCtx_) { + result.AddIssues(ExprCtx_->IssueManager.GetCompletedIssues()); + } + result.AddIssues(FinalIssues_); + return result; +} + +TIssue MakeNoBlocksInfoIssue(const TVector<TString>& names, bool isTypes) { + TIssue result; + TString msg = TStringBuilder() << "Most frequent " << (isTypes ? "types " : "callables ") + << "which do not support block mode: " << JoinRange(", ", names.begin(), names.end()); + result.SetMessage(msg); + result.SetCode(isTypes ? TIssuesIds::CORE_TOP_UNSUPPORTED_BLOCK_TYPES : TIssuesIds::CORE_TOP_UNSUPPORTED_BLOCK_CALLABLES, TSeverityIds::S_INFO); + return result; +} + +void TProgram::FinalizeIssues() { + FinalIssues_.Clear(); + if (TypeCtx_) { + static const size_t topCount = 10; + auto noBlockTypes = TypeCtx_->GetTopNoBlocksTypes(topCount); + if (!noBlockTypes.empty()) { + FinalIssues_.AddIssue(MakeNoBlocksInfoIssue(noBlockTypes, true)); + } + auto noBlockCallables = TypeCtx_->GetTopNoBlocksCallables(topCount); + if (!noBlockCallables.empty()) { + FinalIssues_.AddIssue(MakeNoBlocksInfoIssue(noBlockCallables, false)); + } + } +} + NThreading::TFuture<void> TProgram::CleanupLastSession() { YQL_LOG_CTX_ROOT_SESSION_SCOPE(GetSessionId()); diff --git a/ydb/library/yql/core/facade/yql_facade.h b/ydb/library/yql/core/facade/yql_facade.h index 3536d7a4758..9aceae87c37 100644 --- a/ydb/library/yql/core/facade/yql_facade.h +++ b/ydb/library/yql/core/facade/yql_facade.h @@ -192,28 +192,14 @@ public: [[nodiscard]] NThreading::TFuture<void> Abort(); - inline TIssues Issues() { - if (ExprCtx_) { - return ExprCtx_->IssueManager.GetIssues(); - } else { - return {}; - } - } - - inline TIssues CompletedIssues() const { - if (ExprCtx_) { - return ExprCtx_->IssueManager.GetCompletedIssues(); - } else { - return {}; - } - } + TIssues Issues() const; + TIssues CompletedIssues() const; + void FinalizeIssues(); void Print(IOutputStream* exprOut, IOutputStream* planOut, bool cleanPlan = false); inline void PrintErrorsTo(IOutputStream& out) const { - if (ExprCtx_) { - ExprCtx_->IssueManager.GetIssues().PrintWithProgramTo(out, Filename_, SourceCode_); - } + Issues().PrintWithProgramTo(out, Filename_, SourceCode_); } inline const TAstNode* AstRoot() const { @@ -455,6 +441,7 @@ private: TMaybe<TString> LineageStr_; TQContext QContext_; + TIssues FinalIssues_; }; } // namspace NYql diff --git a/ydb/library/yql/core/issue/protos/issue_id.proto b/ydb/library/yql/core/issue/protos/issue_id.proto index 5d8812c6402..a635b9b9a52 100644 --- a/ydb/library/yql/core/issue/protos/issue_id.proto +++ b/ydb/library/yql/core/issue/protos/issue_id.proto @@ -39,6 +39,10 @@ message TIssuesIds { CORE_ALIAS_SHADOWS_COLUMN = 1111; CORE_LINEAGE_INTERNAL_ERROR = 1112; +// core informational + CORE_TOP_UNSUPPORTED_BLOCK_TYPES = 1200; + CORE_TOP_UNSUPPORTED_BLOCK_CALLABLES = 1201; + // core errors CORE_GC_NODES_LIMIT_EXCEEDED = 1500; CORE_GC_STRINGS_LIMIT_EXCEEDED = 1501; diff --git a/ydb/library/yql/core/issue/yql_issue.txt b/ydb/library/yql/core/issue/yql_issue.txt index d9ecca2db9e..7a4151a1898 100644 --- a/ydb/library/yql/core/issue/yql_issue.txt +++ b/ydb/library/yql/core/issue/yql_issue.txt @@ -663,3 +663,11 @@ ids { code: YT_SECURE_DATA_IN_COMMON_TMP severity: S_WARNING } +ids { + code: CORE_TOP_UNSUPPORTED_BLOCK_TYPES + severity: S_INFO +} +ids { + code: CORE_TOP_UNSUPPORTED_BLOCK_CALLABLES + severity: S_INFO +} 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 b2ba6f70743..940656f76ca 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 @@ -2291,10 +2291,11 @@ IGraphTransformer::TStatus PeepHoleFinalStage(const TExprNode::TPtr& input, TExp } IGraphTransformer::TStatus PeepHoleBlockStage(const TExprNode::TPtr& input, TExprNode::TPtr& output, - TExprContext& ctx, TTypeAnnotationContext& types, const TExtPeepHoleOptimizerMap& extOptimizers) + TExprContext& ctx, TTypeAnnotationContext& types, const TExtPeepHoleOptimizerMap& extOptimizers, TProcessedNodesSet& cache) { TOptimizeExprSettings settings(&types); settings.CustomInstantTypeTransformer = types.CustomInstantTypeTransformer.Get(); + settings.ProcessedNodes = &cache; return OptimizeExpr(input, output, [&types, &extOptimizers]( const TExprNode::TPtr& node, TExprContext& ctx) -> TExprNode::TPtr { @@ -5693,7 +5694,11 @@ bool CollectBlockRewrites(const TMultiExprType* multiInputType, bool keepInputCo allInputTypes.push_back(i); } - auto resolveStatus = types.ArrowResolver->AreTypesSupported(ctx.GetPosition(lambda->Pos()), allInputTypes, ctx); + const IArrowResolver::TUnsupportedTypeCallback onUnsupportedType = [&types](const auto& typeKindOrSlot) { + std::visit([&types](const auto& value) { types.IncNoBlockType(value); }, typeKindOrSlot); + }; + + auto resolveStatus = types.ArrowResolver->AreTypesSupported(ctx.GetPosition(lambda->Pos()), allInputTypes, ctx, onUnsupportedType); YQL_ENSURE(resolveStatus != IArrowResolver::ERROR); if (resolveStatus != IArrowResolver::OK) { return false; @@ -5747,7 +5752,7 @@ bool CollectBlockRewrites(const TMultiExprType* multiInputType, bool keepInputCo if (node->IsList() || rewriteAsIs || node->IsCallable({"And", "Or", "Xor", "Not", "Coalesce", "Exists", "If", "Just", "AsStruct", "Member", "Nth", "ToPg", "FromPg", "PgResolvedCall", "PgResolvedOp"})) { - if (node->IsCallable() && !IsSupportedAsBlockType(node->Pos(), *node->GetTypeAnn(), ctx, types)) { + if (node->IsCallable() && !IsSupportedAsBlockType(node->Pos(), *node->GetTypeAnn(), ctx, types, true)) { return true; } @@ -5775,7 +5780,7 @@ bool CollectBlockRewrites(const TMultiExprType* multiInputType, bool keepInputCo auto child = node->ChildPtr(index); if (!child->GetTypeAnn()->IsComputable()) { funcArgs.push_back(child); - } else if (child->IsComplete() && IsSupportedAsBlockType(child->Pos(), *child->GetTypeAnn(), ctx, types)) { + } else if (child->IsComplete() && IsSupportedAsBlockType(child->Pos(), *child->GetTypeAnn(), ctx, types, true)) { funcArgs.push_back(ctx.NewCallable(node->Pos(), "AsScalar", { child })); } else if (auto rit = rewrites.find(child.Get()); rit != rewrites.end()) { funcArgs.push_back(rit->second); @@ -5796,7 +5801,7 @@ bool CollectBlockRewrites(const TMultiExprType* multiInputType, bool keepInputCo auto member = funcArgs[index]; auto child = member->TailPtr(); TExprNodePtr rewrite; - if (child->IsComplete() && IsSupportedAsBlockType(child->Pos(), *child->GetTypeAnn(), ctx, types)) { + if (child->IsComplete() && IsSupportedAsBlockType(child->Pos(), *child->GetTypeAnn(), ctx, types, true)) { rewrite = ctx.NewCallable(child->Pos(), "AsScalar", { child }); } else if (auto rit = rewrites.find(child.Get()); rit != rewrites.end()) { rewrite = rit->second; @@ -5821,6 +5826,7 @@ bool CollectBlockRewrites(const TMultiExprType* multiInputType, bool keepInputCo const bool isUdf = node->IsCallable("Apply") && node->Head().IsCallable("Udf"); if (isUdf) { if (!GetSetting(*node->Head().Child(7), "blocks")) { + types.IncNoBlockCallable(node->Head().Head().Content()); return true; } } @@ -5832,7 +5838,7 @@ bool CollectBlockRewrites(const TMultiExprType* multiInputType, bool keepInputCo allTypes.push_back(node->Child(i)->GetTypeAnn()); } - auto resolveStatus = types.ArrowResolver->AreTypesSupported(ctx.GetPosition(node->Pos()), allTypes, ctx); + auto resolveStatus = types.ArrowResolver->AreTypesSupported(ctx.GetPosition(node->Pos()), allTypes, ctx, onUnsupportedType); YQL_ENSURE(resolveStatus != IArrowResolver::ERROR); if (resolveStatus != IArrowResolver::OK) { return true; @@ -5898,6 +5904,7 @@ bool CollectBlockRewrites(const TMultiExprType* multiInputType, bool keepInputCo } else { auto fit = funcs.find(node->Content()); if (fit == funcs.end()) { + types.IncNoBlockCallable(node->Content()); return true; } @@ -5907,6 +5914,7 @@ bool CollectBlockRewrites(const TMultiExprType* multiInputType, bool keepInputCo auto resolveStatus = types.ArrowResolver->LoadFunctionMetadata(ctx.GetPosition(node->Pos()), arrowFunctionName, argTypes, outType, ctx); YQL_ENSURE(resolveStatus != IArrowResolver::ERROR); if (resolveStatus != IArrowResolver::OK) { + types.IncNoBlockCallable(node->Content()); return true; } funcArgs.push_back(ExpandType(node->Pos(), *outType, ctx)); @@ -8555,10 +8563,10 @@ THolder<IGraphTransformer> CreatePeepHoleFinalStageTransformer(TTypeAnnotationCo pipeline.Add( CreateFunctorTransformer( - [&types](const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx) -> IGraphTransformer::TStatus { + [&types, cache = TProcessedNodesSet()](const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx) mutable -> IGraphTransformer::TStatus { if (types.IsBlockEngineEnabled()) { const auto& extStageRules = TPeepHoleRules::Instance().BlockStageExtRules; - return PeepHoleBlockStage(input, output, ctx, types, extStageRules); + return PeepHoleBlockStage(input, output, ctx, types, extStageRules, cache); } else { output = input; return IGraphTransformer::TStatus::Ok; @@ -8574,10 +8582,10 @@ THolder<IGraphTransformer> CreatePeepHoleFinalStageTransformer(TTypeAnnotationCo pipeline.Add( CreateFunctorTransformer( - [&types](const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx) -> IGraphTransformer::TStatus { + [&types, cache = TProcessedNodesSet()](const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx) mutable -> IGraphTransformer::TStatus { if (types.IsBlockEngineEnabled()) { const auto& extStageRules = TPeepHoleRules::Instance().BlockStageExtFinalRules; - return PeepHoleBlockStage(input, output, ctx, types, extStageRules); + return PeepHoleBlockStage(input, output, ctx, types, extStageRules, cache); } else { output = input; return IGraphTransformer::TStatus::Ok; diff --git a/ydb/library/yql/core/yql_arrow_resolver.h b/ydb/library/yql/core/yql_arrow_resolver.h index d30f6239ca3..b22dfe3ee9a 100644 --- a/ydb/library/yql/core/yql_arrow_resolver.h +++ b/ydb/library/yql/core/yql_arrow_resolver.h @@ -2,11 +2,15 @@ #include <ydb/library/yql/ast/yql_expr.h> +#include <functional> +#include <variant> + namespace NYql { class IArrowResolver : public TThrRefBase { public: using TPtr = TIntrusiveConstPtr<IArrowResolver>; + using TUnsupportedTypeCallback = std::function<void(std::variant<ETypeAnnotationKind, NUdf::EDataSlot>)>; enum EStatus { OK, @@ -21,7 +25,8 @@ public: virtual EStatus HasCast(const TPosition& pos, const TTypeAnnotationNode* from, const TTypeAnnotationNode* to, TExprContext& ctx) const = 0; - virtual EStatus AreTypesSupported(const TPosition& pos, const TVector<const TTypeAnnotationNode*>& types, TExprContext& ctx) const = 0; + virtual EStatus AreTypesSupported(const TPosition& pos, const TVector<const TTypeAnnotationNode*>& types, TExprContext& ctx, + const TUnsupportedTypeCallback& onUnsupported = {}) const = 0; }; } diff --git a/ydb/library/yql/core/yql_expr_type_annotation.cpp b/ydb/library/yql/core/yql_expr_type_annotation.cpp index d4bdae90694..57636a4d52c 100644 --- a/ydb/library/yql/core/yql_expr_type_annotation.cpp +++ b/ydb/library/yql/core/yql_expr_type_annotation.cpp @@ -3126,12 +3126,20 @@ bool IsWideSequenceBlockType(const TTypeAnnotationNode& type) { return IsWideBlockType(*itemType); } -bool IsSupportedAsBlockType(TPositionHandle pos, const TTypeAnnotationNode& type, TExprContext& ctx, TTypeAnnotationContext& types) { +bool IsSupportedAsBlockType(TPositionHandle pos, const TTypeAnnotationNode& type, TExprContext& ctx, TTypeAnnotationContext& types, + bool reportUnspported) +{ if (!types.ArrowResolver) { return false; } - auto resolveStatus = types.ArrowResolver->AreTypesSupported(ctx.GetPosition(pos), { &type }, ctx); + IArrowResolver::TUnsupportedTypeCallback onUnsupportedType; + if (reportUnspported) { + onUnsupportedType = [&types](const auto& typeKindOrSlot) { + std::visit([&types](const auto& value) { types.IncNoBlockType(value); }, typeKindOrSlot); + }; + } + auto resolveStatus = types.ArrowResolver->AreTypesSupported(ctx.GetPosition(pos), { &type }, ctx, onUnsupportedType); YQL_ENSURE(resolveStatus != IArrowResolver::ERROR); return resolveStatus == IArrowResolver::OK; } diff --git a/ydb/library/yql/core/yql_expr_type_annotation.h b/ydb/library/yql/core/yql_expr_type_annotation.h index 8030fdbad85..46e37ef4bfd 100644 --- a/ydb/library/yql/core/yql_expr_type_annotation.h +++ b/ydb/library/yql/core/yql_expr_type_annotation.h @@ -130,7 +130,7 @@ bool EnsureWideStreamType(const TExprNode& node, TExprContext& ctx); bool EnsureWideStreamType(TPositionHandle position, const TTypeAnnotationNode& type, TExprContext& ctx); bool IsWideBlockType(const TTypeAnnotationNode& type); bool IsWideSequenceBlockType(const TTypeAnnotationNode& type); -bool IsSupportedAsBlockType(TPositionHandle pos, const TTypeAnnotationNode& type, TExprContext& ctx, TTypeAnnotationContext& types); +bool IsSupportedAsBlockType(TPositionHandle pos, const TTypeAnnotationNode& type, TExprContext& ctx, TTypeAnnotationContext& types, bool reportUnspported = false); bool EnsureSupportedAsBlockType(TPositionHandle pos, const TTypeAnnotationNode& type, TExprContext& ctx, TTypeAnnotationContext& types); bool EnsureWideBlockType(TPositionHandle position, const TTypeAnnotationNode& type, TTypeAnnotationNode::TListType& blockItemTypes, TExprContext& ctx, bool allowScalar = true); bool EnsureWideFlowBlockType(const TExprNode& node, TTypeAnnotationNode::TListType& blockItemTypes, TExprContext& ctx, bool allowScalar = true); diff --git a/ydb/library/yql/core/yql_type_annotation.cpp b/ydb/library/yql/core/yql_type_annotation.cpp index 14f80c335e1..b565f615650 100644 --- a/ydb/library/yql/core/yql_type_annotation.cpp +++ b/ydb/library/yql/core/yql_type_annotation.cpp @@ -56,6 +56,61 @@ void TTypeAnnotationContext::Reset() { ExpectedConstraints.clear(); ExpectedColumnOrders.clear(); StatisticsMap.clear(); + NoBlockRewriteCallableStats.clear(); + NoBlockRewriteTypeStats.clear(); +} + +void TTypeAnnotationContext::IncNoBlockCallable(TStringBuf callableName) { + ++NoBlockRewriteCallableStats[callableName]; +} + +void TTypeAnnotationContext::IncNoBlockType(const TTypeAnnotationNode& type) { + if (type.GetKind() == ETypeAnnotationKind::Data) { + IncNoBlockType(type.Cast<TDataExprType>()->GetSlot()); + } else { + IncNoBlockType(type.GetKind()); + } +} + +void TTypeAnnotationContext::IncNoBlockType(ETypeAnnotationKind kind) { + ++NoBlockRewriteTypeStats[ToString(kind)]; +} + +void TTypeAnnotationContext::IncNoBlockType(NUdf::EDataSlot slot) { + ++NoBlockRewriteTypeStats[ToString(slot)]; +} + +namespace { + +template<typename T> +TVector<T> GetMaxByCount(const THashMap<T, size_t>& stats, size_t maxCount) { + TVector<T> result; + result.reserve(stats.size()); + for (auto& [key, _] : stats) { + result.push_back(key); + } + size_t n = std::min(maxCount, stats.size()); + std::partial_sort(result.begin(), result.begin() + n, result.end(), + [&stats](const T& l, const T& r) { + const auto& cntLeft = stats.find(l)->second; + const auto& cntRight = stats.find(r)->second; + if (cntLeft != cntRight) { + return cntLeft < cntRight; + } + return l < r; + }); + result.resize(n); + return result; +} + +} + +TVector<TString> TTypeAnnotationContext::GetTopNoBlocksCallables(size_t maxCount) const { + return GetMaxByCount(NoBlockRewriteCallableStats, maxCount); +} + +TVector<TString> TTypeAnnotationContext::GetTopNoBlocksTypes(size_t maxCount) const { + return GetMaxByCount(NoBlockRewriteTypeStats, maxCount); } TString TColumnOrder::Find(const TString& name) const { diff --git a/ydb/library/yql/core/yql_type_annotation.h b/ydb/library/yql/core/yql_type_annotation.h index 8e8bbaa53a4..dbc63d61d5f 100644 --- a/ydb/library/yql/core/yql_type_annotation.h +++ b/ydb/library/yql/core/yql_type_annotation.h @@ -334,6 +334,8 @@ struct TTypeAnnotationContext: public TThrRefBase { ui32 FolderSubDirsLimit = 1000; bool UseBlocks = false; EBlockEngineMode BlockEngineMode = EBlockEngineMode::Disable; + THashMap<TString, size_t> NoBlockRewriteCallableStats; + THashMap<TString, size_t> NoBlockRewriteTypeStats; TMaybe<bool> PgEmitAggApply; IArrowResolver::TPtr ArrowResolver; TFileStoragePtr FileStorage; @@ -441,6 +443,14 @@ struct TTypeAnnotationContext: public TThrRefBase { bool IsBlockEngineEnabled() const { return BlockEngineMode != EBlockEngineMode::Disable || UseBlocks; } + + void IncNoBlockCallable(TStringBuf callableName); + void IncNoBlockType(const TTypeAnnotationNode& type); + void IncNoBlockType(ETypeAnnotationKind kind); + void IncNoBlockType(NUdf::EDataSlot slot); + + TVector<TString> GetTopNoBlocksCallables(size_t maxCount) const; + TVector<TString> GetTopNoBlocksTypes(size_t maxCount) const; }; template <> inline diff --git a/ydb/library/yql/minikql/mkql_type_builder.cpp b/ydb/library/yql/minikql/mkql_type_builder.cpp index 8fc007e9c82..2116718db5f 100644 --- a/ydb/library/yql/minikql/mkql_type_builder.cpp +++ b/ydb/library/yql/minikql/mkql_type_builder.cpp @@ -1517,7 +1517,7 @@ bool ConvertArrowType(NUdf::EDataSlot slot, std::shared_ptr<arrow::DataType>& ty } } -bool ConvertArrowType(TType* itemType, std::shared_ptr<arrow::DataType>& type) { +bool ConvertArrowType(TType* itemType, std::shared_ptr<arrow::DataType>& type, const TArrowConvertFailedCallback& onFail) { bool isOptional; auto unpacked = UnpackOptional(itemType, isOptional); if (unpacked->IsOptional() || isOptional && unpacked->IsPg()) { @@ -1538,7 +1538,7 @@ bool ConvertArrowType(TType* itemType, std::shared_ptr<arrow::DataType>& type) { // previousType is always Optional std::shared_ptr<arrow::DataType> innerArrowType; - if (!ConvertArrowType(previousType, innerArrowType)) { + if (!ConvertArrowType(previousType, innerArrowType, onFail)) { return false; } @@ -1560,7 +1560,7 @@ bool ConvertArrowType(TType* itemType, std::shared_ptr<arrow::DataType>& type) { std::shared_ptr<arrow::DataType> childType; const TString memberName(structType->GetMemberName(i)); auto memberType = structType->GetMemberType(i); - if (!ConvertArrowType(memberType, childType)) { + if (!ConvertArrowType(memberType, childType, onFail)) { return false; } members.emplace_back(std::make_shared<arrow::Field>(memberName, childType, memberType->IsOptional())); @@ -1576,7 +1576,7 @@ bool ConvertArrowType(TType* itemType, std::shared_ptr<arrow::DataType>& type) { for (ui32 i = 0; i < tupleType->GetElementsCount(); ++i) { std::shared_ptr<arrow::DataType> childType; auto elementType = tupleType->GetElementType(i); - if (!ConvertArrowType(elementType, childType)) { + if (!ConvertArrowType(elementType, childType, onFail)) { return false; } @@ -1605,15 +1605,25 @@ bool ConvertArrowType(TType* itemType, std::shared_ptr<arrow::DataType>& type) { } if (!unpacked->IsData()) { + if (onFail) { + onFail(unpacked); + } return false; } auto slot = AS_TYPE(TDataType, unpacked)->GetDataSlot(); if (!slot) { + if (onFail) { + onFail(unpacked); + } return false; } - return ConvertArrowType(*slot, type); + bool result = ConvertArrowType(*slot, type); + if (!result && onFail) { + onFail(unpacked); + } + return result; } void TArrowType::Export(ArrowSchema* out) const { diff --git a/ydb/library/yql/minikql/mkql_type_builder.h b/ydb/library/yql/minikql/mkql_type_builder.h index 6c2f9b4acc6..285cc1c8b2b 100644 --- a/ydb/library/yql/minikql/mkql_type_builder.h +++ b/ydb/library/yql/minikql/mkql_type_builder.h @@ -30,7 +30,8 @@ inline size_t CalcBlockLen(size_t maxBlockItemSize) { return MaxBlockSizeInBytes / std::max<size_t>(maxBlockItemSize, 1); } -bool ConvertArrowType(TType* itemType, std::shared_ptr<arrow::DataType>& type); +using TArrowConvertFailedCallback = std::function<void(TType*)>; +bool ConvertArrowType(TType* itemType, std::shared_ptr<arrow::DataType>& type, const TArrowConvertFailedCallback& = {}); bool ConvertArrowType(NUdf::EDataSlot slot, std::shared_ptr<arrow::DataType>& type); template<NUdf::EDataSlot slot> diff --git a/ydb/library/yql/providers/common/arrow_resolve/yql_simple_arrow_resolver.cpp b/ydb/library/yql/providers/common/arrow_resolve/yql_simple_arrow_resolver.cpp index 8376d71f781..0a417ef5d8c 100644 --- a/ydb/library/yql/providers/common/arrow_resolve/yql_simple_arrow_resolver.cpp +++ b/ydb/library/yql/providers/common/arrow_resolve/yql_simple_arrow_resolver.cpp @@ -57,20 +57,41 @@ private: } } - EStatus AreTypesSupported(const TPosition& pos, const TVector<const TTypeAnnotationNode*>& types, TExprContext& ctx) const override { + EStatus AreTypesSupported(const TPosition& pos, const TVector<const TTypeAnnotationNode*>& types, TExprContext& ctx, + const TUnsupportedTypeCallback& onUnsupported = {}) const override + { try { TScopedAlloc alloc(__LOCATION__); TTypeEnvironment env(alloc); TTypeBuilder typeBuilder(env); + + bool allOk = true; + TArrowConvertFailedCallback cb; + if (onUnsupported) { + cb = [&](TType* failed) { + if (failed->IsData()) { + auto slot = static_cast<TDataType*>(failed)->GetDataSlot(); + YQL_ENSURE(slot); + onUnsupported(*slot); + } else { + onUnsupported(NYql::NCommon::ConvertMiniKQLTypeKind(failed)); + } + }; + } + for (const auto& type : types) { + YQL_ENSURE(type); TNullOutput null; auto mkqlType = NCommon::BuildType(*type, typeBuilder, null); std::shared_ptr<arrow::DataType> arrowType; - if (!ConvertArrowType(mkqlType, arrowType)) { - return EStatus::NOT_FOUND; + if (!ConvertArrowType(mkqlType, arrowType, cb)) { + allOk = false; + if (!cb) { + break; + } } } - return EStatus::OK; + return allOk ? EStatus::OK : EStatus::NOT_FOUND; } catch (const std::exception& e) { ctx.AddError(TIssue(pos, e.what())); return EStatus::ERROR; diff --git a/ydb/library/yql/providers/common/mkql/yql_type_mkql.cpp b/ydb/library/yql/providers/common/mkql/yql_type_mkql.cpp index 2d74fc1c55c..0b40b5b339b 100644 --- a/ydb/library/yql/providers/common/mkql/yql_type_mkql.cpp +++ b/ydb/library/yql/providers/common/mkql/yql_type_mkql.cpp @@ -426,5 +426,65 @@ const TTypeAnnotationNode* ConvertMiniKQLType(TPosition position, NKikimr::NMini YQL_ENSURE(false, "Unknown kind"); } +ETypeAnnotationKind ConvertMiniKQLTypeKind(NKikimr::NMiniKQL::TType* type) { + using namespace NKikimr::NMiniKQL; + switch (type->GetKind()) { + case TType::EKind::Type: + return ETypeAnnotationKind::Generic; + case TType::EKind::Void: + return ETypeAnnotationKind::Void; + case TType::EKind::Data: + return ETypeAnnotationKind::Data; + case TType::EKind::Struct: + return ETypeAnnotationKind::Struct; + case TType::EKind::List: + return ETypeAnnotationKind::List; + case TType::EKind::Optional: + return ETypeAnnotationKind::Optional; + case TType::EKind::Dict: + return ETypeAnnotationKind::Dict; + case TType::EKind::Callable: + return ETypeAnnotationKind::Callable; + case TType::EKind::Any: + case TType::EKind::ReservedKind: + YQL_ENSURE(false, "Not supported"); + break; + case TType::EKind::Tuple: + return ETypeAnnotationKind::Tuple; + case TType::EKind::Resource: + return ETypeAnnotationKind::Resource; + case TType::EKind::Stream: + return ETypeAnnotationKind::Stream; + case TType::EKind::Variant: + return ETypeAnnotationKind::Variant; + case TType::EKind::Null: + return ETypeAnnotationKind::Null; + case TType::EKind::EmptyList: + return ETypeAnnotationKind::EmptyList; + case TType::EKind::EmptyDict: + return ETypeAnnotationKind::EmptyDict; + case TType::EKind::Tagged: + return ETypeAnnotationKind::Tagged; + case TType::EKind::Block: + { + auto blockType = static_cast<TBlockType*>(type); + if (blockType->GetShape() == NKikimr::NMiniKQL::TBlockType::EShape::Many) { + return ETypeAnnotationKind::Block; + } else { + return ETypeAnnotationKind::Scalar; + } + } + case TType::EKind::Flow: + return ETypeAnnotationKind::Flow; + case TType::EKind::Pg: + return ETypeAnnotationKind::Pg; + case TType::EKind::Multi: + return ETypeAnnotationKind::Multi; + } + + YQL_ENSURE(false, "Unknown kind"); +} + + } // namespace NCommon } // namespace NYql diff --git a/ydb/library/yql/providers/common/mkql/yql_type_mkql.h b/ydb/library/yql/providers/common/mkql/yql_type_mkql.h index 53c5b1f7be5..a00def3ac80 100644 --- a/ydb/library/yql/providers/common/mkql/yql_type_mkql.h +++ b/ydb/library/yql/providers/common/mkql/yql_type_mkql.h @@ -22,6 +22,7 @@ NKikimr::NMiniKQL::TType* BuildType(TPositionHandle pos, const TTypeAnnotationNo NKikimr::NMiniKQL::TType* BuildType(const TExprNode& owner, const TTypeAnnotationNode& annotation, NKikimr::NMiniKQL::TTypeBuilder& typeBuilder); const TTypeAnnotationNode* ConvertMiniKQLType(TPosition position, NKikimr::NMiniKQL::TType* type, TExprContext& ctx); +ETypeAnnotationKind ConvertMiniKQLTypeKind(NKikimr::NMiniKQL::TType* type); } // namespace NCommon } // namespace NYql diff --git a/ydb/library/yql/tests/common/test_framework/yql_utils.py b/ydb/library/yql/tests/common/test_framework/yql_utils.py index 12d733af861..d19561f9ee8 100644 --- a/ydb/library/yql/tests/common/test_framework/yql_utils.py +++ b/ydb/library/yql/tests/common/test_framework/yql_utils.py @@ -501,6 +501,11 @@ def is_canonize_yt(cfg): return True return False +def is_with_final_result_issues(cfg): + for item in cfg: + if item[0] == 'with_final_result_issues': + return True + return False def skip_test_if_required(cfg): for item in cfg: diff --git a/ydb/library/yql/tests/sql/dq_file.py b/ydb/library/yql/tests/sql/dq_file.py index dbacef45fe2..1e96ae5bb14 100644 --- a/ydb/library/yql/tests/sql/dq_file.py +++ b/ydb/library/yql/tests/sql/dq_file.py @@ -6,7 +6,7 @@ import re import yatest.common from yql_utils import get_supported_providers, yql_binary_path, is_xfail, is_skip_forceblocks, get_param, \ normalize_source_code_path, dump_table_yson, get_gateway_cfg_suffix, do_custom_query_check, normalize_result, \ - stable_result_file, stable_table_file + stable_result_file, stable_table_file, is_with_final_result_issues from utils import get_config, DATA_PATH from file_common import run_file, run_file_no_cache @@ -32,10 +32,16 @@ def run_test(suite, case, cfg, tmpdir, what, yql_http_file_server): if force_blocks and is_skip_forceblocks(config): pytest.skip('skip force blocks requested') + extra_args=["--emulate-yt"] if what == 'Analyze': - (res, tables_res) = run_file_no_cache('dq', suite, case, cfg, config, yql_http_file_server, DQRUN_PATH, extra_args=["--emulate-yt", "--analyze-query", "--optimize"]) + extra_args += ["--analyze-query", "--optimize"] + if is_with_final_result_issues(config): + extra_args += ["--with-final-issues"] + + if what == 'Analyze': + (res, tables_res) = run_file_no_cache('dq', suite, case, cfg, config, yql_http_file_server, DQRUN_PATH, extra_args=extra_args) else: - (res, tables_res) = run_file('dq', suite, case, cfg, config, yql_http_file_server, DQRUN_PATH, extra_args=["--emulate-yt"]) + (res, tables_res) = run_file('dq', suite, case, cfg, config, yql_http_file_server, DQRUN_PATH, extra_args=extra_args) to_canonize = [] diff --git a/ydb/library/yql/tests/sql/dq_file/part5/canondata/result.json b/ydb/library/yql/tests/sql/dq_file/part5/canondata/result.json index f94775c7e3b..54e040cc89a 100644 --- a/ydb/library/yql/tests/sql/dq_file/part5/canondata/result.json +++ b/ydb/library/yql/tests/sql/dq_file/part5/canondata/result.json @@ -711,6 +711,32 @@ } ], "test.test[blocks-sub_uint64_opt2--Results]": [], + "test.test[blocks-type_and_callable_stats--Analyze]": [ + { + "checksum": "ba2a8428a72e0ef51d7f5a825ffd3d1e", + "size": 3705, + "uri": "https://{canondata_backend}/1784117/9a53e0c31670253d78108c8a3b4f81fc219a1c68/resource.tar.gz#test.test_blocks-type_and_callable_stats--Analyze_/plan.txt" + } + ], + "test.test[blocks-type_and_callable_stats--Debug]": [ + { + "checksum": "fea9bf013d4fa84ee9ed1470290a2247", + "size": 2819, + "uri": "https://{canondata_backend}/1689644/40519f669ee0ff4cd14681f4648f099da23d476a/resource.tar.gz#test.test_blocks-type_and_callable_stats--Debug_/opt.yql_patched" + } + ], + "test.test[blocks-type_and_callable_stats--Plan]": [ + { + "checksum": "ba2a8428a72e0ef51d7f5a825ffd3d1e", + "size": 3705, + "uri": "https://{canondata_backend}/1784117/9a53e0c31670253d78108c8a3b4f81fc219a1c68/resource.tar.gz#test.test_blocks-type_and_callable_stats--Plan_/plan.txt" + } + ], + "test.test[blocks-type_and_callable_stats--Results]": [ + { + "uri": "file://test.test_blocks-type_and_callable_stats--Results_/extracted" + } + ], "test.test[coalesce-coalesce_symmetry-default.txt-Analyze]": [ { "checksum": "4d9d7cd78393c759728e69e95aefb913", diff --git a/ydb/library/yql/tests/sql/dq_file/part5/canondata/test.test_blocks-type_and_callable_stats--Results_/extracted b/ydb/library/yql/tests/sql/dq_file/part5/canondata/test.test_blocks-type_and_callable_stats--Results_/extracted new file mode 100644 index 00000000000..4260358aac6 --- /dev/null +++ b/ydb/library/yql/tests/sql/dq_file/part5/canondata/test.test_blocks-type_and_callable_stats--Results_/extracted @@ -0,0 +1,3 @@ +<tmp_path>/program.sql:<main>: Info: Most frequent types which do not support block mode: Dict, DyNumber, List, Void + +<tmp_path>/program.sql:<main>: Info: Most frequent callables which do not support block mode: Re2.Grep, Re2.Match, SafeCast
\ No newline at end of file diff --git a/ydb/library/yql/tests/sql/hybrid_file/part7/canondata/result.json b/ydb/library/yql/tests/sql/hybrid_file/part7/canondata/result.json index 1c19f535b85..3ec49bf3e03 100644 --- a/ydb/library/yql/tests/sql/hybrid_file/part7/canondata/result.json +++ b/ydb/library/yql/tests/sql/hybrid_file/part7/canondata/result.json @@ -741,6 +741,20 @@ "uri": "https://{canondata_backend}/1031349/8b8964a29e1f3930fc799646d4ad2b51c549588e/resource.tar.gz#test.test_blocks-top_sort_one_asc--Plan_/plan.txt" } ], + "test.test[blocks-type_and_callable_stats--Debug]": [ + { + "checksum": "a01ceb9ea4ea544c1a7e54496bffec41", + "size": 3907, + "uri": "https://{canondata_backend}/1031349/61ef6576b4067a10cada6609ae12eda1d03e8ab5/resource.tar.gz#test.test_blocks-type_and_callable_stats--Debug_/opt.yql_patched" + } + ], + "test.test[blocks-type_and_callable_stats--Plan]": [ + { + "checksum": "4f5ebace275ca31a34ca23bdb57a6dc7", + "size": 4074, + "uri": "https://{canondata_backend}/1031349/61ef6576b4067a10cada6609ae12eda1d03e8ab5/resource.tar.gz#test.test_blocks-type_and_callable_stats--Plan_/plan.txt" + } + ], "test.test[coalesce-coalesce_sugar-default.txt-Debug]": [ { "checksum": "f6a160186160453bd01f600884397730", diff --git a/ydb/library/yql/tests/sql/sql2yql/canondata/result.json b/ydb/library/yql/tests/sql/sql2yql/canondata/result.json index 551be78940d..f6980ccf3b4 100644 --- a/ydb/library/yql/tests/sql/sql2yql/canondata/result.json +++ b/ydb/library/yql/tests/sql/sql2yql/canondata/result.json @@ -4262,6 +4262,13 @@ "uri": "https://{canondata_backend}/1889210/525a727248199e4967ca2f854e5235352e3d5482/resource.tar.gz#test_sql2yql.test_blocks-tuple_type_/sql.yql" } ], + "test_sql2yql.test[blocks-type_and_callable_stats]": [ + { + "checksum": "9efa02df55deb6b8dbdca1b440e96fc1", + "size": 2601, + "uri": "https://{canondata_backend}/1937424/7dd37eb1e9f9f10e476a8c866a4f6d9d8a2ae8d2/resource.tar.gz#test_sql2yql.test_blocks-type_and_callable_stats_/sql.yql" + } + ], "test_sql2yql.test[case-case_many_val]": [ { "checksum": "bda507979f30604c929d345df0b011e0", @@ -23708,6 +23715,13 @@ "uri": "https://{canondata_backend}/1889210/525a727248199e4967ca2f854e5235352e3d5482/resource.tar.gz#test_sql_format.test_blocks-tuple_type_/formatted.sql" } ], + "test_sql_format.test[blocks-type_and_callable_stats]": [ + { + "checksum": "0c26e93da59abd323c566a60d42be7c6", + "size": 401, + "uri": "https://{canondata_backend}/1937424/7dd37eb1e9f9f10e476a8c866a4f6d9d8a2ae8d2/resource.tar.gz#test_sql_format.test_blocks-type_and_callable_stats_/formatted.sql" + } + ], "test_sql_format.test[case-case_many_val]": [ { "checksum": "b47f8a0a4b6bdb400396d301c9371805", diff --git a/ydb/library/yql/tests/sql/suites/blocks/type_and_callable_stats.cfg b/ydb/library/yql/tests/sql/suites/blocks/type_and_callable_stats.cfg new file mode 100644 index 00000000000..6a380025730 --- /dev/null +++ b/ydb/library/yql/tests/sql/suites/blocks/type_and_callable_stats.cfg @@ -0,0 +1,4 @@ +with_final_result_issues +in Input input_strings.txt +udf string_udf +udf re2_udf diff --git a/ydb/library/yql/tests/sql/suites/blocks/type_and_callable_stats.sql b/ydb/library/yql/tests/sql/suites/blocks/type_and_callable_stats.sql new file mode 100644 index 00000000000..5357170adb0 --- /dev/null +++ b/ydb/library/yql/tests/sql/suites/blocks/type_and_callable_stats.sql @@ -0,0 +1,16 @@ +pragma BlockEngine='force'; + +USE plato; +$match = Re2::Match(@@\d+@@); +$grep = Re2::Grep('911'); + +SELECT + key, + String::EscapeC(value) as ok1, + $match(key) as no_block_udf1, + $grep(key) as no_block_udf2, + AsList(key) as no_block_list, + AsSet(key) as no_block_set_and_void, + cast(key as Double) as no_block_cast, + AsTuple(key, DyNumber("123")) as no_block_dynumber, +FROM Input; diff --git a/ydb/library/yql/tests/sql/utils.py b/ydb/library/yql/tests/sql/utils.py index f385428abda..aaf62644516 100644 --- a/ydb/library/yql/tests/sql/utils.py +++ b/ydb/library/yql/tests/sql/utils.py @@ -117,6 +117,7 @@ def validate_cfg(result): "canonize_peephole", "canonize_lineage", "peephole_use_blocks", + "with_final_result_issues", "xfail", "pragma", "canonize_yt", diff --git a/ydb/library/yql/tests/sql/yt_file.py b/ydb/library/yql/tests/sql/yt_file.py index b41e66a3146..2ab410f0867 100644 --- a/ydb/library/yql/tests/sql/yt_file.py +++ b/ydb/library/yql/tests/sql/yt_file.py @@ -8,7 +8,7 @@ import yatest.common from yql_utils import execute, get_tables, get_files, get_http_files, \ KSV_ATTR, yql_binary_path, is_xfail, is_canonize_peephole, is_peephole_use_blocks, is_canonize_lineage, \ is_skip_forceblocks, get_param, normalize_source_code_path, replace_vals, get_gateway_cfg_suffix, \ - do_custom_query_check, stable_result_file, stable_table_file + do_custom_query_check, stable_result_file, stable_table_file, is_with_final_result_issues from yqlrun import YQLRun from utils import get_config, get_parameters_json, DATA_PATH @@ -55,7 +55,10 @@ def run_test(suite, case, cfg, tmpdir, what, yql_http_file_server): (res, tables_res) = run_file_no_cache('yt', suite, case, cfg, config, yql_http_file_server, extra_args=['--lineage']) return [yatest.common.canonical_file(res.results_file)] - (res, tables_res) = run_file('yt', suite, case, cfg, config, yql_http_file_server) + extra_final_args = [] + if is_with_final_result_issues(config): + extra_final_args += ['--with-final-issues'] + (res, tables_res) = run_file('yt', suite, case, cfg, config, yql_http_file_server, extra_args=extra_final_args) to_canonize = [] diff --git a/ydb/library/yql/tests/sql/yt_native_file/part5/canondata/result.json b/ydb/library/yql/tests/sql/yt_native_file/part5/canondata/result.json index 2c6162416b1..2b693945837 100644 --- a/ydb/library/yql/tests/sql/yt_native_file/part5/canondata/result.json +++ b/ydb/library/yql/tests/sql/yt_native_file/part5/canondata/result.json @@ -727,6 +727,37 @@ "uri": "https://{canondata_backend}/1817427/0b979af6b2bfa42e752a296b0288b726527203dd/resource.tar.gz#test.test_blocks-sub_uint64_opt2--Results_/results.txt" } ], + "test.test[blocks-type_and_callable_stats--Debug]": [ + { + "checksum": "abf887f971c093b3c766c0d61de9bfa5", + "size": 3140, + "uri": "https://{canondata_backend}/1942278/7c66ffff1df826f3e0283b5718f3b64fef634b24/resource.tar.gz#test.test_blocks-type_and_callable_stats--Debug_/opt.yql" + } + ], + "test.test[blocks-type_and_callable_stats--Peephole]": [ + { + "checksum": "7c4459aaef912df4e3a670d1353db50b", + "size": 3060, + "uri": "https://{canondata_backend}/1942278/7c66ffff1df826f3e0283b5718f3b64fef634b24/resource.tar.gz#test.test_blocks-type_and_callable_stats--Peephole_/opt.yql" + } + ], + "test.test[blocks-type_and_callable_stats--Plan]": [ + { + "checksum": "990c31fd75086073adb260445a1886fa", + "size": 3527, + "uri": "https://{canondata_backend}/1936842/85945930c4a0d22d0dbc35897f90760fc842f68b/resource.tar.gz#test.test_blocks-type_and_callable_stats--Plan_/plan.txt" + } + ], + "test.test[blocks-type_and_callable_stats--Results]": [ + { + "checksum": "d73069afcdb42caedfabf2180cc11bc2", + "size": 10729, + "uri": "https://{canondata_backend}/1942278/7c66ffff1df826f3e0283b5718f3b64fef634b24/resource.tar.gz#test.test_blocks-type_and_callable_stats--Results_/results.txt" + }, + { + "uri": "file://test.test_blocks-type_and_callable_stats--Results_/extracted" + } + ], "test.test[coalesce-coalesce_symmetry-default.txt-Debug]": [ { "checksum": "eaea85a7f97f5d800e13e8d9676a846e", diff --git a/ydb/library/yql/tests/sql/yt_native_file/part5/canondata/test.test_blocks-type_and_callable_stats--Results_/extracted b/ydb/library/yql/tests/sql/yt_native_file/part5/canondata/test.test_blocks-type_and_callable_stats--Results_/extracted new file mode 100644 index 00000000000..4260358aac6 --- /dev/null +++ b/ydb/library/yql/tests/sql/yt_native_file/part5/canondata/test.test_blocks-type_and_callable_stats--Results_/extracted @@ -0,0 +1,3 @@ +<tmp_path>/program.sql:<main>: Info: Most frequent types which do not support block mode: Dict, DyNumber, List, Void + +<tmp_path>/program.sql:<main>: Info: Most frequent callables which do not support block mode: Re2.Grep, Re2.Match, SafeCast
\ No newline at end of file diff --git a/ydb/library/yql/tools/dqrun/dqrun.cpp b/ydb/library/yql/tools/dqrun/dqrun.cpp index 9370779057d..c69af2f6c7c 100644 --- a/ydb/library/yql/tools/dqrun/dqrun.cpp +++ b/ydb/library/yql/tools/dqrun/dqrun.cpp @@ -132,6 +132,7 @@ struct TRunOptions { IOutputStream* ErrStream = &Cerr; IOutputStream* TracePlan = &Cerr; bool UseMetaFromGraph = false; + bool WithFinalIssues = false; }; class TStoreMappingFunctor: public NLastGetopt::IOptHandler { @@ -409,6 +410,9 @@ int RunProgram(TProgramPtr program, const TRunOptions& options, const THashMap<T auto config = TOptPipelineConfigurator(program, options.PrintPlan, options.TracePlan); status = program->RunWithConfig(options.User, config); } + if (options.WithFinalIssues) { + program->FinalizeIssues(); + } program->PrintErrorsTo(*options.ErrStream); if (status == TProgram::TStatus::Error) { if (options.TraceOpt) { @@ -677,6 +681,7 @@ int RunMain(int argc, const char* argv[]) .StoreResult(&tokenAccessorEndpoint); opts.AddLongOption("yson-attrs", "Provide operation yson attribues").StoreResult(&ysonAttrs); opts.AddLongOption("pg-ext", "pg extensions config file").StoreResult(&pgExtConfig); + opts.AddLongOption("with-final-issues").NoArgument(); opts.AddHelpOption('h'); opts.SetFreeArgsNum(0); @@ -1090,6 +1095,10 @@ int RunMain(int argc, const char* argv[]) program->SetOperationAttrsYson(ysonAttrs); } + if (res.Has("with-final-issues")) { + runOptions.WithFinalIssues = true; + } + int result = RunProgram(std::move(program), runOptions, clusters, sqlFlags); if (res.Has("metrics")) { NProto::TMetricsRegistrySnapshot snapshot; diff --git a/ydb/library/yql/tools/yqlrun/http/yql_server.cpp b/ydb/library/yql/tools/yqlrun/http/yql_server.cpp index 7edbd52bd41..357e1c5bc33 100644 --- a/ydb/library/yql/tools/yqlrun/http/yql_server.cpp +++ b/ydb/library/yql/tools/yqlrun/http/yql_server.cpp @@ -442,6 +442,9 @@ YQL_ACTION(OptimizeOrValidateFile) Writer.Write(TStringBuf("opttrace"), traceOut->Str()); } + if (options & TYqlAction::WithFinalIssues) { + prg->FinalizeIssues(); + } WriteStatus(noError, prg->Issues()); } }; @@ -509,6 +512,9 @@ YQL_ACTION(FileRun) Writer.Write(TStringBuf("opttrace"), traceOut->Str()); } + if (options & TYqlAction::WithFinalIssues) { + prg->FinalizeIssues(); + } WriteStatus(status != TProgram::TStatus::Error, prg->Issues()); if (status != TProgram::TStatus::Error) { diff --git a/ydb/library/yql/tools/yqlrun/http/yql_servlet.h b/ydb/library/yql/tools/yqlrun/http/yql_servlet.h index d6e65fa31b4..8ee9b402880 100644 --- a/ydb/library/yql/tools/yqlrun/http/yql_servlet.h +++ b/ydb/library/yql/tools/yqlrun/http/yql_servlet.h @@ -37,6 +37,7 @@ public: PrintAst = 0x0100, PrintExpr = 0x0200, PrintTraceOpt = 0x0400, + WithFinalIssues = 0x0800, }; public: @@ -105,6 +106,7 @@ public: } else if (lang == TStringBuf("sql")) { options |= TYqlAction::SqlProgram; } + options |= TYqlAction::WithFinalIssues; TStringStream output; NJson::TJsonWriter writer(&output, false); diff --git a/ydb/library/yql/tools/yqlrun/yqlrun.cpp b/ydb/library/yql/tools/yqlrun/yqlrun.cpp index 67057b0f096..21c5f337132 100644 --- a/ydb/library/yql/tools/yqlrun/yqlrun.cpp +++ b/ydb/library/yql/tools/yqlrun/yqlrun.cpp @@ -138,6 +138,13 @@ public: out << baseSS.Data(); } + void FinalizeIssues() { + BaseProg->FinalizeIssues(); + for (auto& info : Infos) { + info.Prog->FinalizeIssues(); + } + } + void PrintErrorsTo(IOutputStream& out) const { TStringStream baseSS; BaseProg->PrintErrorsTo(baseSS); @@ -474,6 +481,7 @@ int Main(int argc, const char *argv[]) opts.AddLongOption("test-format", "compare formatted query's AST with the original query's AST (only syntaxVersion=1 is supported)").NoArgument(); opts.AddLongOption("show-kernels", "show all Arrow kernel families").NoArgument(); opts.AddLongOption("pg-ext", "pg extensions config file").StoreResult(&pgExtConfig); + opts.AddLongOption("with-final-issues", "Include some final messages (like statistic) in issues").NoArgument(); opts.SetFreeArgsMax(0); TOptsParseResult res(&opts, argc, argv); @@ -842,6 +850,9 @@ int Main(int argc, const char *argv[]) status = program->Lineage(username, traceOut, exprOut, withTypes); } + if (res.Has("with-final-issues")) { + program->FinalizeIssues(); + } program->PrintErrorsTo(*errStream); if (status == TProgram::TStatus::Error) { return 1; |