diff options
author | vvvv <[email protected]> | 2025-02-20 17:52:55 +0300 |
---|---|---|
committer | vvvv <[email protected]> | 2025-02-20 18:09:50 +0300 |
commit | 85a37e6d028089a8eb1680d5a8d701c58ea48965 (patch) | |
tree | 0d43ed225e659989a021ade01d84aa7329883977 | |
parent | a9b386524b35fd2b5f62cf1fd22a7304120e9cec (diff) |
YQL-19588 early scan for error types
commit_hash:65fc8d62e0b7fa491747980a3a40e14b4742d1bc
6 files changed, 74 insertions, 12 deletions
diff --git a/yql/essentials/ast/yql_expr.h b/yql/essentials/ast/yql_expr.h index a64a2f9aec6..92e6c00e54e 100644 --- a/yql/essentials/ast/yql_expr.h +++ b/yql/essentials/ast/yql_expr.h @@ -178,6 +178,7 @@ enum ETypeAnnotationFlags : ui32 { TypeNonPresortable = 0x1000, TypeHasDynamicSize = 0x2000, TypeNonComparableInternal = 0x4000, + TypeHasError = 0x8000, }; const ui64 TypeHashMagic = 0x10000; @@ -313,6 +314,10 @@ public: return (GetFlags() & TypeNonPresortable) == 0; } + bool HasErrors() const { + return (GetFlags() & TypeHasError) != 0; + } + ui32 GetFlags() const { return Flags; } @@ -1038,7 +1043,7 @@ public: static constexpr ETypeAnnotationKind KindValue = ETypeAnnotationKind::Type; TTypeExprType(ui64 hash, const TTypeAnnotationNode* type) - : TTypeAnnotationNode(KindValue, TypeNonPersistable | TypeNonComputable, hash, 0) + : TTypeAnnotationNode(KindValue, TypeNonPersistable | TypeNonComputable | (type->GetFlags() & TypeHasError), hash, 0) , Type(type) { } @@ -1157,7 +1162,7 @@ public: TCallableExprType(ui64 hash, const TTypeAnnotationNode* returnType, const TVector<TArgumentInfo>& arguments , size_t optionalArgumentsCount, const TStringBuf& payload) - : TTypeAnnotationNode(KindValue, MakeFlags(returnType), hash, returnType->GetUsedPgExtensions()) + : TTypeAnnotationNode(KindValue, MakeFlags(arguments, returnType), hash, returnType->GetUsedPgExtensions()) , ReturnType(returnType) , Arguments(arguments) , OptionalArgumentsCount(optionalArgumentsCount) @@ -1244,9 +1249,13 @@ public: } private: - static ui32 MakeFlags(const TTypeAnnotationNode* returnType) { + static ui32 MakeFlags(const TVector<TArgumentInfo>& arguments, const TTypeAnnotationNode* returnType) { ui32 flags = TypeNonPersistable; flags |= returnType->GetFlags(); + for (const auto& arg : arguments) { + flags |= (arg.Type->GetFlags() & TypeHasError); + } + return flags; } @@ -1346,7 +1355,7 @@ public: static constexpr ETypeAnnotationKind KindValue = ETypeAnnotationKind::Error; TErrorExprType(ui64 hash, const TIssue& error) - : TTypeAnnotationNode(KindValue, 0, hash, 0) + : TTypeAnnotationNode(KindValue, TypeHasError, hash, 0) , Error(error) {} diff --git a/yql/essentials/core/common_opt/yql_co_transformer.cpp b/yql/essentials/core/common_opt/yql_co_transformer.cpp index d589e168e5e..52b454a5af0 100644 --- a/yql/essentials/core/common_opt/yql_co_transformer.cpp +++ b/yql/essentials/core/common_opt/yql_co_transformer.cpp @@ -34,10 +34,14 @@ private: IGraphTransformer::TStatus DoTransform(const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx, const TFinalizingOptimizerMap& callables); + bool ScanErrors(const TExprNode& node, TExprContext& ctx); + private: TProcessedNodesSet SimpleProcessedNodes[TCoCallableRules::SIMPLE_STEPS]; TProcessedNodesSet FlowProcessedNodes[TCoCallableRules::FLOW_STEPS]; TProcessedNodesSet FinalProcessedNodes; + TProcessedNodesSet ErrorProcessedNodes; + THashSet<TIssue> AddedErrors; TTypeAnnotationContext* TypeCtx; const bool Final; }; @@ -79,10 +83,16 @@ IGraphTransformer::TStatus TCommonOptTransformer::DoTransform(TExprNode::TPtr in return status; } - return status; + if (!ScanErrors(*output, ctx)) { + return IGraphTransformer::TStatus::Error; + } + + return IGraphTransformer::TStatus::Ok; } void TCommonOptTransformer::Rewind() { + AddedErrors.clear(); + ErrorProcessedNodes.clear(); FinalProcessedNodes.clear(); for (auto& set : FlowProcessedNodes) { @@ -94,6 +104,30 @@ void TCommonOptTransformer::Rewind() { } } +bool TCommonOptTransformer::ScanErrors(const TExprNode& node, TExprContext& ctx) { + auto [it, inserted] = ErrorProcessedNodes.emplace(node.UniqueId()); + if (!inserted) { + return true; + } + + for (const auto& child : node.Children()) { + if (!ScanErrors(*child, ctx)) { + return false; + } + } + + if (!node.IsCallable("ErrorType")) { + return true; + } + + auto issue = node.GetTypeAnn()->Cast<TTypeExprType>()->GetType()->Cast<TErrorExprType>()->GetError(); + if (AddedErrors.insert(issue).second) { + ctx.AddError(issue); + } + + return false; +} + IGraphTransformer::TStatus TCommonOptTransformer::DoTransform( const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx, const TCallableOptimizerMap& callables, diff --git a/yql/essentials/core/services/yql_transform_pipeline.cpp b/yql/essentials/core/services/yql_transform_pipeline.cpp index 5f7165c10df..2dd8f2c2787 100644 --- a/yql/essentials/core/services/yql_transform_pipeline.cpp +++ b/yql/essentials/core/services/yql_transform_pipeline.cpp @@ -200,7 +200,6 @@ TTransformationPipeline& TTransformationPipeline::AddOptimization(bool checkWorl TTransformationPipeline& TTransformationPipeline::AddLineageOptimization(TMaybe<TString>& lineageOut, EYqlIssueCode issueCode) { AddCommonOptimization(issueCode); - AddCheckExecution(false, issueCode); Transformers_.push_back(TTransformStage( CreateFunctorTransformer( [typeCtx = TypeAnnotationContext_, &lineageOut](const TExprNode::TPtr& input, TExprNode::TPtr& output, TExprContext& ctx) { diff --git a/yql/essentials/providers/common/udf_resolve/yql_simple_udf_resolver.cpp b/yql/essentials/providers/common/udf_resolve/yql_simple_udf_resolver.cpp index 0dbc7ce4d26..f85050b5644 100644 --- a/yql/essentials/providers/common/udf_resolve/yql_simple_udf_resolver.cpp +++ b/yql/essentials/providers/common/udf_resolve/yql_simple_udf_resolver.cpp @@ -178,12 +178,14 @@ bool LoadFunctionsMetadata(const TVector<IUdfResolver::TFunction*>& functions, try { TType* mkqlUserType = nullptr; if (udf.UserType) { - // scan for error types - TErrorTypeVisitor errorVisitor(ctx); - udf.UserType->Accept(errorVisitor); - if (errorVisitor.HasErrors()) { - hasErrors = true; - continue; + if (udf.UserType->HasErrors()) { + // scan for error types + TErrorTypeVisitor errorVisitor(ctx); + udf.UserType->Accept(errorVisitor); + if (errorVisitor.HasErrors()) { + hasErrors = true; + continue; + } } TStringStream err; diff --git a/yt/yql/tests/sql/suites/aggregate/error_type.cfg b/yt/yql/tests/sql/suites/aggregate/error_type.cfg new file mode 100644 index 00000000000..83cfd96179a --- /dev/null +++ b/yt/yql/tests/sql/suites/aggregate/error_type.cfg @@ -0,0 +1,2 @@ +xfail + diff --git a/yt/yql/tests/sql/suites/aggregate/error_type.sql b/yt/yql/tests/sql/suites/aggregate/error_type.sql new file mode 100644 index 00000000000..a0e54ef444c --- /dev/null +++ b/yt/yql/tests/sql/suites/aggregate/error_type.sql @@ -0,0 +1,16 @@ +/* custom error: Uncompatible member x types: Int32 and String */ +use plato; + +insert into @foo +select 1 as x; + +insert into @bar +select 'z' as x; + +commit; + +select * from @foo +union +select * from @bar; + + |