diff --git a/ydb/core/grpc_services/query/rpc_execute_query.cpp b/ydb/core/grpc_services/query/rpc_execute_query.cpp index 004eddf5019e..1b02068bc15e 100644 --- a/ydb/core/grpc_services/query/rpc_execute_query.cpp +++ b/ydb/core/grpc_services/query/rpc_execute_query.cpp @@ -264,6 +264,8 @@ class TExecuteQueryRPC : public TActorBootstrapped { .SetSupportStreamTrailingResult(true) .SetOutputChunkMaxSize(req->response_part_limit_bytes()); + assert(req->Getcollect_full_diagnostics()); + auto ev = MakeHolder( QueryAction, queryType, @@ -278,7 +280,8 @@ class TExecuteQueryRPC : public TActorBootstrapped { cachePolicy, nullptr, // operationParams settings, - req->pool_id()); + req->pool_id(), + req->Getcollect_full_diagnostics()); if (!ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), ev.Release(), 0, 0, Span_.GetTraceId())) { NYql::TIssues issues; @@ -396,6 +399,8 @@ class TExecuteQueryRPC : public TActorBootstrapped { hasTrailingMessage = true; response.mutable_tx_meta()->set_id(kqpResponse.GetTxMeta().id()); } + assert(!kqpResponse.GetQueryDiagnostics().empty()); + response.set_query_full_diagnostics(kqpResponse.GetQueryDiagnostics()); } if (hasTrailingMessage) { diff --git a/ydb/core/grpc_services/rpc_execute_data_query.cpp b/ydb/core/grpc_services/rpc_execute_data_query.cpp index bc576098cb91..e88e12f60b23 100644 --- a/ydb/core/grpc_services/rpc_execute_data_query.cpp +++ b/ydb/core/grpc_services/rpc_execute_data_query.cpp @@ -145,7 +145,10 @@ class TExecuteDataQueryRPC : public TRpcKqpRequestActorparameters(), req->collect_stats(), req->has_query_cache_policy() ? &req->query_cache_policy() : nullptr, - req->has_operation_params() ? &req->operation_params() : nullptr); + req->has_operation_params() ? &req->operation_params() : nullptr, + NKqp::NPrivateEvents::TQueryRequestSettings(), + "", + req->Getcollect_full_diagnostics()); ReportCostInfo_ = req->operation_params().report_cost_info() == Ydb::FeatureFlag::ENABLED; @@ -203,6 +206,7 @@ class TExecuteDataQueryRPC : public TRpcKqpRequestActorinsert({queryParameter.GetName(), parameterType}); } } + queryResult->set_query_full_diagnostics(kqpResponse.GetQueryDiagnostics()); } catch (const std::exception& ex) { NYql::TIssues issues; issues.AddIssue(NYql::ExceptionToIssue(ex)); diff --git a/ydb/core/kqp/common/events/query.h b/ydb/core/kqp/common/events/query.h index 19aad90211f2..a246a4a0d939 100644 --- a/ydb/core/kqp/common/events/query.h +++ b/ydb/core/kqp/common/events/query.h @@ -68,7 +68,8 @@ struct TEvQueryRequest: public NActors::TEventLocalSetUsePublicResponseDataFormat(true); @@ -395,6 +396,7 @@ struct TEvQueryRequest: public NActors::TEventLocal UserRequestContext; TDuration ProgressStatsPeriod; std::optional PoolConfig; + bool CollectFullDiagnostics = false; }; struct TEvDataQueryStreamPart: public TEventPBGetDatabaseName().GetOrElse(""))) @@ -35,6 +36,7 @@ TEvKqp::TEvQueryRequest::TEvQueryRequest( , QueryCachePolicy(queryCachePolicy) , HasOperationParams(operationParams) , QuerySettings(querySettings) + , CollectFullDiagnostics(collectFullDiagnostics) { if (HasOperationParams) { OperationTimeout = GetDuration(operationParams->operation_timeout()); @@ -107,6 +109,8 @@ void TEvKqp::TEvQueryRequest::PrepareRemote() const { Record.MutableRequest()->SetIsInternalCall(RequestCtx->IsInternalCall()); Record.MutableRequest()->SetOutputChunkMaxSize(QuerySettings.OutputChunkMaxSize); + Record.MutableRequest()->SetCollectDiagnostics(CollectFullDiagnostics); + RequestCtx.reset(); } } diff --git a/ydb/core/kqp/ut/query/kqp_query_ut.cpp b/ydb/core/kqp/ut/query/kqp_query_ut.cpp index 1a095421c064..b5ff21d0a74b 100644 --- a/ydb/core/kqp/ut/query/kqp_query_ut.cpp +++ b/ydb/core/kqp/ut/query/kqp_query_ut.cpp @@ -179,6 +179,72 @@ Y_UNIT_TEST_SUITE(KqpQuery) { UNIT_ASSERT_VALUES_EQUAL(counters.RecompileRequestGet()->Val(), 1); } + Y_UNIT_TEST(ExecuteDataQueryCollectFullDiagnostics) { + auto setting = NKikimrKqp::TKqpSetting(); + auto serverSettings = TKikimrSettings() + .SetKqpSettings({setting}); + + TKikimrRunner kikimr(serverSettings); + auto db = kikimr.GetTableClient(); + auto session = db.CreateSession().GetValueSync().GetSession(); + + { + UNIT_ASSERT(session.ExecuteSchemeQuery(R"( + CREATE TABLE `/Root/TestTable` ( + Key Uint64, + Value String, + PRIMARY KEY (Key) + ); + )").GetValueSync().IsSuccess()); + } + + { + const TString query(Q1_(R"( + SELECT * FROM `/Root/TestTable`; + )")); + + { + auto settings = TExecDataQuerySettings(); + settings.CollectFullDiagnostics(true); + + auto result = session.ExecuteDataQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync(); + + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString().c_str()); + + UNIT_ASSERT_C(!result.GetDiagnostics().empty(), "Query result diagnostics is empty"); + + TStringStream in; + in << result.GetDiagnostics(); + NJson::TJsonValue value; + ReadJsonTree(&in, &value); + + UNIT_ASSERT_C(value.IsMap(), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_id"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("version"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_text"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_parameter_types"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("table_metadata"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value["table_metadata"].IsArray(), "Incorrect Diagnostics: table_metadata type should be an array"); + UNIT_ASSERT_C(value.Has("created_at"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_syntax"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_database"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_cluster"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_plan"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_type"), "Incorrect Diagnostics"); + } + + { + auto settings = TExecDataQuerySettings(); + + auto result = session.ExecuteDataQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync(); + + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString().c_str()); + + UNIT_ASSERT_C(result.GetDiagnostics().empty(), "Query result diagnostics should be empty, but it's not"); + } + } + } + Y_UNIT_TEST(QueryCachePermissionsLoss) { TKikimrRunner kikimr; auto db = kikimr.GetTableClient(); diff --git a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp index e8065a3eea08..fee83f691bcc 100644 --- a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp +++ b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp @@ -193,6 +193,55 @@ Y_UNIT_TEST_SUITE(KqpQueryService) { } } + Y_UNIT_TEST(ExecuteCollectFullDiagnostics) { + auto kikimr = DefaultKikimrRunner(); + auto db = kikimr.GetQueryClient(); + + { + TExecuteQuerySettings settings; + settings.CollectFullDiagnostics(true); + + auto result = db.ExecuteQuery(R"( + SELECT Key, Value2 FROM TwoShard WHERE Value2 > 0; + )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync(); + + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_C(!result.GetDiagnostics().empty(), "Query result diagnostics is empty"); + + TStringStream in; + in << result.GetDiagnostics(); + NJson::TJsonValue value; + ReadJsonTree(&in, &value); + + UNIT_ASSERT_C(value.IsMap(), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_id"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("version"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_text"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_parameter_types"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("table_metadata"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value["table_metadata"].IsArray(), "Incorrect Diagnostics: table_metadata type should be an array"); + UNIT_ASSERT_C(value.Has("created_at"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_syntax"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_database"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_cluster"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_plan"), "Incorrect Diagnostics"); + UNIT_ASSERT_C(value.Has("query_type"), "Incorrect Diagnostics"); + } + + { + TExecuteQuerySettings settings; + settings.CollectFullDiagnostics(true); + + auto result = db.ExecuteQuery(R"( + SELECT Key, Value2 FROM TwoShard WHERE Value2 > 0; + )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync(); + + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString().c_str()); + + UNIT_ASSERT_C(result.GetDiagnostics().empty(), "Query result diagnostics should be empty, but it's not"); + } + } + void CheckQueryResult(TExecuteQueryResult result) { UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1); diff --git a/ydb/public/api/protos/ydb_query.proto b/ydb/public/api/protos/ydb_query.proto index b1fabe26d5d7..1473817f872e 100644 --- a/ydb/public/api/protos/ydb_query.proto +++ b/ydb/public/api/protos/ydb_query.proto @@ -172,6 +172,8 @@ message ExecuteQueryRequest { int64 response_part_limit_bytes = 9 [(Ydb.value) = "[0; 33554432]"]; string pool_id = 10; // Workload manager pool id + + bool collect_full_diagnostics = 11; } message ResultSetMeta { @@ -191,6 +193,9 @@ message ExecuteQueryResponsePart { Ydb.TableStats.QueryStats exec_stats = 5; TransactionMeta tx_meta = 6; + + // Full query diagnostics + string query_full_diagnostics = 7; } message ExecuteScriptRequest { diff --git a/ydb/public/api/protos/ydb_table.proto b/ydb/public/api/protos/ydb_table.proto index 0cd658c45392..aead7d34e41a 100644 --- a/ydb/public/api/protos/ydb_table.proto +++ b/ydb/public/api/protos/ydb_table.proto @@ -904,6 +904,7 @@ message ExecuteDataQueryRequest { QueryCachePolicy query_cache_policy = 5; Ydb.Operations.OperationParams operation_params = 6; QueryStatsCollection.Mode collect_stats = 7; + bool collect_full_diagnostics = 8; } message ExecuteDataQueryResponse { @@ -946,6 +947,8 @@ message ExecuteQueryResult { QueryMeta query_meta = 3; // Query execution statistics Ydb.TableStats.QueryStats query_stats = 4; + // Full query diagnostics + string query_full_diagnostics = 5; } // Explain data query diff --git a/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp b/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp index 0200655e536a..a27f6d8ae622 100644 --- a/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp +++ b/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp @@ -365,6 +365,8 @@ void TCommandExecuteQuery::Config(TConfig& config) { config.Opts->AddLongOption('q', "query", "Text of query to execute").RequiredArgument("[String]").StoreResult(&Query); config.Opts->AddLongOption('f', "file", "Path to file with query text to execute") .RequiredArgument("PATH").StoreResult(&QueryFile); + config.Opts->AddLongOption("collect-diagnostics", "Collects diagnostics and saves it to file") + .StoreTrue(&CollectFullDiagnostics); AddOutputFormats(config, { EDataFormat::Pretty, @@ -432,6 +434,9 @@ int TCommandExecuteQuery::ExecuteDataQuery(TConfig& config) { NTable::TExecDataQuerySettings settings; settings.KeepInQueryCache(true); settings.CollectQueryStats(ParseQueryStatsModeOrThrow(CollectStatsMode, defaultStatsMode)); + if (CollectFullDiagnostics) { + settings.CollectFullDiagnostics(true); + } NTable::TTxSettings txSettings; if (TxMode) { @@ -516,6 +521,11 @@ void TCommandExecuteQuery::PrintDataQueryResponse(NTable::TDataQueryResult& resu { Cout << Endl << "Flame graph is available for full or profile stats only" << Endl; } + if (CollectFullDiagnostics) + { + TFileOutput file(TStringBuilder() << "diagnostics_" << TGUID::Create().AsGuidString() << ".txt"); + file << result.GetDiagnostics(); + } } int TCommandExecuteQuery::ExecuteSchemeQuery(TConfig& config) { @@ -558,6 +568,9 @@ namespace { if (timeout.has_value()) { settings.ClientTimeout(*timeout); } + if (CollectFullDiagnostics) { + settings.CollectFullDiagnostics(true); + } return settings; } else if constexpr (std::is_same_v) { const auto defaultStatsMode = basicStats @@ -568,6 +581,9 @@ namespace { if (timeout.has_value()) { settings.ClientTimeout(*timeout); } + if (CollectFullDiagnostics) { + settings.CollectFullDiagnostics(true); + } return settings; } Y_UNREACHABLE(); @@ -753,6 +769,8 @@ bool TCommandExecuteQuery::PrintQueryResponse(TIterator& result) { fullStats = queryStats.GetPlan(); } } + + if () } } // TResultSetPrinter destructor should be called before printing stats @@ -767,6 +785,12 @@ bool TCommandExecuteQuery::PrintQueryResponse(TIterator& result) { queryPlanPrinter.Print(*fullStats); } + if (CollectFullDiagnostics) + { + TFileOutput file(TStringBuilder() << "diagnostics_" << TGUID::Create().AsGuidString() << ".txt"); + file << result.GetDiagnostics(); + } + PrintFlameGraph(fullStats); if (IsInterrupted()) { diff --git a/ydb/public/lib/ydb_cli/commands/ydb_service_table.h b/ydb/public/lib/ydb_cli/commands/ydb_service_table.h index a0716f7dc322..70d3fcf1f006 100644 --- a/ydb/public/lib/ydb_cli/commands/ydb_service_table.h +++ b/ydb/public/lib/ydb_cli/commands/ydb_service_table.h @@ -123,6 +123,7 @@ class TCommandExecuteQuery : public TTableCommand, TCommandQueryBase, TCommandWi TString TxMode; TString QueryType; bool BasicStats = false; + bool CollectFullDiagnostics = false; }; class TCommandExplain : public TTableCommand, public TCommandWithOutput, TCommandQueryBase, TInterruptibleCommand { diff --git a/ydb/public/sdk/cpp/client/ydb_query/client.cpp b/ydb/public/sdk/cpp/client/ydb_query/client.cpp index 6cdc1a4a73ca..ee6ccaf6333e 100644 --- a/ydb/public/sdk/cpp/client/ydb_query/client.cpp +++ b/ydb/public/sdk/cpp/client/ydb_query/client.cpp @@ -727,4 +727,9 @@ TResultSetParser TExecuteQueryResult::GetResultSetParser(size_t resultIndex) con return TResultSetParser(GetResultSet(resultIndex)); } +const TString& TExecuteQueryResult::GetDiagnostics() const { + CheckStatusOk("TExecuteQueryResult::GetDiagnostics"); + return Diagnostics_; +} + } // namespace NYdb::NQuery diff --git a/ydb/public/sdk/cpp/client/ydb_query/client.h b/ydb/public/sdk/cpp/client/ydb_query/client.h index a459c4b3981a..5c31967b0ff7 100644 --- a/ydb/public/sdk/cpp/client/ydb_query/client.h +++ b/ydb/public/sdk/cpp/client/ydb_query/client.h @@ -213,23 +213,26 @@ class TExecuteQueryPart : public TStreamPartStatus { ui64 GetResultSetIndex() const { return ResultSetIndex_; } const TResultSet& GetResultSet() const { return *ResultSet_; } TResultSet ExtractResultSet() { return std::move(*ResultSet_); } + const TString& GetDiagnostics() const { return Diagnostics_; } const TMaybe& GetStats() const { return Stats_; } const TMaybe& GetTransaction() const { return Transaction_; } - TExecuteQueryPart(TStatus&& status, TMaybe&& queryStats, TMaybe&& tx) + TExecuteQueryPart(TStatus&& status, TMaybe&& queryStats, TMaybe&& tx, TString&& diagnostics) : TStreamPartStatus(std::move(status)) , Stats_(std::move(queryStats)) , Transaction_(std::move(tx)) + , Diagnostics_(std::move(diagnostics)) {} TExecuteQueryPart(TStatus&& status, TResultSet&& resultSet, i64 resultSetIndex, - TMaybe&& queryStats, TMaybe&& tx) + TMaybe&& queryStats, TMaybe&& tx, TString&& diagnostics) : TStreamPartStatus(std::move(status)) , ResultSet_(std::move(resultSet)) , ResultSetIndex_(resultSetIndex) , Stats_(std::move(queryStats)) , Transaction_(std::move(tx)) + , Diagnostics_(std::move(diagnostics)) {} private: @@ -237,6 +240,7 @@ class TExecuteQueryPart : public TStreamPartStatus { i64 ResultSetIndex_ = 0; TMaybe Stats_; TMaybe Transaction_; + TString Diagnostics_; }; class TExecuteQueryResult : public TStatus { @@ -249,22 +253,26 @@ class TExecuteQueryResult : public TStatus { TMaybe GetTransaction() const {return Transaction_; } + const TString& GetDiagnostics() const; + TExecuteQueryResult(TStatus&& status) : TStatus(std::move(status)) {} TExecuteQueryResult(TStatus&& status, TVector&& resultSets, - TMaybe&& stats, TMaybe&& tx) + TMaybe&& stats, TMaybe&& tx, TString&& diagnostics) : TStatus(std::move(status)) , ResultSets_(std::move(resultSets)) , Stats_(std::move(stats)) , Transaction_(std::move(tx)) + , Diagnostics_(std::move(diagnostics)) {} private: TVector ResultSets_; TMaybe Stats_; TMaybe Transaction_; + TString Diagnostics_; }; } // namespace NYdb::NQuery diff --git a/ydb/public/sdk/cpp/client/ydb_query/impl/exec_query.cpp b/ydb/public/sdk/cpp/client/ydb_query/impl/exec_query.cpp index 93b91c5ac2e1..fe5958a9f43d 100644 --- a/ydb/public/sdk/cpp/client/ydb_query/impl/exec_query.cpp +++ b/ydb/public/sdk/cpp/client/ydb_query/impl/exec_query.cpp @@ -67,13 +67,14 @@ class TExecuteQueryIterator::TReaderImpl { auto readCb = [self, promise](TGRpcStatus&& grpcStatus) mutable { if (!grpcStatus.Ok()) { self->Finished_ = true; - promise.SetValue({TStatus(TPlainStatus(grpcStatus, self->Endpoint_)), {}, {}}); + promise.SetValue({TStatus(TPlainStatus(grpcStatus, self->Endpoint_)), {}, {}, ""}); } else { NYql::TIssues issues; NYql::IssuesFromMessage(self->Response_.issues(), issues); EStatus clientStatus = static_cast(self->Response_.status()); TPlainStatus plainStatus{clientStatus, std::move(issues), self->Endpoint_, {}}; TStatus status{std::move(plainStatus)}; + TString diagnostics; TMaybe stats; TMaybe tx; @@ -85,16 +86,19 @@ class TExecuteQueryIterator::TReaderImpl { tx = TTransaction(self->Session_.GetRef(), self->Response_.tx_meta().id()); } + diagnostics = self->Response_.query_full_diagnostics(); + if (self->Response_.has_result_set()) { promise.SetValue({ std::move(status), TResultSet(std::move(*self->Response_.mutable_result_set())), self->Response_.result_set_index(), std::move(stats), - std::move(tx) + std::move(tx), + std::move(diagnostics) }); } else { - promise.SetValue({std::move(status), std::move(stats), std::move(tx)}); + promise.SetValue({std::move(status), std::move(stats), std::move(tx), std::move(diagnostics)}); } } }; @@ -145,6 +149,7 @@ struct TExecuteQueryBuffer : public TThrRefBase, TNonCopyable { TVector ResultSets_; TMaybe Stats_; TMaybe Tx_; + TString Diagnostics_; void Next() { TPtr self(this); @@ -178,10 +183,11 @@ struct TExecuteQueryBuffer : public TThrRefBase, TNonCopyable { TStatus(EStatus::SUCCESS, NYql::TIssues(std::move(issues))), std::move(resultSets), std::move(stats), - std::move(tx) + std::move(tx), + {} )); } else { - self->Promise_.SetValue(TExecuteQueryResult(std::move(part), {}, std::move(stats), {})); + self->Promise_.SetValue(TExecuteQueryResult(std::move(part), {}, std::move(stats), {}, {})); } return; @@ -210,6 +216,8 @@ struct TExecuteQueryBuffer : public TThrRefBase, TNonCopyable { self->Tx_ = tx; } + self->Diagnostics_ = part.GetDiagnostics(); + self->Next(); }); } @@ -240,6 +248,8 @@ TFuture> StreamExecuteQueryIm request.set_response_part_limit_bytes(*settings.OutputChunkMaxSize_); } + request.set_collect_full_diagnostics(settings.CollectFullDiagnostics_); + if (txControl.HasTx()) { auto requestTxControl = request.mutable_tx_control(); requestTxControl->set_commit_tx(txControl.CommitTx_); diff --git a/ydb/public/sdk/cpp/client/ydb_query/query.h b/ydb/public/sdk/cpp/client/ydb_query/query.h index 3ea49527ae77..e35da4695ac8 100644 --- a/ydb/public/sdk/cpp/client/ydb_query/query.h +++ b/ydb/public/sdk/cpp/client/ydb_query/query.h @@ -74,6 +74,7 @@ struct TExecuteQuerySettings : public TRequestSettings { FLUENT_SETTING_DEFAULT(EStatsMode, StatsMode, EStatsMode::None); FLUENT_SETTING_OPTIONAL(bool, ConcurrentResultSets); FLUENT_SETTING(TString, ResourcePool); + FLUENT_SETTING_DEFAULT(bool, CollectFullDiagnostics, false); }; struct TBeginTxSettings : public TRequestSettings {}; diff --git a/ydb/public/sdk/cpp/client/ydb_table/impl/table_client.h b/ydb/public/sdk/cpp/client/ydb_table/impl/table_client.h index da681f0d959a..42baeeff1d93 100644 --- a/ydb/public/sdk/cpp/client/ydb_table/impl/table_client.h +++ b/ydb/public/sdk/cpp/client/ydb_table/impl/table_client.h @@ -188,7 +188,8 @@ class TTableClient::TImpl: public TClientImplCommon, public txControl.Tx_, Nothing(), false, - Nothing())); + Nothing(), + {})); } return ExecuteDataQueryInternal(session, query, txControl, params, settings, fromCache); @@ -213,6 +214,7 @@ class TTableClient::TImpl: public TClientImplCommon, public } request.set_collect_stats(GetStatsCollectionMode(settings.CollectQueryStats_)); + request.set_collect_full_diagnostics(settings.CollectFullDiagnostics_); SetQuery(query, request.mutable_query()); CollectQuerySize(query, QuerySizeHistogram); @@ -240,6 +242,7 @@ class TTableClient::TImpl: public TClientImplCommon, public TMaybe tx; TMaybe dataQuery; TMaybe queryStats; + TString diagnostics; auto queryText = GetQueryText(query); if (any) { @@ -264,6 +267,8 @@ class TTableClient::TImpl: public TClientImplCommon, public if (result.has_query_stats()) { queryStats = TQueryStats(result.query_stats()); } + + diagnostics = result.query_full_diagnostics(); } if (keepInCache && dataQuery && queryText) { @@ -271,7 +276,7 @@ class TTableClient::TImpl: public TClientImplCommon, public } TDataQueryResult dataQueryResult(TStatus(std::move(status)), - std::move(res), tx, dataQuery, fromCache, queryStats); + std::move(res), tx, dataQuery, fromCache, queryStats, std::move(diagnostics)); delete sessionPtr; tx.Clear(); diff --git a/ydb/public/sdk/cpp/client/ydb_table/table.cpp b/ydb/public/sdk/cpp/client/ydb_table/table.cpp index 1130d5697275..dbe27d67ca6a 100644 --- a/ydb/public/sdk/cpp/client/ydb_table/table.cpp +++ b/ydb/public/sdk/cpp/client/ydb_table/table.cpp @@ -2181,13 +2181,15 @@ TTableDescription TDescribeTableResult::GetTableDescription() const { //////////////////////////////////////////////////////////////////////////////// TDataQueryResult::TDataQueryResult(TStatus&& status, TVector&& resultSets, - const TMaybe& transaction, const TMaybe& dataQuery, bool fromCache, const TMaybe &queryStats) + const TMaybe& transaction, const TMaybe& dataQuery, bool fromCache, const TMaybe &queryStats, + TString&& diagnostics) : TStatus(std::move(status)) , Transaction_(transaction) , ResultSets_(std::move(resultSets)) , DataQuery_(dataQuery) , FromCache_(fromCache) , QueryStats_(queryStats) + , Diagnostics_(std::move(diagnostics)) {} const TVector& TDataQueryResult::GetResultSets() const { @@ -2234,6 +2236,11 @@ const TString TDataQueryResult::GetQueryPlan() const { } } +const TString& TDataQueryResult::GetDiagnostics() const { + CheckStatusOk("TDataQueryResult::GetDiagnostics"); + return Diagnostics_; +} + //////////////////////////////////////////////////////////////////////////////// TBeginTransactionResult::TBeginTransactionResult(TStatus&& status, TTransaction transaction) diff --git a/ydb/public/sdk/cpp/client/ydb_table/table.h b/ydb/public/sdk/cpp/client/ydb_table/table.h index d69a9493d38c..32d0286363bc 100644 --- a/ydb/public/sdk/cpp/client/ydb_table/table.h +++ b/ydb/public/sdk/cpp/client/ydb_table/table.h @@ -1651,6 +1651,8 @@ struct TExecDataQuerySettings : public TOperationRequestSettings {}; @@ -1953,7 +1955,7 @@ class TDescribeTableResult : public NScheme::TDescribePathResult { class TDataQueryResult : public TStatus { public: TDataQueryResult(TStatus&& status, TVector&& resultSets, const TMaybe& transaction, - const TMaybe& dataQuery, bool fromCache, const TMaybe& queryStats); + const TMaybe& dataQuery, bool fromCache, const TMaybe& queryStats, TString&& diagnostics); const TVector& GetResultSets() const; TVector ExtractResultSets() &&; @@ -1970,12 +1972,15 @@ class TDataQueryResult : public TStatus { const TString GetQueryPlan() const; + const TString& GetDiagnostics() const; + private: TMaybe Transaction_; TVector ResultSets_; TMaybe DataQuery_; bool FromCache_; TMaybe QueryStats_; + TString Diagnostics_; }; class TReadTableSnapshot {