diff options
author | vpolka <vpolka@yandex-team.com> | 2023-11-23 14:31:48 +0300 |
---|---|---|
committer | vpolka <vpolka@yandex-team.com> | 2023-11-23 16:10:51 +0300 |
commit | 207ac81618e05ade724a8a8193bc9125d466bd06 (patch) | |
tree | 3d413edf0790e408136e56c71440360c72f6754f | |
parent | 3444af692d32224288c41ba8c21e416d5fd4996c (diff) | |
download | ydb-207ac81618e05ade724a8a8193bc9125d466bd06.tar.gz |
KIKIMR-20078: drop/alter/create user
-rw-r--r-- | ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp | 16 | ||||
-rw-r--r-- | ydb/core/kqp/gateway/kqp_gateway.h | 5 | ||||
-rw-r--r-- | ydb/core/kqp/gateway/kqp_ic_gateway.cpp | 49 | ||||
-rw-r--r-- | ydb/core/kqp/host/kqp_gateway_proxy.cpp | 106 | ||||
-rw-r--r-- | ydb/core/kqp/provider/yql_kikimr_datasink.cpp | 2 | ||||
-rw-r--r-- | ydb/core/kqp/provider/yql_kikimr_exec.cpp | 21 | ||||
-rw-r--r-- | ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp | 15 | ||||
-rw-r--r-- | ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp | 30 | ||||
-rw-r--r-- | ydb/core/protos/flat_scheme_op.proto | 1 | ||||
-rw-r--r-- | ydb/core/protos/kqp_physical.proto | 3 | ||||
-rw-r--r-- | ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp | 5 | ||||
-rw-r--r-- | ydb/library/login/login.cpp | 4 | ||||
-rw-r--r-- | ydb/library/login/login.h | 1 | ||||
-rw-r--r-- | ydb/library/yql/sql/pg/pg_sql.cpp | 6 |
14 files changed, 213 insertions, 51 deletions
diff --git a/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp b/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp index 60757028b8..2fdbf74c10 100644 --- a/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp +++ b/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp @@ -133,6 +133,22 @@ public: return StartBuildOperation(); } + case NKqpProto::TKqpSchemeOperation::kCreateUser: { + auto modifyScheme = schemeOp.GetCreateUser(); + ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + break; + } + case NKqpProto::TKqpSchemeOperation::kAlterUser: { + auto modifyScheme = schemeOp.GetAlterUser(); + ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + break; + } + case NKqpProto::TKqpSchemeOperation::kDropUser: { + auto modifyScheme = schemeOp.GetDropUser(); + ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + break; + } + default: InternalError(TStringBuilder() << "Unexpected scheme operation: " << (ui32) schemeOp.GetOperationCase()); diff --git a/ydb/core/kqp/gateway/kqp_gateway.h b/ydb/core/kqp/gateway/kqp_gateway.h index f5d267d09f..42f43b0240 100644 --- a/ydb/core/kqp/gateway/kqp_gateway.h +++ b/ydb/core/kqp/gateway/kqp_gateway.h @@ -163,6 +163,8 @@ public: public: virtual TString GetDatabase() = 0; + virtual bool GetDomainLoginOnly() = 0; + virtual TMaybe<TString> GetDomainName() = 0; /* Scheme */ virtual NThreading::TFuture<TKqpTableProfilesResult> GetTableProfiles() = 0; @@ -201,6 +203,9 @@ TIntrusivePtr<IKqpGateway> CreateKikimrIcGateway(const TString& cluster, const T bool SplitTablePath(const TString& tableName, const TString& database, std::pair<TString, TString>& pathPair, TString& error, bool createDir); +bool SetDatabaseForLoginOperation(TString& result, bool getDomainLoginOnly, TMaybe<TString> domainName, + const TString& database); + } // namespace NKikimr::NKqp template<> diff --git a/ydb/core/kqp/gateway/kqp_ic_gateway.cpp b/ydb/core/kqp/gateway/kqp_ic_gateway.cpp index aa024e9613..f9d0c0e262 100644 --- a/ydb/core/kqp/gateway/kqp_ic_gateway.cpp +++ b/ydb/core/kqp/gateway/kqp_ic_gateway.cpp @@ -630,6 +630,21 @@ public: UserToken = token; } + bool GetDomainLoginOnly() override { + TAppData* appData = AppData(ActorSystem); + return appData && appData->AuthConfig.GetDomainLoginOnly(); + } + + TMaybe<TString> GetDomainName() override { + TAppData* appData = AppData(ActorSystem); + if (GetDomainLoginOnly()) { + if (appData->DomainsInfo && !appData->DomainsInfo->Domains.empty()) { + return appData->DomainsInfo->Domains.begin()->second->Name; + } + } + return {}; + } + TVector<NKikimrKqp::TKqpTableMetadataProto> GetCollectedSchemeData() override { return MetadataLoader->GetCollectedSchemeData(); } @@ -1368,17 +1383,11 @@ public: auto& dropUser = *schemeTx.MutableAlterLogin()->MutableRemoveUser(); dropUser.SetUser(settings.UserName); + dropUser.SetMissingOk(settings.Force); SendSchemeRequest(ev.Release()).Apply( - [dropUserPromise, &settings](const TFuture<TGenericResult>& future) mutable { - const auto& realResult = future.GetValue(); - if (!realResult.Success() && realResult.Status() == TIssuesIds::DEFAULT_ERROR && settings.Force) { - IKqpGateway::TGenericResult fakeResult; - fakeResult.SetSuccess(); - dropUserPromise.SetValue(std::move(fakeResult)); - } else { - dropUserPromise.SetValue(realResult); - } + [dropUserPromise](const TFuture<TGenericResult>& future) mutable { + dropUserPromise.SetValue(future.GetValue()); } ); @@ -2094,17 +2103,7 @@ private: } bool GetDatabaseForLoginOperation(TString& database) { - TAppData* appData = AppData(ActorSystem); - if (appData && appData->AuthConfig.GetDomainLoginOnly()) { - if (appData->DomainsInfo && !appData->DomainsInfo->Domains.empty()) { - database = "/" + appData->DomainsInfo->Domains.begin()->second->Name; - return true; - } - } else { - database = Database; - return true; - } - return false; + return SetDatabaseForLoginOperation(database, GetDomainLoginOnly(), GetDomainName(), GetDatabase()); } bool GetPathPair(const TString& tableName, std::pair<TString, TString>& pathPair, @@ -2267,6 +2266,16 @@ bool SplitTablePath(const TString& tableName, const TString& database, std::pair } } +bool SetDatabaseForLoginOperation(TString& result, bool getDomainLoginOnly, TMaybe<TString> domainName, + const TString& database) +{ + if (getDomainLoginOnly && !domainName) { + return false; + } + result = domainName ? "/" + *domainName : database; + return true; +} + } // namespace NKqp } // namespace NKikimr diff --git a/ydb/core/kqp/host/kqp_gateway_proxy.cpp b/ydb/core/kqp/host/kqp_gateway_proxy.cpp index 97a2f8ddca..eae247ec57 100644 --- a/ydb/core/kqp/host/kqp_gateway_proxy.cpp +++ b/ydb/core/kqp/host/kqp_gateway_proxy.cpp @@ -778,15 +778,107 @@ public: } TFuture<TGenericResult> CreateUser(const TString& cluster, const TCreateUserSettings& settings) override { - FORWARD_ENSURE_NO_PREPARE(CreateUser, cluster, settings); + CHECK_PREPARED_DDL(CreateUser); + + auto createUserPromise = NewPromise<TGenericResult>(); + + TString database; + if (!SetDatabaseForLoginOperation(database, GetDomainLoginOnly(), GetDomainName(), GetDatabase())) { + return MakeFuture(ResultFromError<TGenericResult>("Couldn't get domain name")); + } + + NKikimrSchemeOp::TModifyScheme schemeTx; + schemeTx.SetWorkingDir(database); + schemeTx.SetOperationType(NKikimrSchemeOp::ESchemeOpAlterLogin); + auto& createUser = *schemeTx.MutableAlterLogin()->MutableCreateUser(); + createUser.SetUser(settings.UserName); + if (settings.Password) { + createUser.SetPassword(settings.Password); + } + + if (IsPrepare()) { + auto& phyQuery = *SessionCtx->Query().PreparingQuery->MutablePhysicalQuery(); + auto& phyTx = *phyQuery.AddTransactions(); + phyTx.SetType(NKqpProto::TKqpPhyTx::TYPE_SCHEME); + + phyTx.MutableSchemeOperation()->MutableCreateUser()->Swap(&schemeTx); + + TGenericResult result; + result.SetSuccess(); + createUserPromise.SetValue(result); + } else { + return Gateway->CreateUser(cluster, settings); + } + + return createUserPromise.GetFuture(); } TFuture<TGenericResult> AlterUser(const TString& cluster, const TAlterUserSettings& settings) override { - FORWARD_ENSURE_NO_PREPARE(AlterUser, cluster, settings); + CHECK_PREPARED_DDL(AlterUser); + + auto alterUserPromise = NewPromise<TGenericResult>(); + + TString database; + if (!SetDatabaseForLoginOperation(database, GetDomainLoginOnly(), GetDomainName(), GetDatabase())) { + return MakeFuture(ResultFromError<TGenericResult>("Couldn't get domain name")); + } + + NKikimrSchemeOp::TModifyScheme schemeTx; + schemeTx.SetWorkingDir(database); + schemeTx.SetOperationType(NKikimrSchemeOp::ESchemeOpAlterLogin); + auto& alterUser = *schemeTx.MutableAlterLogin()->MutableModifyUser(); + alterUser.SetUser(settings.UserName); + if (settings.Password) { + alterUser.SetPassword(settings.Password); + } + + if (IsPrepare()) { + auto& phyQuery = *SessionCtx->Query().PreparingQuery->MutablePhysicalQuery(); + auto& phyTx = *phyQuery.AddTransactions(); + phyTx.SetType(NKqpProto::TKqpPhyTx::TYPE_SCHEME); + + phyTx.MutableSchemeOperation()->MutableAlterUser()->Swap(&schemeTx); + TGenericResult result; + result.SetSuccess(); + alterUserPromise.SetValue(result); + } else { + return Gateway->AlterUser(cluster, settings); + } + + return alterUserPromise.GetFuture(); } TFuture<TGenericResult> DropUser(const TString& cluster, const TDropUserSettings& settings) override { - FORWARD_ENSURE_NO_PREPARE(DropUser, cluster, settings); + CHECK_PREPARED_DDL(DropUser); + + auto dropUserPromise = NewPromise<TGenericResult>(); + + TString database; + if (!SetDatabaseForLoginOperation(database, GetDomainLoginOnly(), GetDomainName(), GetDatabase())) { + return MakeFuture(ResultFromError<TGenericResult>("Couldn't get domain name")); + } + + NKikimrSchemeOp::TModifyScheme schemeTx; + schemeTx.SetWorkingDir(database); + schemeTx.SetOperationType(NKikimrSchemeOp::ESchemeOpAlterLogin); + auto& dropUser = *schemeTx.MutableAlterLogin()->MutableRemoveUser(); + dropUser.SetUser(settings.UserName); + dropUser.SetMissingOk(settings.Force); + + if (IsPrepare()) { + auto& phyQuery = *SessionCtx->Query().PreparingQuery->MutablePhysicalQuery(); + auto& phyTx = *phyQuery.AddTransactions(); + phyTx.SetType(NKqpProto::TKqpPhyTx::TYPE_SCHEME); + + phyTx.MutableSchemeOperation()->MutableAlterUser()->Swap(&schemeTx); + TGenericResult result; + result.SetSuccess(); + dropUserPromise.SetValue(result); + } else { + return Gateway->DropUser(cluster, settings); + } + + return dropUserPromise.GetFuture(); } TFuture<TGenericResult> UpsertObject(const TString& cluster, const TUpsertObjectSettings& settings) override { @@ -890,6 +982,14 @@ private: return Gateway->GetDatabase(); } + bool GetDomainLoginOnly() { + return Gateway->GetDomainLoginOnly(); + } + + TMaybe<TString> GetDomainName() { + return Gateway->GetDomainName(); + } + private: TIntrusivePtr<IKqpGateway> Gateway; TIntrusivePtr<TKikimrSessionContext> SessionCtx; diff --git a/ydb/core/kqp/provider/yql_kikimr_datasink.cpp b/ydb/core/kqp/provider/yql_kikimr_datasink.cpp index 52e7652c3e..9ad5225967 100644 --- a/ydb/core/kqp/provider/yql_kikimr_datasink.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_datasink.cpp @@ -794,7 +794,7 @@ public: .Done() .Ptr(); - } else if (mode == "drop" || mode == "drop_if_exists") { + } else if (mode == "drop" || mode == "drop_if_exists") { return MakeKiDropTable(node, settings, key, ctx); } else { YQL_ENSURE(false, "unknown TableScheme mode \"" << TString(mode) << "\""); diff --git a/ydb/core/kqp/provider/yql_kikimr_exec.cpp b/ydb/core/kqp/provider/yql_kikimr_exec.cpp index bd05a99d72..0974582bd6 100644 --- a/ydb/core/kqp/provider/yql_kikimr_exec.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_exec.cpp @@ -1684,10 +1684,6 @@ public: } if (auto maybeCreateUser = TMaybeNode<TKiCreateUser>(input)) { - if (!EnsureNotPrepare("CREATE USER", input->Pos(), SessionCtx->Query(), ctx)) { - return SyncError(); - } - auto requireStatus = RequireChild(*input, 0); if (requireStatus.Level != TStatus::Ok) { return SyncStatus(requireStatus); @@ -1696,8 +1692,7 @@ public: auto cluster = TString(maybeCreateUser.Cast().DataSink().Cluster()); TCreateUserSettings createUserSettings = ParseCreateUserSettings(maybeCreateUser.Cast()); - bool prepareOnly = SessionCtx->Query().PrepareOnly; - auto future = prepareOnly ? CreateDummySuccess() : Gateway->CreateUser(cluster, createUserSettings); + auto future = Gateway->CreateUser(cluster, createUserSettings); return WrapFuture(future, [](const IKikimrGateway::TGenericResult& res, const TExprNode::TPtr& input, TExprContext& ctx) { @@ -1708,10 +1703,6 @@ public: } if (auto maybeAlterUser = TMaybeNode<TKiAlterUser>(input)) { - if (!EnsureNotPrepare("ALTER USER", input->Pos(), SessionCtx->Query(), ctx)) { - return SyncError(); - } - auto requireStatus = RequireChild(*input, 0); if (requireStatus.Level != TStatus::Ok) { return SyncStatus(requireStatus); @@ -1720,8 +1711,7 @@ public: auto cluster = TString(maybeAlterUser.Cast().DataSink().Cluster()); TAlterUserSettings alterUserSettings = ParseAlterUserSettings(maybeAlterUser.Cast()); - bool prepareOnly = SessionCtx->Query().PrepareOnly; - auto future = prepareOnly ? CreateDummySuccess() : Gateway->AlterUser(cluster, alterUserSettings); + auto future = Gateway->AlterUser(cluster, alterUserSettings); return WrapFuture(future, [](const IKikimrGateway::TGenericResult& res, const TExprNode::TPtr& input, TExprContext& ctx) { @@ -1732,10 +1722,6 @@ public: } if (auto maybeDropUser = TMaybeNode<TKiDropUser>(input)) { - if (!EnsureNotPrepare("DROP USER", input->Pos(), SessionCtx->Query(), ctx)) { - return SyncError(); - } - auto requireStatus = RequireChild(*input, 0); if (requireStatus.Level != TStatus::Ok) { return SyncStatus(requireStatus); @@ -1744,8 +1730,7 @@ public: auto cluster = TString(maybeDropUser.Cast().DataSink().Cluster()); TDropUserSettings dropUserSettings = ParseDropUserSettings(maybeDropUser.Cast()); - bool prepareOnly = SessionCtx->Query().PrepareOnly; - auto future = prepareOnly ? CreateDummySuccess() : Gateway->DropUser(cluster, dropUserSettings); + auto future = Gateway->DropUser(cluster, dropUserSettings); return WrapFuture(future, [](const IKikimrGateway::TGenericResult& res, const TExprNode::TPtr& input, TExprContext& ctx) { diff --git a/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp b/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp index a409057c39..8fdcdb4d96 100644 --- a/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp +++ b/ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp @@ -3082,7 +3082,6 @@ Y_UNIT_TEST_SUITE(KqpScheme) { Y_UNIT_TEST(CreateAndDropUser) { TKikimrRunner kikimr; auto db = kikimr.GetTableClient(); - /* TODO: Fix flaky test in KIKIMR-18780 { // Drop non-existing user force auto query = TStringBuilder() << R"( @@ -3092,7 +3091,7 @@ Y_UNIT_TEST_SUITE(KqpScheme) { auto session = db.CreateSession().GetValueSync().GetSession(); auto result = session.ExecuteSchemeQuery(query).GetValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); - }*/ + } { auto query = TStringBuilder() << R"( --!syntax_v1 @@ -3121,7 +3120,6 @@ Y_UNIT_TEST_SUITE(KqpScheme) { auto result = session.ExecuteSchemeQuery(query).GetValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); } - /* TODO: Fix flaky test in KIKIMR-18780 { // Drop existing user force auto query = TStringBuilder() << R"( @@ -3131,7 +3129,16 @@ Y_UNIT_TEST_SUITE(KqpScheme) { auto session = db.CreateSession().GetValueSync().GetSession(); auto result = session.ExecuteSchemeQuery(query).GetValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); - }*/ + } + { + auto query = TStringBuilder() << R"( + --!syntax_v1 + CREATE USER user1 PASSWORD NULL; + )"; + auto session = db.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteSchemeQuery(query).GetValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + } { // Drop existing user auto query = TStringBuilder() << R"( 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 7eafe2cfb9..e6fcfa5955 100644 --- a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp +++ b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp @@ -584,6 +584,36 @@ Y_UNIT_TEST_SUITE(KqpQueryService) { SELECT * FROM TestDdl; )", TTxControl::BeginTx().CommitTx()).ExtractValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SCHEME_ERROR, result.GetIssues().ToString()); + + result = db.ExecuteQuery(R"( + CREATE USER user1 PASSWORD 'password1'; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + + result = db.ExecuteQuery(R"( + CREATE USER user1 PASSWORD 'password1'; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::PRECONDITION_FAILED, result.GetIssues().ToString()); + + result = db.ExecuteQuery(R"( + ALTER USER user1 WITH ENCRYPTED PASSWORD 'password3'; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + + result = db.ExecuteQuery(R"( + DROP USER user1; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + + result = db.ExecuteQuery(R"( + DROP USER user1; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::PRECONDITION_FAILED, result.GetIssues().ToString()); + + result = db.ExecuteQuery(R"( + DROP USER IF EXISTS user1; + )", TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); } Y_UNIT_TEST(DdlCache) { diff --git a/ydb/core/protos/flat_scheme_op.proto b/ydb/core/protos/flat_scheme_op.proto index 4e81e669c0..d1b50ed389 100644 --- a/ydb/core/protos/flat_scheme_op.proto +++ b/ydb/core/protos/flat_scheme_op.proto @@ -686,6 +686,7 @@ message TLoginModifyUser { message TLoginRemoveUser { optional string User = 1; + optional bool MissingOk = 2; } message TLoginCreateGroup { diff --git a/ydb/core/protos/kqp_physical.proto b/ydb/core/protos/kqp_physical.proto index e42211f402..47c9584532 100644 --- a/ydb/core/protos/kqp_physical.proto +++ b/ydb/core/protos/kqp_physical.proto @@ -386,6 +386,9 @@ message TKqpSchemeOperation { NKikimrSchemeOp.TModifyScheme DropTable = 2; NKikimrSchemeOp.TModifyScheme AlterTable = 3; NKikimrIndexBuilder.TIndexBuildSettings BuildOperation = 4; + NKikimrSchemeOp.TModifyScheme CreateUser = 5; + NKikimrSchemeOp.TModifyScheme AlterUser = 6; + NKikimrSchemeOp.TModifyScheme DropUser = 7; string Type = 9; uint64 Flags = 10; diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp index 374e255eed..f40820a46b 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp @@ -58,7 +58,10 @@ public: case NKikimrSchemeOp::TAlterLogin::kRemoveUser: { const auto& removeUser = alterLogin.GetRemoveUser(); const TString& user = removeUser.GetUser(); - auto response = context.SS->LoginProvider.RemoveUser({.User = user}); + auto response = context.SS->LoginProvider.RemoveUser({ + .User = user, + .MissingOk = removeUser.GetMissingOk() + }); if (response.Error) { result->SetStatus(NKikimrScheme::StatusPreconditionFailed, response.Error); } else { diff --git a/ydb/library/login/login.cpp b/ydb/library/login/login.cpp index f65d753c96..45bd462bf7 100644 --- a/ydb/library/login/login.cpp +++ b/ydb/library/login/login.cpp @@ -99,7 +99,9 @@ TLoginProvider::TRemoveUserResponse TLoginProvider::RemoveUser(const TRemoveUser auto itUserModify = Sids.find(request.User); if (itUserModify == Sids.end() || itUserModify->second.Type != ESidType::USER) { - response.Error = "User not found"; + if (!request.MissingOk) { + response.Error = "User not found"; + } return response; } diff --git a/ydb/library/login/login.h b/ydb/library/login/login.h index 3cd8d3856b..758520dc75 100644 --- a/ydb/library/login/login.h +++ b/ydb/library/login/login.h @@ -73,6 +73,7 @@ public: struct TRemoveUserRequest : TBasicRequest { TString User; + bool MissingOk; }; struct TRemoveUserResponse : TBasicResponse { diff --git a/ydb/library/yql/sql/pg/pg_sql.cpp b/ydb/library/yql/sql/pg/pg_sql.cpp index e52781ab37..d765e335a2 100644 --- a/ydb/library/yql/sql/pg/pg_sql.cpp +++ b/ydb/library/yql/sql/pg/pg_sql.cpp @@ -325,9 +325,9 @@ public: Statements.push_back(configSource); for (int i = 0; i < ListLength(raw); ++i) { - if (!ParseRawStmt(LIST_CAST_NTH(RawStmt, raw, i))) { - return nullptr; - } + if (!ParseRawStmt(LIST_CAST_NTH(RawStmt, raw, i))) { + return nullptr; + } } if (!Views.empty()) { |