aboutsummaryrefslogtreecommitdiffstats
path: root/yql
diff options
context:
space:
mode:
authorflown4qqqq <flown4qqqq@yandex-team.com>2025-01-24 00:47:07 +0300
committerflown4qqqq <flown4qqqq@yandex-team.com>2025-01-24 01:01:16 +0300
commitbf896a57c7a7ffb14ba93068a4c3efeab50dfb36 (patch)
tree38715f12c0ddf2192da62ab1a41f119c0293e1e2 /yql
parente0834724754ae9e26fd14e27027e69cc22d1939f (diff)
downloadydb-bf896a57c7a7ffb14ba93068a4c3efeab50dfb36.tar.gz
Add option 'HASH' into CREATE USER
Need for: <https://github.com/ydb-platform/ydb-rfc/blob/main/backup_fstek.md> ``` CREATE USER my_user HASH ' {"hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=", "salt": "U+tzBtgo06EBQCjlARA6Jg==", "type": "argon2id" }' ``` commit_hash:a0c695c2e2f7f794e5c4db978fe33a7bfea59e2c
Diffstat (limited to 'yql')
-rw-r--r--yql/essentials/sql/v1/SQLv1.g.in10
-rw-r--r--yql/essentials/sql/v1/SQLv1Antlr4.g.in10
-rw-r--r--yql/essentials/sql/v1/format/sql_format_ut.h4
-rw-r--r--yql/essentials/sql/v1/node.h26
-rw-r--r--yql/essentials/sql/v1/query.cpp166
-rw-r--r--yql/essentials/sql/v1/sql_query.cpp52
-rw-r--r--yql/essentials/sql/v1/sql_translation.cpp123
-rw-r--r--yql/essentials/sql/v1/sql_translation.h5
-rw-r--r--yql/essentials/sql/v1/sql_ut.cpp57
-rw-r--r--yql/essentials/sql/v1/sql_ut_antlr4.cpp59
10 files changed, 331 insertions, 181 deletions
diff --git a/yql/essentials/sql/v1/SQLv1.g.in b/yql/essentials/sql/v1/SQLv1.g.in
index 510afaa501..d28661e68e 100644
--- a/yql/essentials/sql/v1/SQLv1.g.in
+++ b/yql/essentials/sql/v1/SQLv1.g.in
@@ -828,8 +828,8 @@ alter_table_alter_index_action:
drop_table_stmt: DROP (TABLE | TABLESTORE | EXTERNAL TABLE) (IF EXISTS)? simple_table_ref;
-create_user_stmt: CREATE USER role_name create_user_option*;
-alter_user_stmt: ALTER USER role_name (WITH? create_user_option+ | RENAME TO role_name);
+create_user_stmt: CREATE USER role_name user_option*;
+alter_user_stmt: ALTER USER role_name (WITH? user_option+ | RENAME TO role_name);
create_group_stmt: CREATE GROUP role_name (WITH USER role_name (COMMA role_name)* COMMA?)?;
alter_group_stmt: ALTER GROUP role_name ((ADD|DROP) USER role_name (COMMA role_name)* COMMA? | RENAME TO role_name);
@@ -837,8 +837,12 @@ alter_group_stmt: ALTER GROUP role_name ((ADD|DROP) USER role_name (COMMA role_n
drop_role_stmt: DROP (USER|GROUP) (IF EXISTS)? role_name (COMMA role_name)* COMMA?;
role_name: an_id_or_type | bind_parameter;
-create_user_option: password_option | login_option;
+
+user_option: authentication_option | login_option;
+
+authentication_option: password_option | hash_option;
password_option: ENCRYPTED? PASSWORD expr;
+hash_option: HASH expr;
login_option: LOGIN | NOLOGIN;
grant_permissions_stmt: GRANT permission_name_target ON an_id_schema (COMMA an_id_schema)* TO role_name (COMMA role_name)* COMMA? (WITH GRANT OPTION)?;
diff --git a/yql/essentials/sql/v1/SQLv1Antlr4.g.in b/yql/essentials/sql/v1/SQLv1Antlr4.g.in
index 2ddfd0c748..3f4089a93b 100644
--- a/yql/essentials/sql/v1/SQLv1Antlr4.g.in
+++ b/yql/essentials/sql/v1/SQLv1Antlr4.g.in
@@ -827,8 +827,8 @@ alter_table_alter_index_action:
drop_table_stmt: DROP (TABLE | TABLESTORE | EXTERNAL TABLE) (IF EXISTS)? simple_table_ref;
-create_user_stmt: CREATE USER role_name create_user_option*;
-alter_user_stmt: ALTER USER role_name (WITH? create_user_option+ | RENAME TO role_name);
+create_user_stmt: CREATE USER role_name user_option*;
+alter_user_stmt: ALTER USER role_name (WITH? user_option+ | RENAME TO role_name);
create_group_stmt: CREATE GROUP role_name (WITH USER role_name (COMMA role_name)* COMMA?)?;
alter_group_stmt: ALTER GROUP role_name ((ADD|DROP) USER role_name (COMMA role_name)* COMMA? | RENAME TO role_name);
@@ -836,8 +836,12 @@ alter_group_stmt: ALTER GROUP role_name ((ADD|DROP) USER role_name (COMMA role_n
drop_role_stmt: DROP (USER|GROUP) (IF EXISTS)? role_name (COMMA role_name)* COMMA?;
role_name: an_id_or_type | bind_parameter;
-create_user_option: password_option | login_option;
+
+user_option: authentication_option | login_option;
+
+authentication_option: password_option | hash_option;
password_option: ENCRYPTED? PASSWORD expr;
+hash_option: HASH expr;
login_option: LOGIN | NOLOGIN;
grant_permissions_stmt: GRANT permission_name_target ON an_id_schema (COMMA an_id_schema)* TO role_name (COMMA role_name)* COMMA? (WITH GRANT OPTION)?;
diff --git a/yql/essentials/sql/v1/format/sql_format_ut.h b/yql/essentials/sql/v1/format/sql_format_ut.h
index a8fd6b7b3f..722863ecaa 100644
--- a/yql/essentials/sql/v1/format/sql_format_ut.h
+++ b/yql/essentials/sql/v1/format/sql_format_ut.h
@@ -80,6 +80,8 @@ Y_UNIT_TEST(CreateUser) {
{"use plato;cREATE USER user1 PASSWORD '123' NOLOGIN;", "USE plato;\n\nCREATE USER user1 PASSWORD '123' NOLOGIN;\n"},
{"use plato;CREATE USER user1 LOGIN;", "USE plato;\n\nCREATE USER user1 LOGIN;\n"},
{"use plato;CREATE USER user1 NOLOGIN;", "USE plato;\n\nCREATE USER user1 NOLOGIN;\n"},
+ {"use plato;CReATE UseR user1 HasH '{\"hash\": \"p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=\",\"salt\": \"U+tzBtgo06EBQCjlARA6Jg==\",\"type\": \"argon2id\"}'",
+ "USE plato;\n\nCREATE USER user1 HASH '{\"hash\": \"p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=\",\"salt\": \"U+tzBtgo06EBQCjlARA6Jg==\",\"type\": \"argon2id\"}';\n"},
};
TSetup setup;
@@ -103,6 +105,8 @@ Y_UNIT_TEST(AlterUser) {
{"use plato;alter user user encrypted password 'foo';","USE plato;\n\nALTER USER user ENCRYPTED PASSWORD 'foo';\n"},
{"use plato;alter user user with encrypted password 'foo';","USE plato;\n\nALTER USER user WITH ENCRYPTED PASSWORD 'foo';\n"},
{"use plato;ALTER USER user1 NOLOGIN;", "USE plato;\n\nALTER USER user1 NOLOGIN;\n"},
+ {"use plato;alter UseR user1 HasH '{\"hash\": \"p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=\",\"salt\": \"U+tzBtgo06EBQCjlARA6Jg==\",\"type\": \"argon2id\"}'",
+ "USE plato;\n\nALTER USER user1 HASH '{\"hash\": \"p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=\",\"salt\": \"U+tzBtgo06EBQCjlARA6Jg==\",\"type\": \"argon2id\"}';\n"},
};
TSetup setup;
diff --git a/yql/essentials/sql/v1/node.h b/yql/essentials/sql/v1/node.h
index e19245f695..c9402a2f97 100644
--- a/yql/essentials/sql/v1/node.h
+++ b/yql/essentials/sql/v1/node.h
@@ -1302,19 +1302,21 @@ namespace NSQLTranslationV1 {
};
struct TRoleParameters {
- TMaybe<TDeferredAtom> Password;
- bool IsPasswordEncrypted = false;
+ protected:
+ TRoleParameters() {}
+ public:
TVector<TDeferredAtom> Roles;
+ };
- enum class ETypeOfLogin {
- Undefined,
- Login,
- NoLogin
- };
-
- ETypeOfLogin CanLogin = ETypeOfLogin::Undefined;
+ struct TUserParameters : TRoleParameters {
+ TMaybe<TDeferredAtom> Password;
+ bool IsPasswordEncrypted = false;
+ std::optional<bool> CanLogin;
+ TMaybe<TDeferredAtom> Hash;
};
+ struct TCreateGroupParameters : TRoleParameters {};
+
struct TSequenceParameters {
bool MissingOk = false;
TMaybe<TDeferredAtom> StartValue;
@@ -1522,9 +1524,9 @@ namespace NSQLTranslationV1 {
);
// Implemented in query.cpp
- TNodePtr BuildCreateUser(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TMaybe<TRoleParameters>& params, TScopedStatePtr scoped);
- TNodePtr BuildCreateGroup(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TMaybe<TRoleParameters>& params, TScopedStatePtr scoped);
- TNodePtr BuildAlterUser(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TRoleParameters& params, TScopedStatePtr scoped);
+ TNodePtr BuildCreateGroup(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TMaybe<TCreateGroupParameters>& params, TScopedStatePtr scoped);
+ TNodePtr BuildControlUser(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name,
+ const TMaybe<TUserParameters>& params, TScopedStatePtr scoped, bool isCreateUser);
TNodePtr BuildRenameUser(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TDeferredAtom& newName, TScopedStatePtr scoped);
TNodePtr BuildAlterGroup(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TVector<TDeferredAtom>& toChange, bool isDrop,
TScopedStatePtr scoped);
diff --git a/yql/essentials/sql/v1/query.cpp b/yql/essentials/sql/v1/query.cpp
index a1323972c4..8ed6827cf3 100644
--- a/yql/essentials/sql/v1/query.cpp
+++ b/yql/essentials/sql/v1/query.cpp
@@ -842,7 +842,7 @@ TNodePtr BuildTableKeys(TPosition pos, const TString& service, const TDeferredAt
return new TPrepTableKeys(pos, service, cluster, func, args);
}
-class TInputOptions final: public TAstListNode {
+class TInputOptions final : public TAstListNode {
public:
TInputOptions(TPosition pos, const TTableHints& hints)
: TAstListNode(pos)
@@ -889,7 +889,7 @@ TNodePtr BuildInputOptions(TPosition pos, const TTableHints& hints) {
return new TInputOptions(pos, hints);
}
-class TIntoTableOptions: public TAstListNode {
+class TIntoTableOptions : public TAstListNode {
public:
TIntoTableOptions(TPosition pos, const TVector<TString>& columns, const TTableHints& hints)
: TAstListNode(pos)
@@ -944,7 +944,7 @@ TNodePtr BuildIntoTableOptions(TPosition pos, const TVector<TString>& eraseColum
return new TIntoTableOptions(pos, eraseColumns, hints);
}
-class TInputTablesNode final: public TAstListNode {
+class TInputTablesNode final : public TAstListNode {
public:
TInputTablesNode(TPosition pos, const TTableList& tables, bool inSubquery, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -1000,7 +1000,7 @@ TNodePtr BuildInputTables(TPosition pos, const TTableList& tables, bool inSubque
return new TInputTablesNode(pos, tables, inSubquery, scoped);
}
-class TCreateTableNode final: public TAstListNode {
+class TCreateTableNode final : public TAstListNode {
public:
TCreateTableNode(TPosition pos, const TTableRef& tr, bool existingOk, bool replaceIfExists, const TCreateTableParameters& params, TSourcePtr values, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -1314,7 +1314,7 @@ TNodePtr BuildCreateTable(TPosition pos, const TTableRef& tr, bool existingOk, b
return new TCreateTableNode(pos, tr, existingOk, replaceIfExists, params, std::move(values), scoped);
}
-class TAlterTableNode final: public TAstListNode {
+class TAlterTableNode final : public TAstListNode {
public:
TAlterTableNode(TPosition pos, const TTableRef& tr, const TAlterTableParameters& params, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -1544,7 +1544,7 @@ TNodePtr BuildAlterTable(TPosition pos, const TTableRef& tr, const TAlterTablePa
return new TAlterTableNode(pos, tr, params, scoped);
}
-class TDropTableNode final: public TAstListNode {
+class TDropTableNode final : public TAstListNode {
public:
TDropTableNode(TPosition pos, const TTableRef& tr, bool missingOk, ETableType tableType, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -1633,7 +1633,7 @@ static INode::TPtr CreateConsumerDesc(const TTopicConsumerDescription& desc, con
);
}
-class TCreateTopicNode final: public TAstListNode {
+class TCreateTopicNode final : public TAstListNode {
public:
TCreateTopicNode(TPosition pos, const TTopicRef& tr, const TCreateTopicParameters& params, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -1725,7 +1725,7 @@ TNodePtr BuildCreateTopic(
return new TCreateTopicNode(pos, tr, params, scoped);
}
-class TAlterTopicNode final: public TAstListNode {
+class TAlterTopicNode final : public TAstListNode {
public:
TAlterTopicNode(TPosition pos, const TTopicRef& tr, const TAlterTopicParameters& params, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -1847,7 +1847,7 @@ TNodePtr BuildAlterTopic(
return new TAlterTopicNode(pos, tr, params, scoped);
}
-class TDropTopicNode final: public TAstListNode {
+class TDropTopicNode final : public TAstListNode {
public:
TDropTopicNode(TPosition pos, const TTopicRef& tr, const TDropTopicParameters& params, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -1895,37 +1895,47 @@ TNodePtr BuildDropTopic(TPosition pos, const TTopicRef& tr, const TDropTopicPara
return new TDropTopicNode(pos, tr, params, scoped);
}
-class TCreateRole final: public TAstListNode {
+class TControlUser final : public TAstListNode {
public:
- TCreateRole(TPosition pos, bool isUser, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TMaybe<TRoleParameters>& params, TScopedStatePtr scoped)
+ TControlUser(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TMaybe<TUserParameters>& params, TScopedStatePtr scoped, bool IsCreateUser)
: TAstListNode(pos)
- , IsUser(isUser)
, Service(service)
, Cluster(cluster)
, Name(name)
, Params(params)
, Scoped(scoped)
+ , IsCreateUser(IsCreateUser)
{
FakeSource = BuildFakeSource(pos);
scoped->UseCluster(service, cluster);
}
- bool DoInit(TContext& ctx, ISource* src) override {
- Y_UNUSED(src);
+ bool DoInit(TContext& ctx, ISource*) override {
auto name = Name.Build();
TNodePtr password;
- if (Params && Params->Password) {
- password = Params->Password->Build();
+ TNodePtr hash;
+
+ if (Params) {
+ if (Params->Password) {
+ password = Params->Password->Build();
+ } else if (Params->Hash) {
+ hash = Params->Hash->Build();
+ }
}
+
TNodePtr cluster = Scoped->WrapCluster(Cluster, ctx);
- if (!name->Init(ctx, FakeSource.Get()) || !cluster->Init(ctx, FakeSource.Get())) {
- return false;
- }
- if (password && !password->Init(ctx, FakeSource.Get())) {
+ if (!name->Init(ctx, FakeSource.Get())
+ || !cluster->Init(ctx, FakeSource.Get())
+ || password && !password->Init(ctx, FakeSource.Get())
+ || hash && !hash->Init(ctx, FakeSource.Get())
+ )
+ {
return false;
}
+ auto options = Y(Q(Y(Q("mode"), Q(IsCreateUser ? "createUser" : "alterUser")))) ;
+
TVector<TNodePtr> roles;
if (Params && !Params->Roles.empty()) {
for (auto& item : Params->Roles) {
@@ -1934,9 +1944,10 @@ public:
return false;
}
}
+
+ options = L(options, Q(Y(Q("roles"), Q(new TAstListNodeImpl(Pos, std::move(roles))))));
}
- auto options = Y(Q(Y(Q("mode"), Q(IsUser ? "createUser" : "createGroup"))));
if (Params) {
if (Params->IsPasswordEncrypted) {
options = L(options, Q(Y(Q("passwordEncrypted"))));
@@ -1944,17 +1955,15 @@ public:
if (Params->Password) {
options = L(options, Q(Y(Q("password"), password)));
+ } else if (Params->Hash) {
+ options = L(options, Q(Y(Q("hash"), hash)));
} else {
options = L(options, Q(Y(Q("nullPassword"))));
}
- if (!Params->Roles.empty()) {
- options = L(options, Q(Y(Q("roles"), Q(new TAstListNodeImpl(Pos, std::move(roles))))));
- }
-
- if (Params->CanLogin == TRoleParameters::ETypeOfLogin::Login) {
+ if (Params->CanLogin.has_value() && Params->CanLogin.value() || !Params->CanLogin.has_value() && IsCreateUser) {
options = L(options, Q(Y(Q("login"))));
- } else if (Params->CanLogin == TRoleParameters::ETypeOfLogin::NoLogin) {
+ } else {
options = L(options, Q(Y(Q("noLogin"))));
}
}
@@ -1971,29 +1980,31 @@ public:
TPtr DoClone() const final {
return {};
}
+
private:
- const bool IsUser;
const TString Service;
TDeferredAtom Cluster;
TDeferredAtom Name;
- const TMaybe<TRoleParameters> Params;
+ const TMaybe<TUserParameters> Params;
TScopedStatePtr Scoped;
TSourcePtr FakeSource;
+ bool IsCreateUser;
};
-TNodePtr BuildCreateUser(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TMaybe<TRoleParameters>& params, TScopedStatePtr scoped) {
- bool isUser = true;
- return new TCreateRole(pos, isUser, service, cluster, name, params, scoped);
-}
-
-TNodePtr BuildCreateGroup(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TMaybe<TRoleParameters>& params, TScopedStatePtr scoped) {
- bool isUser = false;
- return new TCreateRole(pos, isUser, service, cluster, name, params, scoped);
+TNodePtr BuildControlUser( TPosition pos,
+ const TString& service,
+ const TDeferredAtom& cluster,
+ const TDeferredAtom& name,
+ const TMaybe<TUserParameters>& params,
+ TScopedStatePtr scoped,
+ bool isCreateUser)
+{
+ return new TControlUser(pos, service, cluster, name, params, scoped, isCreateUser);
}
-class TAlterUser final: public TAstListNode {
+class TCreateGroup final : public TAstListNode {
public:
- TAlterUser(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TRoleParameters& params, TScopedStatePtr scoped)
+ TCreateGroup(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TMaybe<TCreateGroupParameters>& params, TScopedStatePtr scoped)
: TAstListNode(pos)
, Service(service)
, Cluster(cluster)
@@ -2005,42 +2016,26 @@ public:
scoped->UseCluster(service, cluster);
}
- bool DoInit(TContext& ctx, ISource* src) override {
- Y_UNUSED(src);
- auto name = Name.Build();
- TNodePtr password;
- if (Params.Password) {
- password = Params.Password->Build();
- }
- TNodePtr cluster = Scoped->WrapCluster(Cluster, ctx);
-
- if (!name->Init(ctx, FakeSource.Get()) || !cluster->Init(ctx, FakeSource.Get())) {
- return false;
- }
- if (password && !password->Init(ctx, FakeSource.Get())) {
- return false;
- }
+ bool DoInit(TContext& ctx, ISource*) override {
+ auto options = Y(Q(Y(Q("mode"), Q("createGroup"))));
- auto options = Y(Q(Y(Q("mode"), Q("alterUser"))));
- if (Params.IsPasswordEncrypted) {
- options = L(options, Q(Y(Q("passwordEncrypted"))));
- }
+ TVector<TNodePtr> roles;
+ if (Params && !Params->Roles.empty()) {
+ for (auto& item : Params->Roles) {
+ roles.push_back(item.Build());
+ if (!roles.back()->Init(ctx, FakeSource.Get())) {
+ return false;
+ }
+ }
- if (Params.Password) {
- options = L(options, Q(Y(Q("password"), password)));
- } else {
- options = L(options, Q(Y(Q("nullPassword"))));
+ options = L(options, Q(Y(Q("roles"), Q(new TAstListNodeImpl(Pos, std::move(roles))))));
}
- if (Params.CanLogin == TRoleParameters::ETypeOfLogin::Login) {
- options = L(options, Q(Y(Q("login"))));
- } else if (Params.CanLogin == TRoleParameters::ETypeOfLogin::NoLogin) {
- options = L(options, Q(Y(Q("noLogin"))));
- }
+ TNodePtr cluster = Scoped->WrapCluster(Cluster, ctx);
Add("block", Q(Y(
Y("let", "sink", Y("DataSink", BuildQuotedAtom(Pos, Service), cluster)),
- Y("let", "world", Y(TString(WriteName), "world", "sink", Y("Key", Q(Y(Q("role"), Y("String", name)))), Y("Void"), Q(options))),
+ Y("let", "world", Y(TString(WriteName), "world", "sink", Y("Key", Q(Y(Q("role"), Y("String", Name.Build())))), Y("Void"), Q(options))),
Y("return", ctx.PragmaAutoCommit ? Y(TString(CommitName), "world", "sink") : AstNode("world"))
)));
@@ -2050,20 +2045,21 @@ public:
TPtr DoClone() const final {
return {};
}
+
private:
const TString Service;
TDeferredAtom Cluster;
TDeferredAtom Name;
- const TRoleParameters Params;
+ const TMaybe<TCreateGroupParameters> Params;
TScopedStatePtr Scoped;
TSourcePtr FakeSource;
};
-TNodePtr BuildAlterUser(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TRoleParameters& params, TScopedStatePtr scoped) {
- return new TAlterUser(pos, service, cluster, name, params, scoped);
+TNodePtr BuildCreateGroup(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TMaybe<TCreateGroupParameters>& params, TScopedStatePtr scoped) {
+ return new TCreateGroup(pos, service, cluster, name, params, scoped);
}
-class TAlterSequence final: public TAstListNode {
+class TAlterSequence final : public TAstListNode {
public:
TAlterSequence(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TString& id, const TSequenceParameters& params, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -2167,7 +2163,7 @@ TNodePtr BuildAlterSequence(TPosition pos, const TString& service, const TDeferr
return new TAlterSequence(pos, service, cluster, id, params, scoped);
}
-class TRenameRole final: public TAstListNode {
+class TRenameRole final : public TAstListNode {
public:
TRenameRole(TPosition pos, bool isUser, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TDeferredAtom& newName, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -2230,7 +2226,7 @@ TNodePtr BuildRenameGroup(TPosition pos, const TString& service, const TDeferred
return new TRenameRole(pos, isUser, service, cluster, name, newName, scoped);
}
-class TAlterGroup final: public TAstListNode {
+class TAlterGroup final : public TAstListNode {
public:
TAlterGroup(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TDeferredAtom& name, const TVector<TDeferredAtom>& toChange, bool isDrop, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -2293,7 +2289,7 @@ TNodePtr BuildAlterGroup(TPosition pos, const TString& service, const TDeferredA
return new TAlterGroup(pos, service, cluster, name, toChange, isDrop, scoped);
}
-class TDropRoles final: public TAstListNode {
+class TDropRoles final : public TAstListNode {
public:
TDropRoles(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TVector<TDeferredAtom>& toDrop, bool isUser, bool missingOk, TScopedStatePtr scoped)
: TAstListNode(pos)
@@ -2517,7 +2513,7 @@ private:
}; // TAsyncReplication
-class TCreateAsyncReplication final: public TAsyncReplication {
+class TCreateAsyncReplication final : public TAsyncReplication {
public:
explicit TCreateAsyncReplication(TPosition pos, const TString& id,
std::vector<std::pair<TString, TString>>&& targets,
@@ -2571,7 +2567,7 @@ TNodePtr BuildCreateAsyncReplication(TPosition pos, const TString& id,
return new TCreateAsyncReplication(pos, id, std::move(targets), std::move(settings), context);
}
-class TDropAsyncReplication final: public TAsyncReplication {
+class TDropAsyncReplication final : public TAsyncReplication {
public:
explicit TDropAsyncReplication(TPosition pos, const TString& id, bool cascade, const TObjectOperatorContext& context)
: TAsyncReplication(pos, id, cascade ? "dropCascade" : "drop", context)
@@ -2589,7 +2585,7 @@ TNodePtr BuildDropAsyncReplication(TPosition pos, const TString& id, bool cascad
return new TDropAsyncReplication(pos, id, cascade, context);
}
-class TAlterAsyncReplication final: public TAsyncReplication {
+class TAlterAsyncReplication final : public TAsyncReplication {
public:
explicit TAlterAsyncReplication(TPosition pos, const TString& id,
std::map<TString, TNodePtr>&& settings,
@@ -2805,7 +2801,7 @@ static const TMap<EWriteColumnMode, TString> columnModeToStrMapKikimr {
{EWriteColumnMode::DeleteOn, "delete_on"},
};
-class TWriteTableNode final: public TAstListNode {
+class TWriteTableNode final : public TAstListNode {
public:
TWriteTableNode(TPosition pos, const TString& label, const TTableRef& table, EWriteColumnMode mode,
TNodePtr options, TScopedStatePtr scoped)
@@ -2876,7 +2872,7 @@ TNodePtr BuildWriteTable(TPosition pos, const TString& label, const TTableRef& t
return new TWriteTableNode(pos, label, table, mode, std::move(options), scoped);
}
-class TClustersSinkOperationBase: public TAstListNode {
+class TClustersSinkOperationBase : public TAstListNode {
protected:
TClustersSinkOperationBase(TPosition pos)
: TAstListNode(pos)
@@ -2936,7 +2932,7 @@ TNodePtr BuildRollbackClusters(TPosition pos) {
return new TRollbackClustersNode(pos);
}
-class TWriteResultNode final: public TAstListNode {
+class TWriteResultNode final : public TAstListNode {
public:
TWriteResultNode(TPosition pos, const TString& label, TNodePtr settings)
: TAstListNode(pos)
@@ -2972,7 +2968,7 @@ TNodePtr BuildWriteResult(TPosition pos, const TString& label, TNodePtr settings
return new TWriteResultNode(pos, label, settings);
}
-class TYqlProgramNode: public TAstListNode {
+class TYqlProgramNode : public TAstListNode {
public:
TYqlProgramNode(TPosition pos, const TVector<TNodePtr>& blocks, bool topLevel, TScopedStatePtr scoped, bool useSeq)
: TAstListNode(pos)
@@ -3310,7 +3306,7 @@ TNodePtr BuildQuery(TPosition pos, const TVector<TNodePtr>& blocks, bool topLeve
return new TYqlProgramNode(pos, blocks, topLevel, scoped, useSeq);
}
-class TPragmaNode final: public INode {
+class TPragmaNode final : public INode {
public:
TPragmaNode(TPosition pos, const TString& prefix, const TString& name, const TVector<TDeferredAtom>& values, bool valueDefault)
: INode(pos)
@@ -3394,7 +3390,7 @@ TNodePtr BuildPragma(TPosition pos, const TString& prefix, const TString& name,
return new TPragmaNode(pos, prefix, name, values, valueDefault);
}
-class TSqlLambda final: public TAstListNode {
+class TSqlLambda final : public TAstListNode {
public:
TSqlLambda(TPosition pos, TVector<TString>&& args, TVector<TNodePtr>&& exprSeq)
: TAstListNode(pos)
@@ -3553,7 +3549,7 @@ TNodePtr BuildWorldForNode(TPosition pos, TNodePtr list, TNodePtr bodyNode, TNod
return new TWorldFor(pos, list, bodyNode, elseNode, isEvaluate, isParallel);
}
-class TAnalyzeNode final: public TAstListNode {
+class TAnalyzeNode final : public TAstListNode {
public:
TAnalyzeNode(TPosition pos, const TString& service, const TDeferredAtom& cluster, const TAnalyzeParams& params, TScopedStatePtr scoped)
: TAstListNode(pos)
diff --git a/yql/essentials/sql/v1/sql_query.cpp b/yql/essentials/sql/v1/sql_query.cpp
index a04ce65986..7510acc467 100644
--- a/yql/essentials/sql/v1/sql_query.cpp
+++ b/yql/essentials/sql/v1/sql_query.cpp
@@ -648,7 +648,7 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core&
break;
}
case TRule_sql_stmt_core::kAltSqlStmtCore22: {
- // create_user_stmt: CREATE USER role_name (create_user_option)*;
+ // create_user_stmt: CREATE USER role_name (user_option)*;
Ctx.BodyPart();
auto& node = core.GetAlt_sql_stmt_core22().GetRule_create_user_stmt1();
@@ -668,27 +668,26 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core&
return false;
}
- TMaybe<TRoleParameters> roleParams;
+ TMaybe<TUserParameters> createUserParams;
const auto& options = node.GetBlock4();
- {
- roleParams.ConstructInPlace();
- std::vector<TRule_create_user_option> opts;
- opts.reserve(options.size());
- for (const auto& opt : options) {
- opts.push_back(opt.GetRule_create_user_option1());
- }
+ createUserParams.ConstructInPlace();
+ std::vector<TRule_user_option> opts;
+ opts.reserve(options.size());
+ for (const auto& opt : options) {
+ opts.push_back(opt.GetRule_user_option1());
+ }
- if (!RoleParameters(opts, *roleParams)) {
- return false;
- }
+ bool isCreateUser = true;
+ if (!UserParameters(opts, *createUserParams, isCreateUser)) {
+ return false;
}
- AddStatementToBlocks(blocks, BuildCreateUser(pos, service, cluster, roleName, roleParams, Ctx.Scoped));
+ AddStatementToBlocks(blocks, BuildControlUser(pos, service, cluster, roleName, createUserParams, Ctx.Scoped, isCreateUser));
break;
}
case TRule_sql_stmt_core::kAltSqlStmtCore23: {
- // alter_user_stmt: ALTER USER role_name (WITH? create_user_option+ | RENAME TO role_name);
+ // alter_user_stmt: ALTER USER role_name (WITH? user_option+ | RENAME TO role_name);
Ctx.BodyPart();
auto& node = core.GetAlt_sql_stmt_core23().GetRule_alter_user_stmt1();
@@ -713,19 +712,20 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core&
TNodePtr stmt;
switch (node.GetBlock4().Alt_case()) {
case TRule_alter_user_stmt_TBlock4::kAlt1: {
- TRoleParameters roleParams;
+ TUserParameters alterUserParams;
auto options = node.GetBlock4().GetAlt1().GetBlock2();
- std::vector<TRule_create_user_option> opts;
+ std::vector<TRule_user_option> opts;
opts.reserve(options.size());
for (const auto& opt : options) {
- opts.push_back(opt.GetRule_create_user_option1());
+ opts.push_back(opt.GetRule_user_option1());
}
- if (!RoleParameters(opts, roleParams)) {
+ bool isCreateUser = false;
+ if (!UserParameters(opts, alterUserParams, isCreateUser)) {
return false;
}
- stmt = BuildAlterUser(pos, service, cluster, roleName, roleParams, Ctx.Scoped);
+ stmt = BuildControlUser(pos, service, cluster, roleName, alterUserParams, Ctx.Scoped, isCreateUser);
break;
}
case TRule_alter_user_stmt_TBlock4::kAlt2: {
@@ -734,7 +734,7 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core&
if (!RoleNameClause(node.GetBlock4().GetAlt2().GetRule_role_name3(), tgtRoleName, allowSystemRoles)) {
return false;
}
- stmt = BuildRenameUser(pos, service, cluster, roleName, tgtRoleName,Ctx.Scoped);
+ stmt = BuildRenameUser(pos, service, cluster, roleName, tgtRoleName, Ctx.Scoped);
break;
}
case TRule_alter_user_stmt_TBlock4::ALT_NOT_SET:
@@ -765,25 +765,25 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core&
return false;
}
- TRoleParameters roleParams;
+ TCreateGroupParameters createGroupParams;
if (node.HasBlock4()) {
auto& addDropNode = node.GetBlock4();
TVector<TDeferredAtom> roles;
bool allowSystemRoles = false;
- roleParams.Roles.emplace_back();
- if (!RoleNameClause(addDropNode.GetRule_role_name3(), roleParams.Roles.back(), allowSystemRoles)) {
+ createGroupParams.Roles.emplace_back();
+ if (!RoleNameClause(addDropNode.GetRule_role_name3(), createGroupParams.Roles.back(), allowSystemRoles)) {
return false;
}
for (auto& item : addDropNode.GetBlock4()) {
- roleParams.Roles.emplace_back();
- if (!RoleNameClause(item.GetRule_role_name2(), roleParams.Roles.back(), allowSystemRoles)) {
+ createGroupParams.Roles.emplace_back();
+ if (!RoleNameClause(item.GetRule_role_name2(), createGroupParams.Roles.back(), allowSystemRoles)) {
return false;
}
}
}
- AddStatementToBlocks(blocks, BuildCreateGroup(pos, service, cluster, roleName, roleParams, Ctx.Scoped));
+ AddStatementToBlocks(blocks, BuildCreateGroup(pos, service, cluster, roleName, createGroupParams, Ctx.Scoped));
break;
}
case TRule_sql_stmt_core::kAltSqlStmtCore25: {
diff --git a/yql/essentials/sql/v1/sql_translation.cpp b/yql/essentials/sql/v1/sql_translation.cpp
index a4c55cad71..1c60897886 100644
--- a/yql/essentials/sql/v1/sql_translation.cpp
+++ b/yql/essentials/sql/v1/sql_translation.cpp
@@ -3818,64 +3818,113 @@ bool TSqlTranslation::RoleNameClause(const TRule_role_name& node, TDeferredAtom&
return true;
}
-bool TSqlTranslation::RoleParameters(const std::vector<TRule_create_user_option>& optionsList, TRoleParameters& result) {
- enum class ECreateUserOption {
+bool TSqlTranslation::PasswordParameter(const TRule_password_option& passwordOption, TUserParameters& result) {
+ // password_option: ENCRYPTED? PASSWORD expr;
+ TSqlExpression expr(Ctx, Mode);
+ TNodePtr password = expr.Build(passwordOption.GetRule_expr3());
+ if (!password) {
+ Error() << "Couldn't parse the password";
+ return false;
+ }
+
+ result.IsPasswordEncrypted = passwordOption.HasBlock1();
+ if (!password->IsNull()) {
+ result.Password = MakeAtomFromExpression(Ctx.Pos(), Ctx, password);
+ }
+
+ return true;
+}
+
+bool TSqlTranslation::HashParameter(const TRule_hash_option& hashOption, TUserParameters& result) {
+ // hash_option: HASH expr;
+ TSqlExpression expr(Ctx, Mode);
+ TNodePtr hash = expr.Build(hashOption.GetRule_expr2());
+
+ if (!hash) {
+ Error() << "Couldn't parse the hash of password";
+ return false;
+ }
+
+ if (!hash->IsNull()) {
+ result.Hash = MakeAtomFromExpression(Ctx.Pos(), Ctx, hash);
+ }
+
+ return true;
+}
+
+void TSqlTranslation::LoginParameter(const TRule_login_option& loginOption, std::optional<bool>& canLogin) {
+ // login_option: LOGIN | NOLOGIN;
+
+ auto token = loginOption.GetToken1().GetId();
+ if (IS_TOKEN(token, LOGIN)) {
+ canLogin = true;
+ } else if (IS_TOKEN(token, NOLOGIN)) {
+ canLogin = false;
+ } else {
+ Y_ABORT("You should change implementation according to grammar changes");
+ }
+}
+
+bool TSqlTranslation::UserParameters(const std::vector<TRule_user_option>& optionsList, TUserParameters& result, bool isCreateUser) {
+ enum class EUserOption {
Login,
- Password
+ Authentication
};
- std::set<ECreateUserOption> used = {};
+ std::set<EUserOption> used;
- auto ParseCreateUserOption = [&used, this](const TRule_create_user_option& option, TRoleParameters& result) -> bool {
- // create_user_option: password_option | login_option;
- // password_option: ENCRYPTED? PASSWORD expr;
- // login_option: LOGIN | NOLOGIN;
+ auto ParseUserOption = [&used, this](const TRule_user_option& option, TUserParameters& result) -> bool {
+ // user_option: authentication_option | login_option;
+ // authentication_option: password_option | hash_option;
switch (option.Alt_case()) {
- case TRule_create_user_option::kAltCreateUserOption1:
+ case TRule_user_option::kAltUserOption1:
{
- TSqlExpression expr(Ctx, Mode);
- TNodePtr password = expr.Build(option.GetAlt_create_user_option1().GetRule_password_option1().GetRule_expr3());
- if (!password) {
- Error() << "Couldn't parse the password";
+ if (used.contains(EUserOption::Authentication)) {
+ Error() << "Conflicting or redundant options";
return false;
}
- result.IsPasswordEncrypted = option.GetAlt_create_user_option1().GetRule_password_option1().HasBlock1();
- if (!password->IsNull()) {
- result.Password = MakeAtomFromExpression(Ctx.Pos(), Ctx, password);
- }
+ used.insert(EUserOption::Authentication);
- if (used.contains(ECreateUserOption::Password)) {
- Error() << "Conflicting or redundant options";
- return false;
- }
+ const auto& authenticationOption = option.GetAlt_user_option1().GetRule_authentication_option1();
+
+ switch (authenticationOption.Alt_case()) {
+ case TRule_authentication_option::kAltAuthenticationOption1: {
+ if (!PasswordParameter(authenticationOption.GetAlt_authentication_option1().GetRule_password_option1(), result)){
+ return false;
+ }
- used.insert(ECreateUserOption::Password);
+ break;
+ }
+ case TRule_authentication_option::kAltAuthenticationOption2: {
+ if (!HashParameter(authenticationOption.GetAlt_authentication_option2().GetRule_hash_option1(), result)){
+ return false;
+ }
+
+ break;
+ }
+ case TRule_authentication_option::ALT_NOT_SET: {
+ Y_ABORT("You should change implementation according to grammar changes");
+ }
+ }
break;
}
- case TRule_create_user_option::kAltCreateUserOption2:
+ case TRule_user_option::kAltUserOption2:
{
- if (used.contains(ECreateUserOption::Login)) {
+ if (used.contains(EUserOption::Login)) {
Error() << "Conflicting or redundant options";
return false;
}
- used.insert(ECreateUserOption::Login);
+ used.insert(EUserOption::Login);
- const auto token = option.GetAlt_create_user_option2().GetRule_login_option1().GetToken1().GetId();
- if (IS_TOKEN(token, LOGIN)) {
- result.CanLogin = TRoleParameters::ETypeOfLogin::Login;
- } else if (IS_TOKEN(token, NOLOGIN)) {
- result.CanLogin = TRoleParameters::ETypeOfLogin::NoLogin;
- } else {
- Y_ABORT("You should change implementation according to grammar changes");
- }
+ LoginParameter(option.GetAlt_user_option2().GetRule_login_option1(), result.CanLogin);
break;
}
- case TRule_create_user_option::ALT_NOT_SET:
+ case TRule_user_option::ALT_NOT_SET:
{
Y_ABORT("You should change implementation according to grammar changes");
}
@@ -3884,10 +3933,12 @@ bool TSqlTranslation::RoleParameters(const std::vector<TRule_create_user_option>
return true;
};
- result = TRoleParameters{};
+ if (isCreateUser) {
+ result.CanLogin = true;
+ }
for (const auto& option : optionsList) {
- if (!ParseCreateUserOption(option, result)) {
+ if (!ParseUserOption(option, result)) {
return false;
}
}
diff --git a/yql/essentials/sql/v1/sql_translation.h b/yql/essentials/sql/v1/sql_translation.h
index 74b78ae330..a052f1979b 100644
--- a/yql/essentials/sql/v1/sql_translation.h
+++ b/yql/essentials/sql/v1/sql_translation.h
@@ -242,7 +242,10 @@ protected:
bool ParseResourcePoolClassifierSettings(std::map<TString, TDeferredAtom>& result, const TRule_with_table_settings& settings);
bool ParseResourcePoolClassifierSettings(std::map<TString, TDeferredAtom>& result, std::set<TString>& toReset, const TRule_alter_resource_pool_classifier_action& alterAction);
bool RoleNameClause(const TRule_role_name& node, TDeferredAtom& result, bool allowSystemRoles);
- bool RoleParameters(const std::vector<TRule_create_user_option>& optionsList, TRoleParameters& result);
+ bool PasswordParameter(const TRule_password_option& passwordOption, TUserParameters& result);
+ bool HashParameter(const TRule_hash_option& hashOption, TUserParameters& result);
+ void LoginParameter(const TRule_login_option& loginOption, std::optional<bool>& canLogin);
+ bool UserParameters(const std::vector<TRule_user_option>& optionsList, TUserParameters& result, bool isCreateUser);
bool PermissionNameClause(const TRule_permission_name_target& node, TVector<TDeferredAtom>& result, bool withGrantOption);
bool PermissionNameClause(const TRule_permission_name& node, TDeferredAtom& result);
bool PermissionNameClause(const TRule_permission_id& node, TDeferredAtom& result);
diff --git a/yql/essentials/sql/v1/sql_ut.cpp b/yql/essentials/sql/v1/sql_ut.cpp
index 9baf35f8f4..6bdd2c7e44 100644
--- a/yql/essentials/sql/v1/sql_ut.cpp
+++ b/yql/essentials/sql/v1/sql_ut.cpp
@@ -5017,7 +5017,6 @@ select FormatType($f());
)");
UNIT_ASSERT(reqCreateUser.IsOk());
- UNIT_ASSERT(reqCreateUser.Root);
auto reqAlterUser = SqlToYql(R"(
USE plato;
@@ -5033,7 +5032,6 @@ select FormatType($f());
)");
UNIT_ASSERT(reqPasswordAndLogin.IsOk());
- UNIT_ASSERT(reqPasswordAndLogin.Root);
auto reqPasswordAndNoLogin = SqlToYql(R"(
USE plato;
@@ -5041,7 +5039,6 @@ select FormatType($f());
)");
UNIT_ASSERT(reqPasswordAndNoLogin.IsOk());
- UNIT_ASSERT(reqPasswordAndNoLogin.Root);
auto reqLogin = SqlToYql(R"(
USE plato;
@@ -5049,7 +5046,6 @@ select FormatType($f());
)");
UNIT_ASSERT(reqLogin.IsOk());
- UNIT_ASSERT(reqLogin.Root);
auto reqNoLogin = SqlToYql(R"(
USE plato;
@@ -5057,7 +5053,6 @@ select FormatType($f());
)");
UNIT_ASSERT(reqNoLogin.IsOk());
- UNIT_ASSERT(reqNoLogin.Root);
auto reqLoginNoLogin = SqlToYql(R"(
USE plato;
@@ -5074,7 +5069,6 @@ select FormatType($f());
)");
UNIT_ASSERT(reqAlterLoginNoLogin.IsOk());
- UNIT_ASSERT(reqAlterLoginNoLogin.Root);
auto reqAlterLoginNoLoginWithPassword = SqlToYql(R"(
USE plato;
@@ -5083,7 +5077,56 @@ select FormatType($f());
)");
UNIT_ASSERT(reqAlterLoginNoLoginWithPassword.IsOk());
- UNIT_ASSERT(reqAlterLoginNoLoginWithPassword.Root);
+ }
+
+ Y_UNIT_TEST(CreateUserWithHash) {
+ auto reqCreateUser = SqlToYql(R"(
+ USE plato;
+ CREATE USER user1 HASH '{
+ "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
+ "salt": "U+tzBtgo06EBQCjlARA6Jg==",
+ "type": "argon2id"
+ }';
+ )");
+
+ UNIT_ASSERT(reqCreateUser.IsOk());
+
+ auto reqCreateUserWithNoLogin = SqlToYql(R"(
+ USE plato;
+ CREATE USER user1 HASH '{
+ "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
+ "salt": "U+tzBtgo06EBQCjlARA6Jg==",
+ "type": "argon2id"
+ }'
+ NOLOGIN;
+ )");
+
+ UNIT_ASSERT(reqCreateUserWithNoLogin.IsOk());
+
+ auto reqCreateUserWithPassword = SqlToYql(R"(
+ USE plato;
+ CREATE USER user1 HASH '{
+ "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
+ "salt": "U+tzBtgo06EBQCjlARA6Jg==",
+ "type": "argon2id"
+ }'
+ PASSWORD '123';
+ )");
+
+ UNIT_ASSERT(!reqCreateUserWithPassword.IsOk());
+ UNIT_ASSERT_STRING_CONTAINS(reqCreateUserWithPassword.Issues.ToString(), "Error: Conflicting or redundant options");
+
+ auto reqAlterUser = SqlToYql(R"(
+ USE plato;
+ CREATE USER user1;
+ ALTER USER user1 HASH '{
+ "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
+ "salt": "U+tzBtgo06EBQCjlARA6Jg==",
+ "type": "argon2id"
+ }';
+ )");
+
+ UNIT_ASSERT(reqAlterUser.IsOk());
}
Y_UNIT_TEST(CreateAlterUserWithoutCluster) {
diff --git a/yql/essentials/sql/v1/sql_ut_antlr4.cpp b/yql/essentials/sql/v1/sql_ut_antlr4.cpp
index 05e85605ef..4b1233bfee 100644
--- a/yql/essentials/sql/v1/sql_ut_antlr4.cpp
+++ b/yql/essentials/sql/v1/sql_ut_antlr4.cpp
@@ -483,7 +483,6 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
)");
UNIT_ASSERT(reqCreateUser.IsOk());
- UNIT_ASSERT(reqCreateUser.Root);
auto reqAlterUser = SqlToYql(R"(
USE plato;
@@ -491,7 +490,7 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
)");
UNIT_ASSERT(!reqAlterUser.IsOk());
- UNIT_ASSERT_STRING_CONTAINS(reqAlterUser.Issues.ToString(), "Error: mismatched input ';' expecting {ENCRYPTED, LOGIN, NOLOGIN, PASSWORD, RENAME, WITH}");
+ UNIT_ASSERT_STRING_CONTAINS(reqAlterUser.Issues.ToString(), "Error: mismatched input ';' expecting {ENCRYPTED, HASH, LOGIN, NOLOGIN, PASSWORD, RENAME, WITH}");
auto reqPasswordAndLogin = SqlToYql(R"(
USE plato;
@@ -499,7 +498,6 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
)");
UNIT_ASSERT(reqPasswordAndLogin.IsOk());
- UNIT_ASSERT(reqPasswordAndLogin.Root);
auto reqPasswordAndNoLogin = SqlToYql(R"(
USE plato;
@@ -507,7 +505,6 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
)");
UNIT_ASSERT(reqPasswordAndNoLogin.IsOk());
- UNIT_ASSERT(reqPasswordAndNoLogin.Root);
auto reqLogin = SqlToYql(R"(
USE plato;
@@ -515,7 +512,6 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
)");
UNIT_ASSERT(reqLogin.IsOk());
- UNIT_ASSERT(reqLogin.Root);
auto reqNoLogin = SqlToYql(R"(
USE plato;
@@ -523,7 +519,6 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
)");
UNIT_ASSERT(reqNoLogin.IsOk());
- UNIT_ASSERT(reqNoLogin.Root);
auto reqLoginNoLogin = SqlToYql(R"(
USE plato;
@@ -540,7 +535,6 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
)");
UNIT_ASSERT(reqAlterLoginNoLogin.IsOk());
- UNIT_ASSERT(reqAlterLoginNoLogin.Root);
auto reqAlterLoginNoLoginWithPassword = SqlToYql(R"(
USE plato;
@@ -549,7 +543,56 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
)");
UNIT_ASSERT(reqAlterLoginNoLoginWithPassword.IsOk());
- UNIT_ASSERT(reqAlterLoginNoLoginWithPassword.Root);
+ }
+
+ Y_UNIT_TEST(CreateUserWithHash) {
+ auto reqCreateUser = SqlToYql(R"(
+ USE plato;
+ CREATE USER user1 HASH '{
+ "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
+ "salt": "U+tzBtgo06EBQCjlARA6Jg==",
+ "type": "argon2id"
+ }';
+ )");
+
+ UNIT_ASSERT(reqCreateUser.IsOk());
+
+ auto reqCreateUserWithNoLogin = SqlToYql(R"(
+ USE plato;
+ CREATE USER user1 HASH '{
+ "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
+ "salt": "U+tzBtgo06EBQCjlARA6Jg==",
+ "type": "argon2id"
+ }'
+ NOLOGIN;
+ )");
+
+ UNIT_ASSERT(reqCreateUserWithNoLogin.IsOk());
+
+ auto reqCreateUserWithPassword = SqlToYql(R"(
+ USE plato;
+ CREATE USER user1 HASH '{
+ "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
+ "salt": "U+tzBtgo06EBQCjlARA6Jg==",
+ "type": "argon2id"
+ }'
+ PASSWORD '123';
+ )");
+
+ UNIT_ASSERT(!reqCreateUserWithPassword.IsOk());
+ UNIT_ASSERT_STRING_CONTAINS(reqCreateUserWithPassword.Issues.ToString(), "Error: Conflicting or redundant options");
+
+ auto reqAlterUser = SqlToYql(R"(
+ USE plato;
+ CREATE USER user1;
+ ALTER USER user1 HASH '{
+ "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
+ "salt": "U+tzBtgo06EBQCjlARA6Jg==",
+ "type": "argon2id"
+ }';
+ )");
+
+ UNIT_ASSERT(reqAlterUser.IsOk());
}
Y_UNIT_TEST(JoinWithoutConcreteColumns) {