diff --git a/ydb/core/kqp/session_actor/kqp_query_state.h b/ydb/core/kqp/session_actor/kqp_query_state.h index 56d971e021ad..e88ff2e79a34 100644 --- a/ydb/core/kqp/session_actor/kqp_query_state.h +++ b/ydb/core/kqp/session_actor/kqp_query_state.h @@ -493,18 +493,6 @@ class TKqpQueryState : public TNonCopyable { PrepareCurrentStatement(); } - void PrepareStatementTransaction(NKqpProto::TKqpPhyTx_EType txType) { - if (!HasTxControl()) { - switch (txType) { - case NKqpProto::TKqpPhyTx::TYPE_SCHEME: - TxCtx->EffectiveIsolationLevel = NKikimrKqp::ISOLATION_LEVEL_UNDEFINED; - break; - default: - TxCtx->EffectiveIsolationLevel = NKikimrKqp::ISOLATION_LEVEL_SERIALIZABLE; - } - } - } - // validate the compiled query response and ensure that all table versions are not // changed since the last compilation. bool EnsureTableVersions(const TEvTxProxySchemeCache::TEvNavigateKeySetResult& response); diff --git a/ydb/core/kqp/session_actor/kqp_session_actor.cpp b/ydb/core/kqp/session_actor/kqp_session_actor.cpp index e3b18878a325..f0a379e1f145 100644 --- a/ydb/core/kqp/session_actor/kqp_session_actor.cpp +++ b/ydb/core/kqp/session_actor/kqp_session_actor.cpp @@ -1104,11 +1104,10 @@ class TKqpSessionActor : public TActorBootstrapped { bool ExecutePhyTx(const TKqpPhyTxHolder::TConstPtr& tx, bool commit) { if (tx) { - QueryState->PrepareStatementTransaction(tx->GetType()); switch (tx->GetType()) { case NKqpProto::TKqpPhyTx::TYPE_SCHEME: YQL_ENSURE(tx->StagesSize() == 0); - if (QueryState->HasTxControl() && QueryState->TxCtx->EffectiveIsolationLevel != NKikimrKqp::ISOLATION_LEVEL_UNDEFINED) { + if (QueryState->HasTxControl() && !QueryState->HasImplicitTx() && QueryState->TxCtx->EffectiveIsolationLevel != NKikimrKqp::ISOLATION_LEVEL_UNDEFINED) { ReplyQueryError(Ydb::StatusIds::PRECONDITION_FAILED, "Scheme operations cannot be executed inside transaction"); return true; 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 f6b812e2f5dc..577fe08ef03b 100644 --- a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp +++ b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp @@ -2315,6 +2315,10 @@ Y_UNIT_TEST_SUITE(KqpQueryService) { ALTER TABLE TestDdlDml2 DROP COLUMN Value2; UPSERT INTO TestDdlDml2 (Key, Value1) VALUES (2, "2"); SELECT * FROM TestDdlDml2; + CREATE TABLE TestDdlDml33 ( + Key Uint64, + PRIMARY KEY (Key) + ); )", TTxControl::NoTx()).ExtractValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 2); @@ -2329,6 +2333,13 @@ Y_UNIT_TEST_SUITE(KqpQueryService) { UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1); CompareYson(R"([[[1u];["1"]];[[2u];["2"]]])", FormatResultSetYson(result.GetResultSet(0))); + result = db.ExecuteQuery(R"( + SELECT * FROM TestDdlDml33; + )", TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1); + CompareYson(R"([])", FormatResultSetYson(result.GetResultSet(0))); + result = db.ExecuteQuery(R"( CREATE TABLE TestDdlDml4 ( Key Uint64, @@ -2623,6 +2634,177 @@ Y_UNIT_TEST_SUITE(KqpQueryService) { } } + Y_UNIT_TEST(CheckIsolationLevelFroPerStatementMode) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnablePreparedDdl(true); + appConfig.MutableTableServiceConfig()->SetEnableAstCache(true); + appConfig.MutableTableServiceConfig()->SetEnablePerStatementQueryExecution(true); + auto setting = NKikimrKqp::TKqpSetting(); + auto serverSettings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetKqpSettings({setting}); + + TKikimrRunner kikimr(serverSettings); + auto db = kikimr.GetQueryClient(); + auto tableClient = kikimr.GetTableClient(); + auto session = tableClient.CreateSession().GetValueSync().GetSession(); + + { + // 1 ddl statement + auto result = db.ExecuteQuery(R"( + CREATE TABLE Test1 ( + Key Uint64, + Value1 String, + Value2 String, + PRIMARY KEY (Key) + ); + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 0); + UNIT_ASSERT_EQUAL_C(result.GetIssues().Size(), 0, result.GetIssues().ToString()); + + NYdb::NTable::TDescribeTableResult describe = session.DescribeTable("/Root/Test1").GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetStatus(), EStatus::SUCCESS); + } + + { + // 2 ddl statements + auto result = db.ExecuteQuery(R"( + CREATE TABLE Test2 ( + Key Uint64, + Value1 String, + Value2 String, + PRIMARY KEY (Key) + ); + CREATE TABLE Test3 ( + Key Uint64, + Value1 String, + Value2 String, + PRIMARY KEY (Key) + ); + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 0); + UNIT_ASSERT_EQUAL_C(result.GetIssues().Size(), 0, result.GetIssues().ToString()); + + NYdb::NTable::TDescribeTableResult describe1 = session.DescribeTable("/Root/Test2").GetValueSync(); + UNIT_ASSERT_EQUAL(describe1.GetStatus(), EStatus::SUCCESS); + NYdb::NTable::TDescribeTableResult describe2 = session.DescribeTable("/Root/Test3").GetValueSync(); + UNIT_ASSERT_EQUAL(describe2.GetStatus(), EStatus::SUCCESS); + } + + { + // 1 dml statement + auto result = db.ExecuteQuery(R"( + SELECT * FROM Test1; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1); + UNIT_ASSERT_EQUAL_C(result.GetIssues().Size(), 0, result.GetIssues().ToString()); + } + + { + // 2 dml statements + auto result = db.ExecuteQuery(R"( + SELECT * FROM Test2; + SELECT * FROM Test3; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 2); + UNIT_ASSERT_EQUAL_C(result.GetIssues().Size(), 0, result.GetIssues().ToString()); + } + + { + // 1 ddl 1 dml statements + auto result = db.ExecuteQuery(R"( + CREATE TABLE Test4 ( + Key Uint64, + Value1 String, + Value2 String, + PRIMARY KEY (Key) + ); + SELECT * FROM Test4; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1); + UNIT_ASSERT_EQUAL_C(result.GetIssues().Size(), 0, result.GetIssues().ToString()); + NYdb::NTable::TDescribeTableResult describe = session.DescribeTable("/Root/Test4").GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetStatus(), EStatus::SUCCESS); + } + + { + // 1 dml 1 ddl statements + auto result = db.ExecuteQuery(R"( + SELECT * FROM Test4; + CREATE TABLE Test5 ( + Key Uint64, + Value1 String, + Value2 String, + PRIMARY KEY (Key) + ); + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1); + UNIT_ASSERT_EQUAL_C(result.GetIssues().Size(), 0, result.GetIssues().ToString()); + NYdb::NTable::TDescribeTableResult describe = session.DescribeTable("/Root/Test5").GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetStatus(), EStatus::SUCCESS); + } + + { + // 1 ddl 1 dml 1 ddl 1 dml statements + auto result = db.ExecuteQuery(R"( + CREATE TABLE Test6 ( + Key Uint64, + Value1 String, + Value2 String, + PRIMARY KEY (Key) + ); + SELECT * FROM Test6; + CREATE TABLE Test7 ( + Key Uint64, + Value1 String, + Value2 String, + PRIMARY KEY (Key) + ); + SELECT * FROM Test7; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 2); + UNIT_ASSERT_EQUAL_C(result.GetIssues().Size(), 0, result.GetIssues().ToString()); + NYdb::NTable::TDescribeTableResult describe1 = session.DescribeTable("/Root/Test6").GetValueSync(); + UNIT_ASSERT_EQUAL(describe1.GetStatus(), EStatus::SUCCESS); + NYdb::NTable::TDescribeTableResult describe2 = session.DescribeTable("/Root/Test7").GetValueSync(); + UNIT_ASSERT_EQUAL(describe2.GetStatus(), EStatus::SUCCESS); + } + + { + // 1 dml 1 ddl 1 dml 1 ddl statements + auto result = db.ExecuteQuery(R"( + SELECT * FROM Test7; + CREATE TABLE Test8 ( + Key Uint64, + Value1 String, + Value2 String, + PRIMARY KEY (Key) + ); + SELECT * FROM Test8; + CREATE TABLE Test9 ( + Key Uint64, + Value1 String, + Value2 String, + PRIMARY KEY (Key) + ); + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 2); + UNIT_ASSERT_EQUAL_C(result.GetIssues().Size(), 0, result.GetIssues().ToString()); + NYdb::NTable::TDescribeTableResult describe1 = session.DescribeTable("/Root/Test8").GetValueSync(); + UNIT_ASSERT_EQUAL(describe1.GetStatus(), EStatus::SUCCESS); + NYdb::NTable::TDescribeTableResult describe2 = session.DescribeTable("/Root/Test9").GetValueSync(); + UNIT_ASSERT_EQUAL(describe2.GetStatus(), EStatus::SUCCESS); + } + } + Y_UNIT_TEST(TableSink_ReplaceFromSelectOlap) { NKikimrConfig::TAppConfig appConfig; appConfig.MutableTableServiceConfig()->SetEnableOlapSink(true);