From 256404a14d4e72a39585ed6e5cb8fd1ffbe14d1b Mon Sep 17 00:00:00 2001 From: Gigoriy Pisarenko Date: Fri, 26 Jan 2024 16:27:40 +0000 Subject: [PATCH 1/4] Show ast on case of compilation error --- .../kqp/compile_service/kqp_compile_actor.cpp | 26 ++++++++++++------- ydb/core/kqp/host/kqp_host.cpp | 11 ++++++++ ydb/core/kqp/host/kqp_host_impl.h | 6 ++++- .../kqp/session_actor/kqp_session_actor.cpp | 15 ++++++++--- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/ydb/core/kqp/compile_service/kqp_compile_actor.cpp b/ydb/core/kqp/compile_service/kqp_compile_actor.cpp index 283c6a2cde88..b4f674238d56 100644 --- a/ydb/core/kqp/compile_service/kqp_compile_actor.cpp +++ b/ydb/core/kqp/compile_service/kqp_compile_actor.cpp @@ -372,6 +372,14 @@ class TKqpCompileActor : public TActorBootstrapped { PassAway(); } + void FillPreparedQuery(std::unique_ptr preparingQuery, NKikimrKqp::EQueryType queryType) { + auto preparedQueryHolder = std::make_shared( + preparingQuery.release(), AppData()->FunctionRegistry); + preparedQueryHolder->MutableLlvmSettings().Fill(Config, queryType); + KqpCompileResult->PreparedQuery = preparedQueryHolder; + KqpCompileResult->AllowCache = CanCacheQuery(KqpCompileResult->PreparedQuery->GetPhysicalQuery()); + } + void Handle(TEvKqp::TEvContinueProcess::TPtr &ev, const TActorContext &ctx) { Y_ENSURE(!ev->Get()->QueryId); @@ -403,16 +411,10 @@ class TKqpCompileActor : public TActorBootstrapped { if (status == Ydb::StatusIds::SUCCESS) { YQL_ENSURE(kqpResult.PreparingQuery); - { - auto preparedQueryHolder = std::make_shared( - kqpResult.PreparingQuery.release(), AppData()->FunctionRegistry); - preparedQueryHolder->MutableLlvmSettings().Fill(Config, queryType); - KqpCompileResult->PreparedQuery = preparedQueryHolder; - KqpCompileResult->AllowCache = CanCacheQuery(KqpCompileResult->PreparedQuery->GetPhysicalQuery()); - - if (AstResult) { - KqpCompileResult->Ast = AstResult->Ast; - } + FillPreparedQuery(std::move(kqpResult.PreparingQuery), queryType); + + if (AstResult) { + KqpCompileResult->Ast = AstResult->Ast; } auto now = TInstant::Now(); @@ -423,6 +425,10 @@ class TKqpCompileActor : public TActorBootstrapped { << ", self: " << ctx.SelfID << ", duration: " << duration); } else { + if (kqpResult.PreparingQuery) { + FillPreparedQuery(std::move(kqpResult.PreparingQuery), queryType); + } + LOG_ERROR_S(ctx, NKikimrServices::KQP_COMPILE_ACTOR, "Compilation failed" << ", self: " << ctx.SelfID << ", status: " << Ydb::StatusIds_StatusCode_Name(status) diff --git a/ydb/core/kqp/host/kqp_host.cpp b/ydb/core/kqp/host/kqp_host.cpp index 750fe8120dbc..b2118473ad70 100644 --- a/ydb/core/kqp/host/kqp_host.cpp +++ b/ydb/core/kqp/host/kqp_host.cpp @@ -323,6 +323,7 @@ class TAsyncPrepareYqlResult : public TKqpAsyncResultBase queryCtx, const TKqpQueryRef& query, TMaybe sqlVersion) : TKqpAsyncResultBase(queryRoot, exprCtx, transformer) , QueryCtx(queryCtx) + , ExprCtx(exprCtx) , QueryText(query.Text) , SqlVersion(sqlVersion) {} @@ -342,8 +343,18 @@ class TAsyncPrepareYqlResult : public TKqpAsyncResultBaseGetPhysicalQuery().GetQueryAst(); } + void FillPartialResult(TResult& prepareResult) const override { + YQL_ENSURE(QueryCtx->PrepareOnly); + + if (auto exprRoot = GetExprRoot()) { + prepareResult.PreparingQuery = std::move(QueryCtx->PreparingQuery); + prepareResult.PreparingQuery->MutablePhysicalQuery()->SetQueryAst(KqpExprToPrettyString(*GetExprRoot(), ExprCtx)); + } + } + private: TIntrusivePtr QueryCtx; + NYql::TExprContext& ExprCtx; TString QueryText; TMaybe SqlVersion; }; diff --git a/ydb/core/kqp/host/kqp_host_impl.h b/ydb/core/kqp/host/kqp_host_impl.h index 550f9e2776d3..2837b818eeba 100644 --- a/ydb/core/kqp/host/kqp_host_impl.h +++ b/ydb/core/kqp/host/kqp_host_impl.h @@ -34,7 +34,9 @@ class TKqpAsyncResultBase : public NYql::IKikimrAsyncResult { YQL_ENSURE(HasResult()); if (Status.GetValue() == NYql::IGraphTransformer::TStatus::Error) { - return NYql::NCommon::ResultFromErrors(ExprCtx.IssueManager.GetIssues()); + TResult result = NYql::NCommon::ResultFromErrors(ExprCtx.IssueManager.GetIssues()); + FillPartialResult(result); + return result; } YQL_ENSURE(Status.GetValue() == NYql::IGraphTransformer::TStatus::Ok); @@ -83,6 +85,8 @@ class TKqpAsyncResultBase : public NYql::IKikimrAsyncResult { protected: virtual void FillResult(TResult& result) const = 0; + virtual void FillPartialResult(TResult&) const {} + NYql::TExprNode::TPtr GetExprRoot() const { return ExprRoot; } NYql::TExprContext& GetExprContext() const { return ExprCtx; } NYql::IGraphTransformer& GetTransformer() const { return Transformer; } diff --git a/ydb/core/kqp/session_actor/kqp_session_actor.cpp b/ydb/core/kqp/session_actor/kqp_session_actor.cpp index 00bb19061486..91f2e1be4fe1 100644 --- a/ydb/core/kqp/session_actor/kqp_session_actor.cpp +++ b/ydb/core/kqp/session_actor/kqp_session_actor.cpp @@ -1720,10 +1720,17 @@ class TKqpSessionActor : public TActorBootstrapped { const auto& phyQuery = QueryState->PreparedQuery->GetPhysicalQuery(); FillColumnsMeta(phyQuery, response); - } else if (compileResult->Status == Ydb::StatusIds::TIMEOUT && QueryState->QueryDeadlines.CancelAt) { - // The compile timeout cause cancelation execution of request. - // So in case of cancel after we can reply with canceled status - ev.SetYdbStatus(Ydb::StatusIds::CANCELLED); + } else { + if (compileResult->Status == Ydb::StatusIds::TIMEOUT && QueryState->QueryDeadlines.CancelAt) { + // The compile timeout cause cancelation execution of request. + // So in case of cancel after we can reply with canceled status + ev.SetYdbStatus(Ydb::StatusIds::CANCELLED); + } + + auto& preparedQuery = compileResult->PreparedQuery; + if (preparedQuery && QueryState->ReportStats() && QueryState->GetStatsMode() >= Ydb::Table::QueryStatsCollection::STATS_COLLECTION_FULL) { + response.SetQueryAst(preparedQuery->GetPhysicalQuery().GetQueryAst()); + } } } From 889af336103296f01fc975c1dac5e7723bc720f1 Mon Sep 17 00:00:00 2001 From: Gigoriy Pisarenko Date: Mon, 29 Jan 2024 07:15:47 +0000 Subject: [PATCH 2/4] Added integration tests --- ydb/tests/fq/s3/test_bindings.py | 33 +++++++++++++++++++++++++++++++ ydb/tests/fq/yds/test_select_1.py | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/ydb/tests/fq/s3/test_bindings.py b/ydb/tests/fq/s3/test_bindings.py index 9c7ce151bdde..4e4373bd5a6d 100644 --- a/ydb/tests/fq/s3/test_bindings.py +++ b/ydb/tests/fq/s3/test_bindings.py @@ -586,3 +586,36 @@ def test_count_for_pg_binding(self, kikimr, s3, client, pg_syntax): else: assert result_set.columns[0].type.type_id == ydb.Type.UINT64 assert result_set.rows[0].items[0].uint64_value == 1 + + @yq_all + @pytest.mark.parametrize("client", [{"folder_id": "my_folder"}], indirect=True) + def test_ast_in_failed_query_compilation(self, kikimr, s3, client): + resource = boto3.resource( + "s3", + endpoint_url=s3.s3_url, + aws_access_key_id="key", + aws_secret_access_key="secret_key" + ) + + bucket = resource.Bucket("bindbucket") + bucket.create(ACL='public-read') + bucket.objects.all().delete() + + connection_id = client.create_storage_connection("bb", "bindbucket").result.connection_id + + data_column = ydb.Column(name="data", type=ydb.Type(type_id=ydb.Type.PrimitiveTypeId.STRING)) + client.create_object_storage_binding(name="s3binding", + path="/", + format="raw", + connection_id=connection_id, + columns=[data_column]) + + sql = R''' + SELECT some_unknown_column FROM bindings.`s3binding`; + ''' + + query_id = client.create_query("simple", sql, type=fq.QueryContent.QueryType.ANALYTICS).result.query_id + client.wait_query_status(query_id, fq.QueryMeta.FAILED) + + ast = str(client.describe_query(query_id).result.query.ast) + assert ast != "", "Query ast not found" diff --git a/ydb/tests/fq/yds/test_select_1.py b/ydb/tests/fq/yds/test_select_1.py index 6c43b72ffae4..a08fbac2c9aa 100644 --- a/ydb/tests/fq/yds/test_select_1.py +++ b/ydb/tests/fq/yds/test_select_1.py @@ -120,7 +120,7 @@ def test_compile_error(self, client, yq_version): assert "Failed to parse query" in describe_string, describe_string @yq_all - def test_ast_in_failed_query(self, client): + def test_ast_in_failed_query_runtime(self, client): sql = "SELECT unwrap(1 / 0)" query_id = client.create_query("simple", sql, type=fq.QueryContent.QueryType.ANALYTICS).result.query_id From 1c43fc53159cfcf70a517a4f2b8f902082bec3a9 Mon Sep 17 00:00:00 2001 From: Gigoriy Pisarenko Date: Mon, 5 Feb 2024 09:18:16 +0000 Subject: [PATCH 3/4] Fixed issues #1 --- .../kqp/compile_service/kqp_compile_actor.cpp | 14 +++--- ydb/core/kqp/host/kqp_host.cpp | 46 ++++++++++++++----- ydb/core/kqp/host/kqp_host_impl.h | 6 +-- ydb/core/kqp/host/kqp_runner.cpp | 8 ++-- ydb/tests/fq/s3/test_bindings.py | 5 +- ydb/tests/fq/yds/test_select_1.py | 7 +-- 6 files changed, 54 insertions(+), 32 deletions(-) diff --git a/ydb/core/kqp/compile_service/kqp_compile_actor.cpp b/ydb/core/kqp/compile_service/kqp_compile_actor.cpp index b4f674238d56..29fa1de3bf9f 100644 --- a/ydb/core/kqp/compile_service/kqp_compile_actor.cpp +++ b/ydb/core/kqp/compile_service/kqp_compile_actor.cpp @@ -372,12 +372,16 @@ class TKqpCompileActor : public TActorBootstrapped { PassAway(); } - void FillPreparedQuery(std::unique_ptr preparingQuery, NKikimrKqp::EQueryType queryType) { + void FillCompileResult(std::unique_ptr preparingQuery, NKikimrKqp::EQueryType queryType) { auto preparedQueryHolder = std::make_shared( preparingQuery.release(), AppData()->FunctionRegistry); preparedQueryHolder->MutableLlvmSettings().Fill(Config, queryType); KqpCompileResult->PreparedQuery = preparedQueryHolder; KqpCompileResult->AllowCache = CanCacheQuery(KqpCompileResult->PreparedQuery->GetPhysicalQuery()); + + if (AstResult) { + KqpCompileResult->Ast = AstResult->Ast; + } } void Handle(TEvKqp::TEvContinueProcess::TPtr &ev, const TActorContext &ctx) { @@ -411,11 +415,7 @@ class TKqpCompileActor : public TActorBootstrapped { if (status == Ydb::StatusIds::SUCCESS) { YQL_ENSURE(kqpResult.PreparingQuery); - FillPreparedQuery(std::move(kqpResult.PreparingQuery), queryType); - - if (AstResult) { - KqpCompileResult->Ast = AstResult->Ast; - } + FillCompileResult(std::move(kqpResult.PreparingQuery), queryType); auto now = TInstant::Now(); auto duration = now - StartTime; @@ -426,7 +426,7 @@ class TKqpCompileActor : public TActorBootstrapped { << ", duration: " << duration); } else { if (kqpResult.PreparingQuery) { - FillPreparedQuery(std::move(kqpResult.PreparingQuery), queryType); + FillCompileResult(std::move(kqpResult.PreparingQuery), queryType); } LOG_ERROR_S(ctx, NKikimrServices::KQP_COMPILE_ACTOR, "Compilation failed" diff --git a/ydb/core/kqp/host/kqp_host.cpp b/ydb/core/kqp/host/kqp_host.cpp index b2118473ad70..20cb0133deef 100644 --- a/ydb/core/kqp/host/kqp_host.cpp +++ b/ydb/core/kqp/host/kqp_host.cpp @@ -182,6 +182,10 @@ class TAsyncValidateYqlResult : public TKqpAsyncResultBaseQuery().PrepareOnly); validateResult.PreparedQuery.reset(SessionCtx->Query().PreparingQuery.release()); validateResult.SqlVersion = SqlVersion; @@ -211,6 +215,10 @@ class TAsyncExplainYqlResult : public TKqpAsyncResultBase plans; for (auto id : SessionCtx->Query().ExecutionOrder) { @@ -253,6 +261,10 @@ class TAsyncExecuteYqlResult : public TKqpAsyncResultBase(queryResult.ProtobufArenaPtr.get())); @@ -300,6 +312,10 @@ class TAsyncExecuteKqlResult : public TKqpAsyncResultBaseGetPhysicalQuery().GetQueryPlan(); @@ -320,14 +336,24 @@ class TAsyncPrepareYqlResult : public TKqpAsyncResultBase queryCtx, const TKqpQueryRef& query, TMaybe sqlVersion) + TIntrusivePtr queryCtx, const TKqpQueryRef& query, TMaybe sqlVersion, + TIntrusivePtr transformCtx = nullptr) : TKqpAsyncResultBase(queryRoot, exprCtx, transformer) , QueryCtx(queryCtx) , ExprCtx(exprCtx) + , TransformCtx(transformCtx) , QueryText(query.Text) , SqlVersion(sqlVersion) {} void FillResult(TResult& prepareResult) const override { + if (!prepareResult.Success() && TransformCtx) { + if (auto exprRoot = TransformCtx->ExplainTransformerInput ? TransformCtx->ExplainTransformerInput : GetExprRoot()) { + prepareResult.PreparingQuery = std::move(QueryCtx->PreparingQuery); + prepareResult.PreparingQuery->MutablePhysicalQuery()->SetQueryAst(KqpExprToPrettyString(*GetExprRoot(), ExprCtx)); + } + return; + } + YQL_ENSURE(QueryCtx->PrepareOnly); YQL_ENSURE(QueryCtx->PreparingQuery); @@ -343,18 +369,10 @@ class TAsyncPrepareYqlResult : public TKqpAsyncResultBaseGetPhysicalQuery().GetQueryAst(); } - void FillPartialResult(TResult& prepareResult) const override { - YQL_ENSURE(QueryCtx->PrepareOnly); - - if (auto exprRoot = GetExprRoot()) { - prepareResult.PreparingQuery = std::move(QueryCtx->PreparingQuery); - prepareResult.PreparingQuery->MutablePhysicalQuery()->SetQueryAst(KqpExprToPrettyString(*GetExprRoot(), ExprCtx)); - } - } - private: TIntrusivePtr QueryCtx; NYql::TExprContext& ExprCtx; + TIntrusivePtr TransformCtx; TString QueryText; TMaybe SqlVersion; }; @@ -944,6 +962,7 @@ class TKqpHost : public IKqpHost { , IsInternalCall(isInternalCall) , FederatedQuerySetup(federatedQuerySetup) , SessionCtx(new TKikimrSessionContext(funcRegistry, config, TAppData::TimeProvider, TAppData::RandomProvider, userToken)) + , Config(config) , TypesCtx(MakeIntrusive()) , PlanBuilder(CreatePlanBuilder(*TypesCtx)) , FakeWorld(ExprCtx->NewWorld(TPosition())) @@ -1338,7 +1357,7 @@ class TKqpHost : public IKqpHost { } return MakeIntrusive(queryExpr.Get(), ctx, *YqlTransformer, SessionCtx->QueryPtr(), - query.Text, sqlVersion); + query.Text, sqlVersion, TransformCtx); } IAsyncQueryResultPtr PrepareScanQueryInternal(const TKqpQueryRef& query, bool isSql, TExprContext& ctx, @@ -1513,7 +1532,8 @@ class TKqpHost : public IKqpHost { } void Init(EKikimrQueryType queryType) { - KqpRunner = CreateKqpRunner(Gateway, Cluster, TypesCtx, SessionCtx, *FuncRegistry); + TransformCtx = MakeIntrusive(Config, SessionCtx->QueryPtr(), SessionCtx->TablesPtr()); + KqpRunner = CreateKqpRunner(Gateway, Cluster, TypesCtx, SessionCtx, TransformCtx, *FuncRegistry); ExprCtx->NodesAllocationLimit = SessionCtx->Config()._KqpExprNodesAllocationLimit.Get().GetRef(); ExprCtx->StringsAllocationLimit = SessionCtx->Config()._KqpExprStringsAllocationLimit.Get().GetRef(); @@ -1646,6 +1666,7 @@ class TKqpHost : public IKqpHost { std::optional FederatedQuerySetup; TIntrusivePtr SessionCtx; + TKikimrConfiguration::TPtr Config; TIntrusivePtr FuncRegistryHolder; const NKikimr::NMiniKQL::IFunctionRegistry* FuncRegistry; @@ -1659,6 +1680,7 @@ class TKqpHost : public IKqpHost { TExprNode::TPtr FakeWorld; TIntrusivePtr ExecuteCtx; + TIntrusivePtr TransformCtx; TIntrusivePtr KqpRunner; NExternalSource::IExternalSourceFactory::TPtr ExternalSourceFactory{NExternalSource::CreateExternalSourceFactory({})}; diff --git a/ydb/core/kqp/host/kqp_host_impl.h b/ydb/core/kqp/host/kqp_host_impl.h index 2837b818eeba..17110a986926 100644 --- a/ydb/core/kqp/host/kqp_host_impl.h +++ b/ydb/core/kqp/host/kqp_host_impl.h @@ -35,7 +35,7 @@ class TKqpAsyncResultBase : public NYql::IKikimrAsyncResult { if (Status.GetValue() == NYql::IGraphTransformer::TStatus::Error) { TResult result = NYql::NCommon::ResultFromErrors(ExprCtx.IssueManager.GetIssues()); - FillPartialResult(result); + FillResult(result); return result; } @@ -85,8 +85,6 @@ class TKqpAsyncResultBase : public NYql::IKikimrAsyncResult { protected: virtual void FillResult(TResult& result) const = 0; - virtual void FillPartialResult(TResult&) const {} - NYql::TExprNode::TPtr GetExprRoot() const { return ExprRoot; } NYql::TExprContext& GetExprContext() const { return ExprCtx; } NYql::IGraphTransformer& GetTransformer() const { return Transformer; } @@ -248,7 +246,7 @@ class IKqpRunner : public TThrRefBase { TIntrusivePtr CreateKqpRunner(TIntrusivePtr gateway, const TString& cluster, const TIntrusivePtr& typesCtx, const TIntrusivePtr& sessionCtx, - const NMiniKQL::IFunctionRegistry& funcRegistry); + const TIntrusivePtr& transformCtx, const NMiniKQL::IFunctionRegistry& funcRegistry); TAutoPtr CreateKqpExplainPreparedTransformer(TIntrusivePtr gateway, const TString& cluster, TIntrusivePtr transformCtx, const NMiniKQL::IFunctionRegistry* funcRegistry, diff --git a/ydb/core/kqp/host/kqp_runner.cpp b/ydb/core/kqp/host/kqp_runner.cpp index 6e0d9b7f98bc..8e113670b9ca 100644 --- a/ydb/core/kqp/host/kqp_runner.cpp +++ b/ydb/core/kqp/host/kqp_runner.cpp @@ -137,14 +137,14 @@ class TKqpRunner : public IKqpRunner { public: TKqpRunner(TIntrusivePtr gateway, const TString& cluster, const TIntrusivePtr& typesCtx, const TIntrusivePtr& sessionCtx, - const NMiniKQL::IFunctionRegistry& funcRegistry) + const TIntrusivePtr& transformCtx, const NMiniKQL::IFunctionRegistry& funcRegistry) : Gateway(gateway) , Cluster(cluster) , TypesCtx(*typesCtx) , SessionCtx(sessionCtx) , FunctionRegistry(funcRegistry) , Config(sessionCtx->ConfigPtr()) - , TransformCtx(MakeIntrusive(Config, sessionCtx->QueryPtr(), sessionCtx->TablesPtr())) + , TransformCtx(transformCtx) , OptimizeCtx(MakeIntrusive(cluster, Config, sessionCtx->QueryPtr(), sessionCtx->TablesPtr())) , BuildQueryCtx(MakeIntrusive()) @@ -377,9 +377,9 @@ class TKqpRunner : public IKqpRunner { TIntrusivePtr CreateKqpRunner(TIntrusivePtr gateway, const TString& cluster, const TIntrusivePtr& typesCtx, const TIntrusivePtr& sessionCtx, - const NMiniKQL::IFunctionRegistry& funcRegistry) + const TIntrusivePtr& transformCtx, const NMiniKQL::IFunctionRegistry& funcRegistry) { - return new TKqpRunner(gateway, cluster, typesCtx, sessionCtx, funcRegistry); + return new TKqpRunner(gateway, cluster, typesCtx, sessionCtx, transformCtx, funcRegistry); } } // namespace NKqp diff --git a/ydb/tests/fq/s3/test_bindings.py b/ydb/tests/fq/s3/test_bindings.py index 4e4373bd5a6d..3cc4cb2cfdea 100644 --- a/ydb/tests/fq/s3/test_bindings.py +++ b/ydb/tests/fq/s3/test_bindings.py @@ -4,6 +4,7 @@ import boto3 import logging import pytest +import sys import ydb.public.api.protos.ydb_value_pb2 as ydb import ydb.public.api.protos.draft.fq_pb2 as fq @@ -617,5 +618,5 @@ def test_ast_in_failed_query_compilation(self, kikimr, s3, client): query_id = client.create_query("simple", sql, type=fq.QueryContent.QueryType.ANALYTICS).result.query_id client.wait_query_status(query_id, fq.QueryMeta.FAILED) - ast = str(client.describe_query(query_id).result.query.ast) - assert ast != "", "Query ast not found" + ast = client.describe_query(query_id).result.query.ast.data + assert "(\'columns \'(\'\"some_unknown_column\"))" in ast, "Invalid query ast" diff --git a/ydb/tests/fq/yds/test_select_1.py b/ydb/tests/fq/yds/test_select_1.py index a08fbac2c9aa..d3b03bb9359d 100644 --- a/ydb/tests/fq/yds/test_select_1.py +++ b/ydb/tests/fq/yds/test_select_1.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- import logging +import sys from ydb.tests.tools.fq_runner.kikimr_utils import yq_v1, yq_all @@ -121,10 +122,10 @@ def test_compile_error(self, client, yq_version): @yq_all def test_ast_in_failed_query_runtime(self, client): - sql = "SELECT unwrap(1 / 0)" + sql = "SELECT unwrap(42 / 0) AS error_column" query_id = client.create_query("simple", sql, type=fq.QueryContent.QueryType.ANALYTICS).result.query_id client.wait_query_status(query_id, fq.QueryMeta.FAILED) - ast = str(client.describe_query(query_id).result.query.ast) - assert ast != "", "Query ast not found" + ast = client.describe_query(query_id).result.query.ast.data + assert "(\'\"error_column\" (Unwrap (/ (Int32 \'\"42\")" in ast, "Invalid query ast" From b67f7faa17fda0092b678c6e2abfd5291d31f420 Mon Sep 17 00:00:00 2001 From: Gigoriy Pisarenko Date: Mon, 5 Feb 2024 09:20:46 +0000 Subject: [PATCH 4/4] Removed unused import --- ydb/tests/fq/s3/test_bindings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ydb/tests/fq/s3/test_bindings.py b/ydb/tests/fq/s3/test_bindings.py index 3cc4cb2cfdea..f3e7f21b5fbb 100644 --- a/ydb/tests/fq/s3/test_bindings.py +++ b/ydb/tests/fq/s3/test_bindings.py @@ -4,7 +4,6 @@ import boto3 import logging import pytest -import sys import ydb.public.api.protos.ydb_value_pb2 as ydb import ydb.public.api.protos.draft.fq_pb2 as fq