aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormakostrov <makostrov@yandex-team.com>2023-10-22 14:14:32 +0300
committermakostrov <makostrov@yandex-team.com>2023-10-22 14:34:29 +0300
commit12d1c39c9c20ca46bd4a788422bb653ebdfdef58 (patch)
tree3dbc85d6aac84b2fddb63f7bea5a2e9d2b2aa02f
parent24a44df2ab01109cefd64d4bfad05c66e7ebd2af (diff)
downloadydb-12d1c39c9c20ca46bd4a788422bb653ebdfdef58.tar.gz
Вернуть в explain запроса ReplayMessage дополнительную диагностику со схемой
KIKIMR-19690 Стоит не забыть про название флага в API CollectFullDiagnostics И отправлять данные не в бинарном ReplayMessage, а в каком-то читаемом для пользователя формате
-rw-r--r--ydb/core/grpc_services/rpc_explain_data_query.cpp2
-rw-r--r--ydb/core/kqp/common/compilation/events.h8
-rw-r--r--ydb/core/kqp/common/events/query.h4
-rw-r--r--ydb/core/kqp/compile_service/kqp_compile_service.cpp12
-rw-r--r--ydb/core/kqp/session_actor/kqp_query_state.cpp5
-rw-r--r--ydb/core/kqp/session_actor/kqp_query_state.h6
-rw-r--r--ydb/core/kqp/session_actor/kqp_session_actor.cpp46
-rw-r--r--ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp62
-rw-r--r--ydb/core/protos/kqp.proto2
-rw-r--r--ydb/core/protos/kqp_physical.proto1
-rw-r--r--ydb/public/api/protos/ydb_table.proto2
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp15
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_service_table.h1
-rw-r--r--ydb/public/sdk/cpp/client/ydb_table/impl/table_client.cpp5
-rw-r--r--ydb/public/sdk/cpp/client/ydb_table/table.cpp8
-rw-r--r--ydb/public/sdk/cpp/client/ydb_table/table.h8
16 files changed, 147 insertions, 40 deletions
diff --git a/ydb/core/grpc_services/rpc_explain_data_query.cpp b/ydb/core/grpc_services/rpc_explain_data_query.cpp
index 1b25b9e1c16..129ac5468bb 100644
--- a/ydb/core/grpc_services/rpc_explain_data_query.cpp
+++ b/ydb/core/grpc_services/rpc_explain_data_query.cpp
@@ -68,6 +68,7 @@ public:
ev->Record.MutableRequest()->SetAction(NKikimrKqp::QUERY_ACTION_EXPLAIN);
ev->Record.MutableRequest()->SetType(NKikimrKqp::QUERY_TYPE_SQL_DML);
ev->Record.MutableRequest()->SetQuery(req->yql_text());
+ ev->Record.MutableRequest()->SetCollectDiagnostics(req->Getcollect_full_diagnostics());
ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), ev.Release());
}
@@ -83,6 +84,7 @@ public:
Ydb::Table::ExplainQueryResult queryResult;
queryResult.set_query_ast(kqpResponse.GetQueryAst());
queryResult.set_query_plan(kqpResponse.GetQueryPlan());
+ queryResult.set_query_full_diagnostics(kqpResponse.GetQueryDiagnostics());
ReplyWithResult(Ydb::StatusIds::SUCCESS, issueMessage, queryResult, ctx);
} else {
diff --git a/ydb/core/kqp/common/compilation/events.h b/ydb/core/kqp/common/compilation/events.h
index f06eb09e4fe..68a25564137 100644
--- a/ydb/core/kqp/common/compilation/events.h
+++ b/ydb/core/kqp/common/compilation/events.h
@@ -16,7 +16,7 @@ struct TEvCompileRequest: public TEventLocal<TEvCompileRequest, TKqpEvents::EvCo
TMaybe<TKqpQueryId>&& query, bool keepInCache, TInstant deadline,
TKqpDbCountersPtr dbCounters, std::shared_ptr<std::atomic<bool>> intrestedInResult,
const TIntrusivePtr<TUserRequestContext>& userRequestContext, NLWTrace::TOrbit orbit = {},
- TKqpTempTablesState::TConstPtr tempTablesState = nullptr)
+ TKqpTempTablesState::TConstPtr tempTablesState = nullptr, bool collectDiagnostics = false)
: UserToken(userToken)
, Uid(uid)
, Query(std::move(query))
@@ -27,6 +27,7 @@ struct TEvCompileRequest: public TEventLocal<TEvCompileRequest, TKqpEvents::EvCo
, Orbit(std::move(orbit))
, TempTablesState(std::move(tempTablesState))
, IntrestedInResult(std::move(intrestedInResult))
+ , CollectDiagnostics(collectDiagnostics)
{
Y_ENSURE(Uid.Defined() != Query.Defined());
}
@@ -45,6 +46,8 @@ struct TEvCompileRequest: public TEventLocal<TEvCompileRequest, TKqpEvents::EvCo
TKqpTempTablesState::TConstPtr TempTablesState;
std::shared_ptr<std::atomic<bool>> IntrestedInResult;
+
+ bool CollectDiagnostics = false;
};
struct TEvRecompileRequest: public TEventLocal<TEvRecompileRequest, TKqpEvents::EvRecompileRequest> {
@@ -80,8 +83,9 @@ struct TEvRecompileRequest: public TEventLocal<TEvRecompileRequest, TKqpEvents::
};
struct TEvCompileResponse: public TEventLocal<TEvCompileResponse, TKqpEvents::EvCompileResponse> {
- TEvCompileResponse(const TKqpCompileResult::TConstPtr& compileResult, NLWTrace::TOrbit orbit = {})
+ TEvCompileResponse(const TKqpCompileResult::TConstPtr& compileResult, NLWTrace::TOrbit orbit = {}, const std::optional<TString>& replayMessage = std::nullopt)
: CompileResult(compileResult)
+ , ReplayMessage(replayMessage)
, Orbit(std::move(orbit)) {
}
diff --git a/ydb/core/kqp/common/events/query.h b/ydb/core/kqp/common/events/query.h
index a73a6e9e0a7..59fbac0e00e 100644
--- a/ydb/core/kqp/common/events/query.h
+++ b/ydb/core/kqp/common/events/query.h
@@ -233,6 +233,10 @@ public:
return ParametersSize;
}
+ bool GetCollectDiagnostics() const {
+ return Record.GetRequest().GetCollectDiagnostics();
+ }
+
ui32 CalculateSerializedSize() const override {
PrepareRemote();
return Record.ByteSize();
diff --git a/ydb/core/kqp/compile_service/kqp_compile_service.cpp b/ydb/core/kqp/compile_service/kqp_compile_service.cpp
index dcba8b3c1e5..eb6eb9adc0c 100644
--- a/ydb/core/kqp/compile_service/kqp_compile_service.cpp
+++ b/ydb/core/kqp/compile_service/kqp_compile_service.cpp
@@ -552,6 +552,8 @@ private:
Counters->ReportQueryCacheHit(dbCounters, false);
+ CollectDiagnostics = request.CollectDiagnostics;
+
LWTRACK(KqpCompileServiceEnqueued,
ev->Get()->Orbit,
ev->Get()->Query ? ev->Get()->Query->UserSid : 0);
@@ -683,7 +685,7 @@ private:
for (auto& request : requests) {
LWTRACK(KqpCompileServiceGetCompilation, request.Orbit, request.Query.UserSid, compileActorId.ToString());
Reply(request.Sender, compileResult, compileStats, ctx,
- request.Cookie, std::move(request.Orbit), std::move(request.CompileServiceSpan));
+ request.Cookie, std::move(request.Orbit), std::move(request.CompileServiceSpan), (CollectDiagnostics ? ev->Get()->ReplayMessage : std::nullopt));
}
} else {
if (QueryCache.FindByUid(compileResult->Uid, false)) {
@@ -693,7 +695,7 @@ private:
LWTRACK(KqpCompileServiceGetCompilation, compileRequest.Orbit, compileRequest.Query.UserSid, compileActorId.ToString());
Reply(compileRequest.Sender, compileResult, compileStats, ctx,
- compileRequest.Cookie, std::move(compileRequest.Orbit), std::move(compileRequest.CompileServiceSpan));
+ compileRequest.Cookie, std::move(compileRequest.Orbit), std::move(compileRequest.CompileServiceSpan), (CollectDiagnostics ? ev->Get()->ReplayMessage : std::nullopt));
}
catch (const std::exception& e) {
LogException("TEvCompileResponse", ev->Sender, e, ctx);
@@ -787,7 +789,7 @@ private:
void Reply(const TActorId& sender, const TKqpCompileResult::TConstPtr& compileResult,
const NKqpProto::TKqpStatsCompile& compileStats, const TActorContext& ctx, ui64 cookie,
- NLWTrace::TOrbit orbit, NWilson::TSpan span)
+ NLWTrace::TOrbit orbit, NWilson::TSpan span, const std::optional<TString>& replayMessage = std::nullopt)
{
const auto& query = compileResult->Query;
LWTRACK(KqpCompileServiceReply,
@@ -800,7 +802,7 @@ private:
<< ", queryUid: " << compileResult->Uid
<< ", status:" << compileResult->Status);
- auto responseEv = MakeHolder<TEvKqp::TEvCompileResponse>(compileResult, std::move(orbit));
+ auto responseEv = MakeHolder<TEvKqp::TEvCompileResponse>(compileResult, std::move(orbit), replayMessage);
responseEv->Stats.CopyFrom(compileStats);
if (span) {
@@ -859,6 +861,8 @@ private:
TKqpRequestsQueue RequestsQueue;
std::shared_ptr<IQueryReplayBackendFactory> QueryReplayFactory;
std::optional<TKqpFederatedQuerySetup> FederatedQuerySetup;
+
+ bool CollectDiagnostics = false;
};
IActor* CreateKqpCompileService(const TTableServiceConfig& tableServiceConfig, const TQueryServiceConfig& queryServiceConfig,
diff --git a/ydb/core/kqp/session_actor/kqp_query_state.cpp b/ydb/core/kqp/session_actor/kqp_query_state.cpp
index 073f2ea4aa2..5f10ea120fc 100644
--- a/ydb/core/kqp/session_actor/kqp_query_state.cpp
+++ b/ydb/core/kqp/session_actor/kqp_query_state.cpp
@@ -117,6 +117,9 @@ bool TKqpQueryState::SaveAndCheckCompileResult(TEvKqp::TEvCompileResponse* ev) {
CompileStats.Swap(&ev->Stats);
PreparedQuery = CompileResult->PreparedQuery;
+ if (ev->ReplayMessage) {
+ ReplayMessage = *ev->ReplayMessage;
+ }
return true;
}
@@ -161,7 +164,7 @@ std::unique_ptr<TEvKqp::TEvCompileRequest> TKqpQueryState::BuildCompileRequest(s
}
return std::make_unique<TEvKqp::TEvCompileRequest>(UserToken, uid,
- std::move(query), keepInCache, compileDeadline, DbCounters, std::move(cookie), UserRequestContext, std::move(Orbit), TempTablesState);
+ std::move(query), keepInCache, compileDeadline, DbCounters, std::move(cookie), UserRequestContext, std::move(Orbit), TempTablesState, GetCollectDiagnostics());
}
std::unique_ptr<TEvKqp::TEvRecompileRequest> TKqpQueryState::BuildReCompileRequest(std::shared_ptr<std::atomic<bool>> cookie) {
diff --git a/ydb/core/kqp/session_actor/kqp_query_state.h b/ydb/core/kqp/session_actor/kqp_query_state.h
index ec96d32d892..53e348baf18 100644
--- a/ydb/core/kqp/session_actor/kqp_query_state.h
+++ b/ydb/core/kqp/session_actor/kqp_query_state.h
@@ -113,6 +113,8 @@ public:
TKqpTempTablesState::TConstPtr TempTablesState;
+ TString ReplayMessage;
+
NKikimrKqp::EQueryAction GetAction() const {
return RequestEv->GetAction();
}
@@ -424,6 +426,10 @@ public:
return RequestEv->GetArena();
}
+ bool GetCollectDiagnostics() {
+ return RequestEv->GetCollectDiagnostics();
+ }
+
//// Topic ops ////
void AddOffsetsToTransaction();
bool TryMergeTopicOffsets(const NTopic::TTopicOperations &operations, TString& message);
diff --git a/ydb/core/kqp/session_actor/kqp_session_actor.cpp b/ydb/core/kqp/session_actor/kqp_session_actor.cpp
index bdcf88e4d7d..2f6dcf2f4aa 100644
--- a/ydb/core/kqp/session_actor/kqp_session_actor.cpp
+++ b/ydb/core/kqp/session_actor/kqp_session_actor.cpp
@@ -122,26 +122,26 @@ struct TKqpCleanupCtx {
class TKqpSessionActor : public TActorBootstrapped<TKqpSessionActor> {
-class TTimerGuard {
-public:
- TTimerGuard(TKqpSessionActor* this_)
- : This(this_)
- {
- if (This->QueryState) {
- YQL_ENSURE(!This->QueryState->CurrentTimer);
- This->QueryState->CurrentTimer.emplace();
+ class TTimerGuard {
+ public:
+ TTimerGuard(TKqpSessionActor* this_)
+ : This(this_)
+ {
+ if (This->QueryState) {
+ YQL_ENSURE(!This->QueryState->CurrentTimer);
+ This->QueryState->CurrentTimer.emplace();
+ }
}
- }
- ~TTimerGuard() {
- if (This->QueryState) {
- This->QueryState->ResetTimer();
+ ~TTimerGuard() {
+ if (This->QueryState) {
+ This->QueryState->ResetTimer();
+ }
}
- }
-private:
- TKqpSessionActor* This;
-};
+ private:
+ TKqpSessionActor* This;
+ };
public:
static constexpr NKikimrServices::TActivity::EType ActorActivityType() {
@@ -388,6 +388,7 @@ public:
);
switch (action) {
+ case NKikimrKqp::QUERY_ACTION_EXPLAIN:
case NKikimrKqp::QUERY_ACTION_EXECUTE:
case NKikimrKqp::QUERY_ACTION_PREPARE:
case NKikimrKqp::QUERY_ACTION_EXECUTE_PREPARED: {
@@ -421,18 +422,6 @@ public:
case NKikimrKqp::QUERY_ACTION_COMMIT_TX:
return CommitTx();
- case NKikimrKqp::QUERY_ACTION_EXPLAIN: {
- auto type = QueryState->GetType();
- if (type != NKikimrKqp::QUERY_TYPE_SQL_GENERIC_QUERY &&
- type != NKikimrKqp::QUERY_TYPE_SQL_GENERIC_CONCURRENT_QUERY &&
- type != NKikimrKqp::QUERY_TYPE_SQL_GENERIC_SCRIPT)
- {
- return ForwardRequest(ev);
- }
-
- break;
- }
-
// not supported yet
case NKikimrKqp::QUERY_ACTION_VALIDATE:
case NKikimrKqp::QUERY_ACTION_PARSE:
@@ -1639,6 +1628,7 @@ public:
response.SetQueryPlan(preparedQuery->GetPhysicalQuery().GetQueryPlan());
response.SetQueryAst(preparedQuery->GetPhysicalQuery().GetQueryAst());
+ response.SetQueryDiagnostics(QueryState->ReplayMessage);
const auto& phyQuery = QueryState->PreparedQuery->GetPhysicalQuery();
FillColumnsMeta(phyQuery, response);
diff --git a/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp b/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp
index b4a4f340754..0606d80dab8 100644
--- a/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp
+++ b/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp
@@ -1719,6 +1719,68 @@ Y_UNIT_TEST_SUITE(KqpIndexes) {
}
}
+ Y_UNIT_TEST(ExplainCollectFullDiagnostics) {
+ auto setting = NKikimrKqp::TKqpSetting();
+ auto serverSettings = TKikimrSettings()
+ .SetKqpSettings({setting});
+
+ TKikimrRunner kikimr(serverSettings);
+ auto db = kikimr.GetTableClient();
+ auto session = db.CreateSession().GetValueSync().GetSession();
+
+ {
+ auto tableBuilder = db.GetTableBuilder();
+ tableBuilder
+ .AddNullableColumn("Key", EPrimitiveType::Int64)
+ .AddNullableColumn("Index2", EPrimitiveType::Int64)
+ .AddNullableColumn("Value", EPrimitiveType::String);
+ tableBuilder.SetPrimaryKeyColumns(TVector<TString>{"Key"});
+ tableBuilder.AddSecondaryIndex("Index", TVector<TString>{"Index2"});
+ auto result = session.CreateTable("/Root/TestTable", tableBuilder.Build()).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL(result.IsTransportError(), false);
+ UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::SUCCESS);
+ }
+
+ {
+ const TString query(Q1_(R"(
+ SELECT * FROM `/Root/TestTable` VIEW Index as t ORDER BY t.Index2 DESC;
+ )"));
+
+ {
+ auto settings = TExplainDataQuerySettings();
+ settings.WithCollectFullDiagnostics(true);
+
+ auto result = session.ExplainDataQuery(
+ query, settings)
+ .ExtractValueSync();
+
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString().c_str());
+
+ UNIT_ASSERT_C(result.GetAst().Contains("'('\"Reverse\")"), result.GetAst());
+
+ 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.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");
+ }
+ }
+ }
+
Y_UNIT_TEST(SecondaryIndexOrderBy2) {
auto setting = NKikimrKqp::TKqpSetting();
auto serverSettings = TKikimrSettings()
diff --git a/ydb/core/protos/kqp.proto b/ydb/core/protos/kqp.proto
index 97da279a9e4..ef14b52776d 100644
--- a/ydb/core/protos/kqp.proto
+++ b/ydb/core/protos/kqp.proto
@@ -107,6 +107,7 @@ message TQueryRequest {
map<string, Ydb.TypedValue> YdbParameters = 24;
optional bool IsInternalCall = 25;
optional Ydb.Query.Syntax Syntax = 26;
+ optional bool CollectDiagnostics = 27;
}
message TKqpPathIdProto {
@@ -263,6 +264,7 @@ message TQueryResponse {
optional NKqpProto.TKqpStatsQuery QueryStats = 12;
repeated Ydb.ResultSet YdbResults = 13;
optional TTopicOperationsResponse TopicOperations = 14;
+ optional string QueryDiagnostics = 15;
}
message TEvQueryResponse {
diff --git a/ydb/core/protos/kqp_physical.proto b/ydb/core/protos/kqp_physical.proto
index 92ce2f435dc..59fd591e11c 100644
--- a/ydb/core/protos/kqp_physical.proto
+++ b/ydb/core/protos/kqp_physical.proto
@@ -454,4 +454,5 @@ message TKqpPhyQuery {
repeated TKqpTableInfo TableInfos = 8;
bool HasUncommittedChangesRead = 9;
+ string QueryDiagnostics = 10;
}
diff --git a/ydb/public/api/protos/ydb_table.proto b/ydb/public/api/protos/ydb_table.proto
index c6d0bb1b6c1..bcb02e05407 100644
--- a/ydb/public/api/protos/ydb_table.proto
+++ b/ydb/public/api/protos/ydb_table.proto
@@ -853,6 +853,7 @@ message ExplainDataQueryRequest {
// SQL text to explain
string yql_text = 2;
Ydb.Operations.OperationParams operation_params = 3;
+ bool collect_full_diagnostics = 4;
}
message ExplainDataQueryResponse {
@@ -863,6 +864,7 @@ message ExplainDataQueryResponse {
message ExplainQueryResult {
string query_ast = 1;
string query_plan = 2;
+ string query_full_diagnostics = 3;
}
// Prepare given program to execute
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 37d8878cc79..818bc2620c9 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp
+++ b/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp
@@ -14,6 +14,7 @@
#include <util/string/split.h>
#include <util/folder/path.h>
#include <util/folder/dirut.h>
+#include <util/generic/guid.h>
#include <math.h>
@@ -687,6 +688,8 @@ void TCommandExplain::Config(TConfig& config) {
.NoArgument().SetFlag(&Analyze);
config.Opts->AddLongOption("flame-graph", "Builds resource usage flame graph, based on analyze info")
.RequiredArgument("PATH").StoreResult(&FlameGraphPath);
+ config.Opts->AddLongOption("collect-diagnostics", "Collects diagnostics and saves it to file")
+ .StoreTrue(&CollectFullDiagnostics);
AddFormats(config, {
EOutputFormat::Pretty,
@@ -757,14 +760,24 @@ int TCommandExplain::Run(TConfig& config) {
ast = proto.query_ast();
}
} else if (QueryType == "data" && !Analyze) {
+ NTable::TExplainDataQuerySettings settings(FillSettings(NTable::TExplainDataQuerySettings()));
+ if (CollectFullDiagnostics) {
+ settings.WithCollectFullDiagnostics(true);
+ }
+
NTable::TExplainQueryResult result = GetSession(config).ExplainDataQuery(
Query,
- FillSettings(NTable::TExplainDataQuerySettings())
+ settings
).GetValueSync();
ThrowOnError(result);
planJson = result.GetPlan();
ast = result.GetAst();
+ if (CollectFullDiagnostics) {
+ TFileOutput file(TStringBuilder() << "diagnostics_" << TGUID::Create().AsGuidString() << ".txt");
+ file << result.GetDiagnostics();
+ }
+
} else {
throw TMisuseException() << "Unknown query type for explain.";
}
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 52c1bd65564..1c2fa2ce713 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_service_table.h
+++ b/ydb/public/lib/ydb_cli/commands/ydb_service_table.h
@@ -133,6 +133,7 @@ private:
TString QueryType;
bool Analyze = false;
TMaybe<TString> FlameGraphPath;
+ bool CollectFullDiagnostics = false;
};
class TCommandReadTable : public TYdbCommand, public TCommandWithPath,
diff --git a/ydb/public/sdk/cpp/client/ydb_table/impl/table_client.cpp b/ydb/public/sdk/cpp/client/ydb_table/impl/table_client.cpp
index 7a8da53c996..bb85e97b783 100644
--- a/ydb/public/sdk/cpp/client/ydb_table/impl/table_client.cpp
+++ b/ydb/public/sdk/cpp/client/ydb_table/impl/table_client.cpp
@@ -700,6 +700,7 @@ TAsyncExplainDataQueryResult TTableClient::TImpl::ExplainDataQuery(const TSessio
auto request = MakeOperationRequest<Ydb::Table::ExplainDataQueryRequest>(settings);
request.set_session_id(session.GetId());
request.set_yql_text(query);
+ request.set_collect_full_diagnostics(settings.WithCollectFullDiagnostics_);
auto promise = NewPromise<TExplainQueryResult>();
@@ -707,14 +708,16 @@ TAsyncExplainDataQueryResult TTableClient::TImpl::ExplainDataQuery(const TSessio
(google::protobuf::Any* any, TPlainStatus status) mutable {
TString ast;
TString plan;
+ TString diagnostics;
if (any) {
Ydb::Table::ExplainQueryResult result;
any->UnpackTo(&result);
ast = result.query_ast();
plan = result.query_plan();
+ diagnostics = result.query_full_diagnostics();
}
TExplainQueryResult val(TStatus(std::move(status)),
- std::move(plan), std::move(ast));
+ std::move(plan), std::move(ast), std::move(diagnostics));
promise.SetValue(std::move(val));
};
diff --git a/ydb/public/sdk/cpp/client/ydb_table/table.cpp b/ydb/public/sdk/cpp/client/ydb_table/table.cpp
index 54419be40c0..6033ec6438b 100644
--- a/ydb/public/sdk/cpp/client/ydb_table/table.cpp
+++ b/ydb/public/sdk/cpp/client/ydb_table/table.cpp
@@ -2017,10 +2017,11 @@ bool TPrepareQueryResult::IsQueryFromCache() const {
////////////////////////////////////////////////////////////////////////////////
-TExplainQueryResult::TExplainQueryResult(TStatus&& status, TString&& plan, TString&& ast)
+TExplainQueryResult::TExplainQueryResult(TStatus&& status, TString&& plan, TString&& ast, TString&& diagnostics)
: TStatus(std::move(status))
, Plan_(std::move(plan))
, Ast_(std::move(ast))
+ , Diagnostics_(std::move(diagnostics))
{}
const TString& TExplainQueryResult::GetPlan() const {
@@ -2033,6 +2034,11 @@ const TString& TExplainQueryResult::GetAst() const {
return Ast_;
}
+const TString& TExplainQueryResult::GetDiagnostics() const {
+ CheckStatusOk("TExplainQueryResult::GetDiagnostics");
+ return Diagnostics_;
+}
+
////////////////////////////////////////////////////////////////////////////////
TDescribeTableResult::TDescribeTableResult(TStatus&& status, Ydb::Table::DescribeTableResult&& desc,
diff --git a/ydb/public/sdk/cpp/client/ydb_table/table.h b/ydb/public/sdk/cpp/client/ydb_table/table.h
index 06300e9ce75..375b7d114ce 100644
--- a/ydb/public/sdk/cpp/client/ydb_table/table.h
+++ b/ydb/public/sdk/cpp/client/ydb_table/table.h
@@ -1524,7 +1524,9 @@ struct TDescribeTableSettings : public TOperationRequestSettings<TDescribeTableS
FLUENT_SETTING_DEFAULT(bool, WithPartitionStatistics, false);
};
-struct TExplainDataQuerySettings : public TOperationRequestSettings<TExplainDataQuerySettings> {};
+struct TExplainDataQuerySettings : public TOperationRequestSettings<TExplainDataQuerySettings> {
+ FLUENT_SETTING_DEFAULT(bool, WithCollectFullDiagnostics, false);
+};
struct TPrepareDataQuerySettings : public TOperationRequestSettings<TPrepareDataQuerySettings> {};
@@ -1778,14 +1780,16 @@ private:
//! Represents result of ExplainDataQuery call
class TExplainQueryResult : public TStatus {
public:
- TExplainQueryResult(TStatus&& status, TString&& plan, TString&& ast);
+ TExplainQueryResult(TStatus&& status, TString&& plan, TString&& ast, TString&& diagnostics);
const TString& GetPlan() const;
const TString& GetAst() const;
+ const TString& GetDiagnostics() const;
private:
TString Plan_;
TString Ast_;
+ TString Diagnostics_;
};
//! Represents result of DescribeTable call