diff --git a/ydb/core/testlib/actors/test_runtime.cpp b/ydb/core/testlib/actors/test_runtime.cpp index 4b09cda39ae8..07e4a7eed77c 100644 --- a/ydb/core/testlib/actors/test_runtime.cpp +++ b/ydb/core/testlib/actors/test_runtime.cpp @@ -18,10 +18,11 @@ namespace NActors { void TTestActorRuntime::TNodeData::Stop() { - TNodeDataBase::Stop(); if (Mon) { Mon->Stop(); + GetAppData()->Mon = nullptr; } + TNodeDataBase::Stop(); } TTestActorRuntime::TNodeData::~TNodeData() { diff --git a/ydb/core/viewer/json_query.h b/ydb/core/viewer/json_query.h index 5563c8a4ece4..71c3afa51f91 100644 --- a/ydb/core/viewer/json_query.h +++ b/ydb/core/viewer/json_query.h @@ -210,6 +210,10 @@ class TJsonQuery : public TViewerPipeClient { request.SetType(NKikimrKqp::QUERY_TYPE_SQL_DML); request.SetKeepSession(false); SetTransactionMode(request); + if (!request.txcontrol().has_begin_tx()) { + request.mutable_txcontrol()->mutable_begin_tx()->mutable_serializable_read_write(); + request.mutable_txcontrol()->set_commit_tx(true); + } } else if (Action == "explain" || Action == "explain-ast" || Action == "explain-data") { request.SetAction(NKikimrKqp::QUERY_ACTION_EXPLAIN); request.SetType(NKikimrKqp::QUERY_TYPE_SQL_DML); diff --git a/ydb/core/viewer/viewer_ut.cpp b/ydb/core/viewer/viewer_ut.cpp index 3b93fa7d8a07..b78bd810befd 100644 --- a/ydb/core/viewer/viewer_ut.cpp +++ b/ydb/core/viewer/viewer_ut.cpp @@ -1115,6 +1115,91 @@ Y_UNIT_TEST_SUITE(Viewer) { size_t AuthorizeTicketFails = 0; }; + TString PostQuery(TKeepAliveHttpClient& httpClient, TString query, TString action = "", TString transactionMode = "", HttpCodes expectedCode = HTTP_OK) { + TStringStream requestBody; + requestBody + << "{ \"query\": \"" << query << "\"," + << " \"database\": \"/Root\"," + << " \"action\": \"" << action << "\"," + << " \"syntax\": \"yql_v1\"," + << " \"transaction_mode\": \"" << transactionMode << "\"," + << " \"stats\": \"none\" }"; + TStringStream responseStream; + TKeepAliveHttpClient::THeaders headers; + headers["Content-Type"] = "application/json"; + headers["Authorization"] = "test_ydb_token"; + const TKeepAliveHttpClient::THttpCode statusCode = httpClient.DoPost("/viewer/json/query?timeout=600000&base64=false&schema=modern", requestBody.Str(), &responseStream, headers); + const TString response = responseStream.ReadAll(); + UNIT_ASSERT_EQUAL_C(statusCode, expectedCode, statusCode << ": " << response); + return response; + } + + Y_UNIT_TEST(ExecuteQueryDoesntExecuteSchemeOperationsInsideTransation) { + TPortManager tp; + ui16 port = tp.GetPort(2134); + ui16 grpcPort = tp.GetPort(2135); + ui16 monPort = tp.GetPort(8765); + auto settings = TServerSettings(port); + settings.InitKikimrRunConfig() + .SetNodeCount(1) + .SetUseRealThreads(true) + .SetDomainName("Root") + .SetMonitoringPortOffset(monPort, true); + + TServer server(settings); + server.EnableGRpc(grpcPort); + TClient client(settings); + client.InitRootScheme(); + + TTestActorRuntime& runtime = *server.GetRuntime(); + runtime.SetLogPriority(NKikimrServices::TICKET_PARSER, NLog::PRI_TRACE); + + TKeepAliveHttpClient httpClient("localhost", monPort); + + //Scheme operations cannot be executed inside transaction + TString response = PostQuery(httpClient, "CREATE TABLE `/Root/Test` (Key Uint64, Value String, PRIMARY KEY (Key));", "execute-query", "serializable-read-write", HTTP_BAD_REQUEST); + { + NJson::TJsonReaderConfig jsonCfg; + NJson::TJsonValue json; + NJson::ReadJsonTree(response, &jsonCfg, &json, /* throwOnError = */ true); + UNIT_ASSERT_EQUAL_C(json["error"].GetMap().at("message").GetString(), "Scheme operations cannot be executed inside transaction", response); + } + } + + Y_UNIT_TEST(UseTransactionWhenExecuteDataActionQuery) { + TPortManager tp; + ui16 port = tp.GetPort(2134); + ui16 grpcPort = tp.GetPort(2135); + ui16 monPort = tp.GetPort(8765); + auto settings = TServerSettings(port); + settings.InitKikimrRunConfig() + .SetNodeCount(1) + .SetUseRealThreads(true) + .SetDomainName("Root") + .SetMonitoringPortOffset(monPort, true); + + TServer server(settings); + server.EnableGRpc(grpcPort); + TClient client(settings); + client.InitRootScheme(); + + TTestActorRuntime& runtime = *server.GetRuntime(); + runtime.SetLogPriority(NKikimrServices::TICKET_PARSER, NLog::PRI_TRACE); + + TKeepAliveHttpClient httpClient("localhost", monPort); + + PostQuery(httpClient, "CREATE TABLE `/Root/Test` (Key Uint64, Value String, PRIMARY KEY (Key));", "execute-query"); + PostQuery(httpClient, "INSERT INTO `/Root/Test` (Key, Value) VALUES (1, 'testvalue');", "execute-query"); + TString response = PostQuery(httpClient, "SELECT * FROM `/Root/Test`;", "execute-data"); + { + NJson::TJsonReaderConfig jsonCfg; + NJson::TJsonValue json; + NJson::ReadJsonTree(response, &jsonCfg, &json, /* throwOnError = */ true); + auto resultSets = json["result"].GetArray(); + UNIT_ASSERT_EQUAL_C(1, resultSets.size(), response); + } + } + Y_UNIT_TEST(FloatPointJsonQuery) { TPortManager tp; ui16 port = tp.GetPort(2134); @@ -1145,7 +1230,7 @@ Y_UNIT_TEST_SUITE(Viewer) { "database": "/Root", "action": "execute-script", "syntax": "yql_v1", - "stats": "profile" + "stats": "none" })json"; const TKeepAliveHttpClient::THttpCode statusCode = httpClient.DoPost("/viewer/json/query?timeout=600000&base64=false&schema=modern", requestBody, &responseStream, headers); const TString response = responseStream.ReadAll(); @@ -1210,7 +1295,7 @@ Y_UNIT_TEST_SUITE(Viewer) { "database": "/Root", "action": "execute-script", "syntax": "yql_v1", - "stats": "profile" + "stats": "none" })json"; const TKeepAliveHttpClient::THttpCode statusCode = httpClient.DoPost("/viewer/json/query?timeout=600000&base64=false&schema=modern", requestBody, &responseStream, headers); const TString response = responseStream.ReadAll();