diff --git a/ydb/core/kqp/gateway/behaviour/resource_pool/behaviour.cpp b/ydb/core/kqp/gateway/behaviour/resource_pool/behaviour.cpp new file mode 100644 index 000000000000..a1b172b8741b --- /dev/null +++ b/ydb/core/kqp/gateway/behaviour/resource_pool/behaviour.cpp @@ -0,0 +1,28 @@ +#include "behaviour.h" +#include "manager.h" + +#include + + +namespace NKikimr::NKqp { + +TResourcePoolBehaviour::TFactory::TRegistrator TResourcePoolBehaviour::Registrator(TResourcePoolConfig::GetTypeId()); + +NMetadata::NInitializer::IInitializationBehaviour::TPtr TResourcePoolBehaviour::ConstructInitializer() const { + return nullptr; +} + +NMetadata::NModifications::IOperationsManager::TPtr TResourcePoolBehaviour::ConstructOperationsManager() const { + return std::make_shared(); +} + +TString TResourcePoolBehaviour::GetInternalStorageTablePath() const { + return TResourcePoolConfig::GetTypeId(); +} + + +TString TResourcePoolBehaviour::GetTypeId() const { + return TResourcePoolConfig::GetTypeId(); +} + +} // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/gateway/behaviour/resource_pool/behaviour.h b/ydb/core/kqp/gateway/behaviour/resource_pool/behaviour.h new file mode 100644 index 000000000000..01587224e41d --- /dev/null +++ b/ydb/core/kqp/gateway/behaviour/resource_pool/behaviour.h @@ -0,0 +1,27 @@ +#pragma once + +#include + + +namespace NKikimr::NKqp { + +class TResourcePoolConfig { +public: + static TString GetTypeId() { + return "RESOURCE_POOL"; + } +}; + +class TResourcePoolBehaviour: public NMetadata::TClassBehaviour { + static TFactory::TRegistrator Registrator; + +protected: + virtual std::shared_ptr ConstructInitializer() const override; + virtual std::shared_ptr ConstructOperationsManager() const override; + virtual TString GetInternalStorageTablePath() const override; + +public: + virtual TString GetTypeId() const override; +}; + +} // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/gateway/behaviour/resource_pool/manager.cpp b/ydb/core/kqp/gateway/behaviour/resource_pool/manager.cpp new file mode 100644 index 000000000000..f2a30829a243 --- /dev/null +++ b/ydb/core/kqp/gateway/behaviour/resource_pool/manager.cpp @@ -0,0 +1,80 @@ +#include "manager.h" + +#include +#include + + +namespace NKikimr::NKqp { + +namespace { + +void CheckFeatureFlag(TResourcePoolManager::TInternalModificationContext& context) { + auto* actorSystem = context.GetExternalData().GetActorSystem(); + if (!actorSystem) { + ythrow yexception() << "This place needs an actor system. Please contact internal support"; + } + + if (!AppData(actorSystem)->FeatureFlags.GetEnableResourcePools()) { + throw std::runtime_error("Resource pools are disabled. Please contact your system administrator to enable it"); + } +} + +void ValidateObjectId(const TString& objectId) { + if (objectId.find('/') != TString::npos) { + throw std::runtime_error("Resource pool id should not contain '/' symbol"); + } +} + +TResourcePoolManager::TYqlConclusionStatus StatusFromActivityType(TResourcePoolManager::EActivityType activityType) { + using TYqlConclusionStatus = TResourcePoolManager::TYqlConclusionStatus; + using EActivityType = TResourcePoolManager::EActivityType; + + switch (activityType) { + case EActivityType::Undefined: + return TYqlConclusionStatus::Fail("Undefined operation for RESOURCE_POOL object"); + case EActivityType::Upsert: + return TYqlConclusionStatus::Fail("Upsert operation for RESOURCE_POOL objects is not implemented"); + case EActivityType::Create: + return TYqlConclusionStatus::Fail("Create operation for RESOURCE_POOL objects is not implemented"); + case EActivityType::Alter: + return TYqlConclusionStatus::Fail("Alter operation for RESOURCE_POOL objects is not implemented"); + case EActivityType::Drop: + return TYqlConclusionStatus::Fail("Drop operation for RESOURCE_POOL objects is not implemented"); + } +} + +} // anonymous namespace + +NThreading::TFuture TResourcePoolManager::DoModify(const NYql::TObjectSettingsImpl& settings, ui32 nodeId, const NMetadata::IClassBehaviour::TPtr& manager, TInternalModificationContext& context) const { + Y_UNUSED(nodeId, manager); + + try { + CheckFeatureFlag(context); + ValidateObjectId(settings.GetObjectId()); + + return NThreading::MakeFuture(StatusFromActivityType(context.GetActivityType())); + } catch (...) { + return NThreading::MakeFuture(TYqlConclusionStatus::Fail(CurrentExceptionMessage())); + } +} + +TResourcePoolManager::TYqlConclusionStatus TResourcePoolManager::DoPrepare(NKqpProto::TKqpSchemeOperation& schemeOperation, const NYql::TObjectSettingsImpl& settings, const NMetadata::IClassBehaviour::TPtr& manager, TInternalModificationContext& context) const { + Y_UNUSED(schemeOperation, manager); + + try { + CheckFeatureFlag(context); + ValidateObjectId(settings.GetObjectId()); + + return StatusFromActivityType(context.GetActivityType()); + } catch (...) { + return TYqlConclusionStatus::Fail(CurrentExceptionMessage()); + } +} + +NThreading::TFuture TResourcePoolManager::ExecutePrepared(const NKqpProto::TKqpSchemeOperation& schemeOperation, ui32 nodeId, const NMetadata::IClassBehaviour::TPtr& manager, const IOperationsManager::TExternalModificationContext& context) const { + Y_UNUSED(nodeId, manager, context); + + return NThreading::MakeFuture(TYqlConclusionStatus::Fail(TStringBuilder() << "Execution of prepare operation for RESOURCE_POOL object: unsupported operation: " << static_cast(schemeOperation.GetOperationCase()))); +} + +} // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/gateway/behaviour/resource_pool/manager.h b/ydb/core/kqp/gateway/behaviour/resource_pool/manager.h new file mode 100644 index 000000000000..132455a033d4 --- /dev/null +++ b/ydb/core/kqp/gateway/behaviour/resource_pool/manager.h @@ -0,0 +1,25 @@ +#pragma once + +#include + + +namespace NKikimr::NKqp { + +class TResourcePoolManager : public NMetadata::NModifications::IOperationsManager { +public: + using NMetadata::NModifications::IOperationsManager::TYqlConclusionStatus; + +protected: + NThreading::TFuture DoModify(const NYql::TObjectSettingsImpl& settings, ui32 nodeId, + const NMetadata::IClassBehaviour::TPtr& manager, TInternalModificationContext& context) const override; + + TYqlConclusionStatus DoPrepare(NKqpProto::TKqpSchemeOperation& schemeOperation, const NYql::TObjectSettingsImpl& settings, + const NMetadata::IClassBehaviour::TPtr& manager, IOperationsManager::TInternalModificationContext& context) const override; + +public: + + NThreading::TFuture ExecutePrepared(const NKqpProto::TKqpSchemeOperation& schemeOperation, + const ui32 nodeId, const NMetadata::IClassBehaviour::TPtr& manager, const IOperationsManager::TExternalModificationContext& context) const override; +}; + +} // namespace NKikimr::NKqp diff --git a/ydb/core/kqp/gateway/behaviour/resource_pool/ya.make b/ydb/core/kqp/gateway/behaviour/resource_pool/ya.make new file mode 100644 index 000000000000..7dc605c7da65 --- /dev/null +++ b/ydb/core/kqp/gateway/behaviour/resource_pool/ya.make @@ -0,0 +1,15 @@ +LIBRARY() + +SRCS( + manager.cpp + GLOBAL behaviour.cpp +) + +PEERDIR( + ydb/services/metadata/abstract + ydb/services/metadata/manager +) + +YQL_LAST_ABI_VERSION() + +END() diff --git a/ydb/core/kqp/gateway/behaviour/ya.make b/ydb/core/kqp/gateway/behaviour/ya.make index 741203bd73c9..bd59426cc368 100644 --- a/ydb/core/kqp/gateway/behaviour/ya.make +++ b/ydb/core/kqp/gateway/behaviour/ya.make @@ -1,5 +1,6 @@ RECURSE( external_data_source + resource_pool table tablestore ) diff --git a/ydb/core/kqp/gateway/ya.make b/ydb/core/kqp/gateway/ya.make index 42a45f677775..51767a6992a1 100644 --- a/ydb/core/kqp/gateway/ya.make +++ b/ydb/core/kqp/gateway/ya.make @@ -17,6 +17,7 @@ PEERDIR( ydb/core/kqp/gateway/behaviour/tablestore ydb/core/kqp/gateway/behaviour/table ydb/core/kqp/gateway/behaviour/external_data_source + ydb/core/kqp/gateway/behaviour/resource_pool ydb/core/kqp/gateway/behaviour/view ydb/core/kqp/gateway/utils ydb/library/yql/providers/result/expr_nodes diff --git a/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp b/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp index 71797376af04..c91e7dcff563 100644 --- a/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp +++ b/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp @@ -5988,6 +5988,51 @@ Y_UNIT_TEST_SUITE(KqpScheme) { UNIT_ASSERT_EQUAL_C(describe.GetStatus(), EStatus::SCHEME_ERROR, result.GetIssues().ToString()); } } + + Y_UNIT_TEST(DisableResourcePools) { + TKikimrRunner kikimr(TKikimrSettings().SetEnableResourcePools(false)); + auto db = kikimr.GetTableClient(); + auto session = db.CreateSession().GetValueSync().GetSession(); + + auto checkDisabled = [&session](const TString& query) { + Cerr << "Check query:\n" << query << "\n"; + auto result = session.ExecuteSchemeQuery(query).GetValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS(result.GetIssues().ToString(), "Resource pools are disabled. Please contact your system administrator to enable it"); + }; + + // CREATE RESOURCE POOL + checkDisabled(R"( + CREATE RESOURCE POOL `MyResourcePool` WITH ( + CONCURRENT_QUERY_LIMIT=20, + QUERY_CANCEL_AFTER_SECONDS=86400, + QUERY_COUNT_LIMIT=1000 + );)"); + + // ALTER RESOURCE POOL + checkDisabled(R"( + ALTER RESOURCE POOL `MyResourcePool` + SET (CONCURRENT_QUERY_LIMIT = 30), + SET QUERY_COUNT_LIMIT 100, + RESET (QUERY_CANCEL_AFTER_SECONDS); + )"); + + // DROP RESOURCE POOL + checkDisabled("DROP RESOURCE POOL `MyResourcePool`;"); + } + + Y_UNIT_TEST(ResourcePoolsValidation) { + TKikimrRunner kikimr(TKikimrSettings().SetEnableResourcePools(true)); + auto db = kikimr.GetTableClient(); + auto session = db.CreateSession().GetValueSync().GetSession(); + + auto result = session.ExecuteSchemeQuery(R"( + CREATE RESOURCE POOL `MyFolder/MyResourcePool` WITH ( + CONCURRENT_QUERY_LIMIT=20 + );)").GetValueSync(); + UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), EStatus::GENERIC_ERROR); + UNIT_ASSERT_STRING_CONTAINS(result.GetIssues().ToString(), "Resource pool id should not contain '/' symbol"); + } } Y_UNIT_TEST_SUITE(KqpOlapScheme) { diff --git a/ydb/core/protos/feature_flags.proto b/ydb/core/protos/feature_flags.proto index e3e188528c53..6927b2c57cf5 100644 --- a/ydb/core/protos/feature_flags.proto +++ b/ydb/core/protos/feature_flags.proto @@ -141,4 +141,5 @@ message TFeatureFlags { optional bool EnableExternalSourceSchemaInference = 126 [default = false]; optional bool EnableDbMetadataCache = 127 [default = false]; optional bool EnableTableDatetime64 = 128 [default = false]; + optional bool EnableResourcePools = 129 [default = false]; } diff --git a/ydb/core/testlib/basics/feature_flags.h b/ydb/core/testlib/basics/feature_flags.h index a6aec3482fb8..d93dd22e033c 100644 --- a/ydb/core/testlib/basics/feature_flags.h +++ b/ydb/core/testlib/basics/feature_flags.h @@ -59,6 +59,7 @@ class TTestFeatureFlagsHolder { FEATURE_FLAG_SETTER(EnableReplaceIfExistsForExternalEntities) FEATURE_FLAG_SETTER(EnableCMSRequestPriorities) FEATURE_FLAG_SETTER(EnableTableDatetime64) + FEATURE_FLAG_SETTER(EnableResourcePools) #undef FEATURE_FLAG_SETTER }; diff --git a/ydb/library/yql/sql/v1/SQLv1.g.in b/ydb/library/yql/sql/v1/SQLv1.g.in index e2edd1c7238b..3814b5152cd9 100644 --- a/ydb/library/yql/sql/v1/SQLv1.g.in +++ b/ydb/library/yql/sql/v1/SQLv1.g.in @@ -63,6 +63,9 @@ sql_stmt_core: | create_view_stmt | drop_view_stmt | alter_replication_stmt + | create_resource_pool_stmt + | alter_resource_pool_stmt + | drop_resource_pool_stmt ; expr: @@ -798,6 +801,21 @@ permission_name: permission_id | STRING_VALUE; permission_name_target: permission_name (COMMA permission_name)* COMMA? | ALL PRIVILEGES?; +create_resource_pool_stmt: CREATE RESOURCE POOL object_ref + with_table_settings +; + +alter_resource_pool_stmt: ALTER RESOURCE POOL object_ref + alter_resource_pool_action (COMMA alter_resource_pool_action)* +; +alter_resource_pool_action: + alter_table_set_table_setting_uncompat + | alter_table_set_table_setting_compat + | alter_table_reset_table_setting +; + +drop_resource_pool_stmt: DROP RESOURCE POOL object_ref; + create_replication_stmt: CREATE ASYNC REPLICATION object_ref FOR replication_target (COMMA replication_target)* WITH LPAREN replication_settings RPAREN @@ -1189,6 +1207,7 @@ keyword_as_compat: | PATTERN | PER | PERMUTE + | POOL | PRIVILEGES | QUEUE // | READ @@ -1347,6 +1366,7 @@ keyword_compat: ( | PER | PERMUTE | PLAN + | POOL | PRAGMA | PRECEDING | PRESORT @@ -1695,6 +1715,7 @@ PATTERN: P A T T E R N; PER: P E R; PERMUTE: P E R M U T E; PLAN: P L A N; +POOL: P O O L; PRAGMA: P R A G M A; PRECEDING: P R E C E D I N G; PRESORT: P R E S O R T; diff --git a/ydb/library/yql/sql/v1/format/sql_format.cpp b/ydb/library/yql/sql/v1/format/sql_format.cpp index 02ce9b8d1c6e..085b8fe818df 100644 --- a/ydb/library/yql/sql/v1/format/sql_format.cpp +++ b/ydb/library/yql/sql/v1/format/sql_format.cpp @@ -1495,6 +1495,38 @@ friend struct TStaticData; VisitAllFields(TRule_drop_replication_stmt::GetDescriptor(), msg); } + void VisitCreateResourcePool(const TRule_create_resource_pool_stmt& msg) { + PosFromToken(msg.GetToken1()); + NewLine(); + VisitAllFields(TRule_create_resource_pool_stmt::GetDescriptor(), msg); + } + + void VisitAlterResourcePool(const TRule_alter_resource_pool_stmt& msg) { + PosFromToken(msg.GetToken1()); + NewLine(); + VisitToken(msg.GetToken1()); + VisitToken(msg.GetToken2()); + VisitToken(msg.GetToken3()); + Visit(msg.GetRule_object_ref4()); + + NewLine(); + PushCurrentIndent(); + Visit(msg.GetRule_alter_resource_pool_action5()); + for (const auto& action : msg.GetBlock6()) { + Visit(action.GetToken1()); // comma + NewLine(); + Visit(action.GetRule_alter_resource_pool_action2()); + } + + PopCurrentIndent(); + } + + void VisitDropResourcePool(const TRule_drop_resource_pool_stmt& msg) { + PosFromToken(msg.GetToken1()); + NewLine(); + VisitAllFields(TRule_drop_resource_pool_stmt::GetDescriptor(), msg); + } + void VisitAllFields(const NProtoBuf::Descriptor* descr, const NProtoBuf::Message& msg) { VisitAllFieldsImpl(this, descr, msg); } @@ -2708,7 +2740,10 @@ TStaticData::TStaticData() {TRule_revoke_permissions_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitRevokePermissions)}, {TRule_alter_table_store_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitAlterTableStore)}, {TRule_create_view_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitCreateView)}, - {TRule_drop_view_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitDropView)} + {TRule_drop_view_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitDropView)}, + {TRule_create_resource_pool_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitCreateResourcePool)}, + {TRule_alter_resource_pool_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitAlterResourcePool)}, + {TRule_drop_resource_pool_stmt::GetDescriptor(), MakePrettyFunctor(&TPrettyVisitor::VisitDropResourcePool)} }) , ObfuscatingVisitDispatch({ {TToken::GetDescriptor(), MakeObfuscatingFunctor(&TObfuscatingVisitor::VisitToken)}, diff --git a/ydb/library/yql/sql/v1/format/sql_format_ut.cpp b/ydb/library/yql/sql/v1/format/sql_format_ut.cpp index a67fff8534e4..cca94f066896 100644 --- a/ydb/library/yql/sql/v1/format/sql_format_ut.cpp +++ b/ydb/library/yql/sql/v1/format/sql_format_ut.cpp @@ -1581,4 +1581,22 @@ FROM Input MATCH_RECOGNIZE (PATTERN (A) DEFINE A AS A); TSetup setup; setup.Run(cases); } + + Y_UNIT_TEST(ResourcePoolOperations) { + TCases cases = { + {"creAte reSourCe poOl naMe With (a = \"b\")", + "CREATE RESOURCE POOL naMe WITH (a = \"b\");\n"}, + {"create resource pool eds with (a=\"a\",b=\"b\",c = true)", + "CREATE RESOURCE POOL eds WITH (\n\ta = \"a\",\n\tb = \"b\",\n\tc = TRUE\n);\n"}, + {"alTer reSOurcE poOl naMe sEt a tRue, resEt (b, c), seT (x=y, z=false)", + "ALTER RESOURCE POOL naMe\n\tSET a TRUE,\n\tRESET (b, c),\n\tSET (x = y, z = FALSE);\n"}, + {"alter resource pool eds reset (a), set (x=y)", + "ALTER RESOURCE POOL eds\n\tRESET (a),\n\tSET (x = y);\n"}, + {"dRop reSourCe poOl naMe", + "DROP RESOURCE POOL naMe;\n"}, + }; + + TSetup setup; + setup.Run(cases); + } } diff --git a/ydb/library/yql/sql/v1/sql.cpp b/ydb/library/yql/sql/v1/sql.cpp index f2c682d443fb..e50c776269e5 100644 --- a/ydb/library/yql/sql/v1/sql.cpp +++ b/ydb/library/yql/sql/v1/sql.cpp @@ -164,6 +164,9 @@ bool NeedUseForAllStatements(const TRule_sql_stmt_core::AltCase& subquery) { case TRule_sql_stmt_core::kAltSqlStmtCore42: // create view case TRule_sql_stmt_core::kAltSqlStmtCore43: // drop view case TRule_sql_stmt_core::kAltSqlStmtCore44: // alter replication + case TRule_sql_stmt_core::kAltSqlStmtCore45: // create resource pool + case TRule_sql_stmt_core::kAltSqlStmtCore46: // alter resource pool + case TRule_sql_stmt_core::kAltSqlStmtCore47: // drop resource pool return false; } } diff --git a/ydb/library/yql/sql/v1/sql_query.cpp b/ydb/library/yql/sql/v1/sql_query.cpp index 6cec204cb15c..b28b2125bf23 100644 --- a/ydb/library/yql/sql/v1/sql_query.cpp +++ b/ydb/library/yql/sql/v1/sql_query.cpp @@ -1281,6 +1281,69 @@ bool TSqlQuery::Statement(TVector& blocks, const TRule_sql_stmt_core& std::move(settings), context)); break; } + case TRule_sql_stmt_core::kAltSqlStmtCore45: { + // create_resource_pool_stmt: CREATE RESOURCE POOL name WITH (k=v,...); + auto& node = core.GetAlt_sql_stmt_core45().GetRule_create_resource_pool_stmt1(); + TObjectOperatorContext context(Ctx.Scoped); + if (node.GetRule_object_ref4().HasBlock1()) { + if (!ClusterExpr(node.GetRule_object_ref4().GetBlock1().GetRule_cluster_expr1(), + false, context.ServiceId, context.Cluster)) { + return false; + } + } + + const TString& objectId = Id(node.GetRule_object_ref4().GetRule_id_or_at2(), *this).second; + std::map kv; + if (!ParseResourcePoolSettings(kv, node.GetRule_with_table_settings5())) { + return false; + } + + AddStatementToBlocks(blocks, BuildCreateObjectOperation(Ctx.Pos(), objectId, "RESOURCE_POOL", false, false, std::move(kv), context)); + break; + } + case TRule_sql_stmt_core::kAltSqlStmtCore46: { + // alter_resource_pool_stmt: ALTER RESOURCE POOL object_ref alter_resource_pool_action (COMMA alter_external_data_source_action)* + Ctx.BodyPart(); + const auto& node = core.GetAlt_sql_stmt_core46().GetRule_alter_resource_pool_stmt1(); + TObjectOperatorContext context(Ctx.Scoped); + if (node.GetRule_object_ref4().HasBlock1()) { + if (!ClusterExpr(node.GetRule_object_ref4().GetBlock1().GetRule_cluster_expr1(), + false, context.ServiceId, context.Cluster)) { + return false; + } + } + + const TString& objectId = Id(node.GetRule_object_ref4().GetRule_id_or_at2(), *this).second; + std::map kv; + std::set toReset; + if (!ParseResourcePoolSettings(kv, toReset, node.GetRule_alter_resource_pool_action5())) { + return false; + } + + for (const auto& action : node.GetBlock6()) { + if (!ParseResourcePoolSettings(kv, toReset, action.GetRule_alter_resource_pool_action2())) { + return false; + } + } + + AddStatementToBlocks(blocks, BuildAlterObjectOperation(Ctx.Pos(), objectId, "RESOURCE_POOL", std::move(kv), std::move(toReset), context)); + break; + } + case TRule_sql_stmt_core::kAltSqlStmtCore47: { + // drop_resource_pool_stmt: DROP RESOURCE POOL name; + auto& node = core.GetAlt_sql_stmt_core47().GetRule_drop_resource_pool_stmt1(); + TObjectOperatorContext context(Ctx.Scoped); + if (node.GetRule_object_ref4().HasBlock1()) { + if (!ClusterExpr(node.GetRule_object_ref4().GetBlock1().GetRule_cluster_expr1(), + false, context.ServiceId, context.Cluster)) { + return false; + } + } + + const TString& objectId = Id(node.GetRule_object_ref4().GetRule_id_or_at2(), *this).second; + AddStatementToBlocks(blocks, BuildDropObjectOperation(Ctx.Pos(), objectId, "RESOURCE_POOL", false, {}, context)); + break; + } case TRule_sql_stmt_core::ALT_NOT_SET: Ctx.IncrementMonCounter("sql_errors", "UnknownStatement" + internalStatementName); AltNotImplemented("sql_stmt_core", core); diff --git a/ydb/library/yql/sql/v1/sql_translation.cpp b/ydb/library/yql/sql/v1/sql_translation.cpp index e54e059c938e..67119a19945c 100644 --- a/ydb/library/yql/sql/v1/sql_translation.cpp +++ b/ydb/library/yql/sql/v1/sql_translation.cpp @@ -1620,6 +1620,20 @@ namespace { return true; } + bool StoreInt(const TRule_table_setting_value& from, TDeferredAtom& to, TContext& ctx, const TString& errorPrefix = {}) { + switch (from.Alt_case()) { + case TRule_table_setting_value::kAltTableSettingValue3: { + // integer + to = TDeferredAtom(LiteralNumber(ctx, from.GetAlt_table_setting_value3().GetRule_integer1()), ctx); + break; + } + default: + ctx.Error() << errorPrefix << " value should be an integer"; + return false; + } + return true; + } + bool StoreBool(const TRule_table_setting_value& from, TDeferredAtom& to, TContext& ctx) { if (!from.HasAlt_table_setting_value6()) { return false; @@ -4617,4 +4631,82 @@ TNodePtr TSqlTranslation::ReturningList(const ::NSQLv1Generated::TRule_returning return result.Release(); } +bool TSqlTranslation::StoreResourcePoolSettingsEntry(const TIdentifier& id, const TRule_table_setting_value* value, std::map& result) { + YQL_ENSURE(value); + + const TString key = to_lower(id.Name); + if (result.find(key) != result.end()) { + Ctx.Error() << to_upper(key) << " duplicate keys"; + return false; + } + + switch (value->Alt_case()) { + case TRule_table_setting_value::kAltTableSettingValue2: + return StoreString(*value, result[key], Ctx, to_upper(key)); + + case TRule_table_setting_value::kAltTableSettingValue3: + return StoreInt(*value, result[key], Ctx, to_upper(key)); + + default: + Ctx.Error() << to_upper(key) << " value should be a string literal or integer"; + return false; + } + + return true; +} + +bool TSqlTranslation::StoreResourcePoolSettingsEntry(const TRule_alter_table_setting_entry& entry, std::map& result) { + const TIdentifier id = IdEx(entry.GetRule_an_id1(), *this); + return StoreResourcePoolSettingsEntry(id, &entry.GetRule_table_setting_value3(), result); +} + +bool TSqlTranslation::ParseResourcePoolSettings(std::map& result, const TRule_with_table_settings& settingsNode) { + const auto& firstEntry = settingsNode.GetRule_table_settings_entry3(); + if (!StoreResourcePoolSettingsEntry(IdEx(firstEntry.GetRule_an_id1(), *this), &firstEntry.GetRule_table_setting_value3(), result)) { + return false; + } + for (const auto& block : settingsNode.GetBlock4()) { + const auto& entry = block.GetRule_table_settings_entry2(); + if (!StoreResourcePoolSettingsEntry(IdEx(entry.GetRule_an_id1(), *this), &entry.GetRule_table_setting_value3(), result)) { + return false; + } + } + return true; +} + +bool TSqlTranslation::ParseResourcePoolSettings(std::map& result, std::set& toReset, const TRule_alter_resource_pool_action& alterAction) { + switch (alterAction.Alt_case()) { + case TRule_alter_resource_pool_action::kAltAlterResourcePoolAction1: { + const auto& action = alterAction.GetAlt_alter_resource_pool_action1().GetRule_alter_table_set_table_setting_uncompat1(); + if (!StoreResourcePoolSettingsEntry(IdEx(action.GetRule_an_id2(), *this), &action.GetRule_table_setting_value3(), result)) { + return false; + } + return true; + } + case TRule_alter_resource_pool_action::kAltAlterResourcePoolAction2: { + const auto& action = alterAction.GetAlt_alter_resource_pool_action2().GetRule_alter_table_set_table_setting_compat1(); + if (!StoreResourcePoolSettingsEntry(action.GetRule_alter_table_setting_entry3(), result)) { + return false; + } + for (const auto& entry : action.GetBlock4()) { + if (!StoreResourcePoolSettingsEntry(entry.GetRule_alter_table_setting_entry2(), result)) { + return false; + } + } + return true; + } + case TRule_alter_resource_pool_action::kAltAlterResourcePoolAction3: { + const auto& action = alterAction.GetAlt_alter_resource_pool_action3().GetRule_alter_table_reset_table_setting1(); + const TString firstKey = to_lower(IdEx(action.GetRule_an_id3(), *this).Name); + toReset.insert(firstKey); + for (const auto& key : action.GetBlock4()) { + toReset.insert(to_lower(IdEx(key.GetRule_an_id2(), *this).Name)); + } + return true; + } + case TRule_alter_resource_pool_action::ALT_NOT_SET: + Y_ABORT("You should change implementation according to grammar changes"); + } +} + } // namespace NSQLTranslationV1 diff --git a/ydb/library/yql/sql/v1/sql_translation.h b/ydb/library/yql/sql/v1/sql_translation.h index 1e8ccd3a5017..09e634511aa9 100644 --- a/ydb/library/yql/sql/v1/sql_translation.h +++ b/ydb/library/yql/sql/v1/sql_translation.h @@ -175,6 +175,8 @@ class TSqlTranslation: public TTranslation { bool StoreTableSettingsEntry(const TIdentifier& id, const TRule_table_setting_value& value, TTableSettings& settings, ETableType tableType, bool alter = false); bool StoreDataSourceSettingsEntry(const TIdentifier& id, const TRule_table_setting_value* value, std::map& result); bool StoreDataSourceSettingsEntry(const TRule_alter_table_setting_entry& entry, std::map& result); + bool StoreResourcePoolSettingsEntry(const TIdentifier& id, const TRule_table_setting_value* value, std::map& result); + bool StoreResourcePoolSettingsEntry(const TRule_alter_table_setting_entry& entry, std::map& result); bool ResetTableSettingsEntry(const TIdentifier& id, TTableSettings& settings, ETableType tableType); TIdentifier GetTopicConsumerId(const TRule_topic_consumer_ref& node); @@ -229,6 +231,8 @@ class TSqlTranslation: public TTranslation { bool ParseExternalDataSourceSettings(std::map& result, std::set& toReset, const TRule_alter_external_data_source_action& alterActions); bool ParseViewOptions(std::map& features, const TRule_with_table_settings& options); bool ParseViewQuery(std::map& features, const TRule_select_stmt& query); + bool ParseResourcePoolSettings(std::map& result, const TRule_with_table_settings& settings); + bool ParseResourcePoolSettings(std::map& result, std::set& toReset, const TRule_alter_resource_pool_action& alterAction); bool RoleNameClause(const TRule_role_name& node, TDeferredAtom& result, bool allowSystemRoles); bool RoleParameters(const TRule_create_user_option& node, TRoleParameters& result); bool PermissionNameClause(const TRule_permission_name_target& node, TVector& result, bool withGrantOption); diff --git a/ydb/library/yql/sql/v1/sql_ut.cpp b/ydb/library/yql/sql/v1/sql_ut.cpp index 12ecf624fef2..9d580d6c677b 100644 --- a/ydb/library/yql/sql/v1/sql_ut.cpp +++ b/ydb/library/yql/sql/v1/sql_ut.cpp @@ -2494,7 +2494,7 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { Y_UNIT_TEST(AlterTableAddIndexWithIsNotSupported) { ExpectFailWithError("USE plato; ALTER TABLE table ADD INDEX idx LOCAL WITH (a=b, c=d, e=f) ON (col)", - "
:1:40: Error: local: alternative is not implemented yet: 722:7: local_index\n"); + "
:1:40: Error: local: alternative is not implemented yet: 725:7: local_index\n"); } Y_UNIT_TEST(AlterTableAlterIndexSetPartitioningIsCorrect) { @@ -6840,3 +6840,88 @@ Y_UNIT_TEST_SUITE(CompactNamedExprs) { SqlToYql(query).IsOk(); } } + +Y_UNIT_TEST_SUITE(ResourcePool) { + Y_UNIT_TEST(CreateResourcePool) { + NYql::TAstParseResult res = SqlToYql(R"sql( + USE plato; + CREATE RESOURCE POOL MyResourcePool WITH ( + CONCURRENT_QUERY_LIMIT=20, + QUERY_CANCEL_AFTER_SECONDS=86400, + QUEUE_TYPE="FIFO" + ); + )sql"); + UNIT_ASSERT_C(res.Root, res.Issues.ToString()); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"concurrent_query_limit" (Int32 '"20")) '('"query_cancel_after_seconds" (Int32 '"86400")) '('"queue_type" '"FIFO"))#"); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + + Y_UNIT_TEST(CreateResourcePoolWithBadArguments) { + ExpectFailWithError(R"sql( + USE plato; + CREATE RESOURCE POOL MyResourcePool; + )sql" , "
:3:51: Error: Unexpected token ';' : syntax error...\n\n"); + + ExpectFailWithError(R"sql( + USE plato; + CREATE RESOURCE POOL MyResourcePool WITH ( + DUPLICATE_SETTING="first_value", + DUPLICATE_SETTING="second_value" + ); + )sql" , "
:5:21: Error: DUPLICATE_SETTING duplicate keys\n"); + } + + Y_UNIT_TEST(AlterResourcePool) { + NYql::TAstParseResult res = SqlToYql(R"sql( + USE plato; + ALTER RESOURCE POOL MyResourcePool + SET (CONCURRENT_QUERY_LIMIT = 30, Weight = 5), + SET QUEUE_TYPE "UNORDERED", + RESET (Query_Cancel_After_Seconds, Query_Count_Limit); + )sql"); + UNIT_ASSERT_C(res.Root, res.Issues.ToString()); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_STRING_CONTAINS(line, R"#(('mode 'alterObject))#"); + UNIT_ASSERT_STRING_CONTAINS(line, R"#('('features '('('"concurrent_query_limit" (Int32 '"30")) '('"queue_type" '"UNORDERED") '('"weight" (Int32 '"5")))))#"); + UNIT_ASSERT_STRING_CONTAINS(line, R"#('('resetFeatures '('"query_cancel_after_seconds" '"query_count_limit")))#"); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } + + Y_UNIT_TEST(DropResourcePool) { + NYql::TAstParseResult res = SqlToYql(R"sql( + USE plato; + DROP RESOURCE POOL MyResourcePool; + )sql"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write") { + UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'features")); + UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject")); + } + }; + + TWordCountHive elementStat = { {TString("Write"), 0}}; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]); + } +} diff --git a/ydb/services/metadata/abstract/parsing.h b/ydb/services/metadata/abstract/parsing.h index 6e6743327bf8..8b80b1e64d12 100644 --- a/ydb/services/metadata/abstract/parsing.h +++ b/ydb/services/metadata/abstract/parsing.h @@ -60,9 +60,11 @@ class TObjectSettingsImpl { if (auto maybeAtom = i.template Maybe()) { Features.emplace(maybeAtom.Cast().StringValue(), ""); } else if (auto maybeTuple = i.template Maybe()) { - auto tuple = maybeTuple.Cast(); - if (auto tupleValue = tuple.Value().template Maybe()) { - Features.emplace(tuple.Name().Value(), tupleValue.Cast().Value()); + NNodes::TCoNameValueTuple tuple = maybeTuple.Cast(); + if (auto maybeAtom = tuple.Value().template Maybe()) { + Features.emplace(tuple.Name().Value(), maybeAtom.Cast().Value()); + } else if (auto maybeDataCtor = tuple.Value().template Maybe()) { + Features.emplace(tuple.Name().Value(), maybeDataCtor.Cast().Literal().Cast().Value()); } } } diff --git a/ydb/tests/tools/kqprun/configuration/app_config.conf b/ydb/tests/tools/kqprun/configuration/app_config.conf index 6d9a34e34146..eebc7479f333 100644 --- a/ydb/tests/tools/kqprun/configuration/app_config.conf +++ b/ydb/tests/tools/kqprun/configuration/app_config.conf @@ -2,6 +2,7 @@ FeatureFlags { EnableExternalDataSources: true EnableScriptExecutionOperations: true EnableExternalSourceSchemaInference: true + EnableResourcePools: true } KQPConfig {