diff --git a/docs/en/sql-reference/statements/grant.md b/docs/en/sql-reference/statements/grant.md index 7049d03c7e2..25dffc36954 100644 --- a/docs/en/sql-reference/statements/grant.md +++ b/docs/en/sql-reference/statements/grant.md @@ -13,27 +13,27 @@ To revoke privileges, use the [REVOKE](../../sql-reference/statements/revoke.md) ## Granting Privilege Syntax {#grant-privigele-syntax} ``` sql -[REPLACE] GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user | role | CURRENT_USER} [,...] [WITH GRANT OPTION] +GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user | role | CURRENT_USER} [,...] [WITH GRANT OPTION] [WITH REPLACE OPTION] ``` - `privilege` — Type of privilege. - `role` — ClickHouse user role. - `user` — ClickHouse user account. -The `REPLACE` clause replace old privileges by new privileges for the `user` or `role` The `WITH GRANT OPTION` clause grants `user` or `role` with permission to execute the `GRANT` query. Users can grant privileges of the same scope they have and less. +The `WITH REPLACE OPTION` clause replace old privileges by new privileges for the `user` or `role`, if not specified it is append privileges. ## Assigning Role Syntax {#assign-role-syntax} ``` sql -[REPLACE] GRANT [ON CLUSTER cluster_name] role [,...] TO {user | another_role | CURRENT_USER} [,...] [WITH ADMIN OPTION] +GRANT [ON CLUSTER cluster_name] role [,...] TO {user | another_role | CURRENT_USER} [,...] [WITH ADMIN OPTION] [WITH REPLACE OPTION] ``` - `role` — ClickHouse user role. - `user` — ClickHouse user account. -The `REPLACE` clause replace old roles by new role for the `user` or `role` The `WITH ADMIN OPTION` clause grants [ADMIN OPTION](#admin-option-privilege) privilege to `user` or `role`. +The `WITH REPLACE OPTION` clause replace old roles by new role for the `user` or `role`, if not specified it is append roles. ## Usage {#grant-usage} diff --git a/docs/ja/sql-reference/statements/grant.md b/docs/ja/sql-reference/statements/grant.md index 9ecaccebdc8..6fff8da310f 100644 --- a/docs/ja/sql-reference/statements/grant.md +++ b/docs/ja/sql-reference/statements/grant.md @@ -15,27 +15,27 @@ toc_title: GRANT ## 権限構文の付与 {#grant-privigele-syntax} ``` sql -[REPLACE] GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user | role | CURRENT_USER} [,...] [WITH GRANT OPTION] +GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user | role | CURRENT_USER} [,...] [WITH GRANT OPTION] [WITH REPLACE OPTION] ``` - `privilege` — Type of privilege. - `role` — ClickHouse user role. - `user` — ClickHouse user account. -この `REPLACE` 句は `user`または` role`の新しい特権で古い特権を置き換えます この `WITH GRANT OPTION` 句の付与 `user` または `role` 実行する許可を得て `GRANT` クエリ。 ユーザーは、持っているスコープとそれ以下の権限を付与できます。 +この `WITH REPLACE OPTION` 句は `user`または` role`の新しい特権で古い特権を置き換えます, 指定しない場合は、古い特権を古いものに追加してください ## ロール構文の割り当て {#assign-role-syntax} ``` sql -[REPLACE] GRANT [ON CLUSTER cluster_name] role [,...] TO {user | another_role | CURRENT_USER} [,...] [WITH ADMIN OPTION] +GRANT [ON CLUSTER cluster_name] role [,...] TO {user | another_role | CURRENT_USER} [,...] [WITH ADMIN OPTION] [WITH REPLACE OPTION] ``` - `role` — ClickHouse user role. - `user` — ClickHouse user account. -この `REPLACE` 句は`user`または` role`の新しい役割によって古い役割を置き換えます この `WITH ADMIN OPTION` 句の付与 [ADMIN OPTION](#admin-option-privilege) への特権 `user` または `role`. +この `WITH REPLACE OPTION` 句は`user`または` role`の新しい役割によって古い役割を置き換えます, 指定しない場合は、古い特権を古いものに追加してください ## 使用法 {#grant-usage} diff --git a/docs/ru/sql-reference/statements/grant.md b/docs/ru/sql-reference/statements/grant.md index 95b6ded6a26..48c5286c452 100644 --- a/docs/ru/sql-reference/statements/grant.md +++ b/docs/ru/sql-reference/statements/grant.md @@ -13,28 +13,28 @@ toc_title: GRANT ## Синтаксис присвоения привилегий {#grant-privigele-syntax} ```sql -[REPLACE] GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user | role | CURRENT_USER} [,...] [WITH GRANT OPTION] +GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user | role | CURRENT_USER} [,...] [WITH GRANT OPTION] [WITH REPLACE OPTION] ``` - `privilege` — Тип привилегии - `role` — Роль пользователя ClickHouse. - `user` — Пользователь ClickHouse. -`REPLACE` заменяет все старые привилегии новыми привилегиями для `user` или `role`. `WITH GRANT OPTION` разрешает пользователю или роли выполнять запрос `GRANT`. Пользователь может выдавать только те привилегии, которые есть у него, той же или меньшей области действий. +`WITH REPLACE OPTION` заменяет все старые привилегии новыми привилегиями для `user` или `role`, Если не указано, добавьте новые привилегии для старых. ## Синтаксис назначения ролей {#assign-role-syntax} ```sql -[REPLACE] GRANT [ON CLUSTER cluster_name] role [,...] TO {user | another_role | CURRENT_USER} [,...] [WITH ADMIN OPTION] +GRANT [ON CLUSTER cluster_name] role [,...] TO {user | another_role | CURRENT_USER} [,...] [WITH ADMIN OPTION] [WITH REPLACE OPTION] ``` - `role` — Роль пользователя ClickHouse. - `user` — Пользователь ClickHouse. -`REPLACE` заменяет все старые роли новыми ролями для пользователя `user` или `role`. `WITH ADMIN OPTION` присваивает привилегию [ADMIN OPTION](#admin-option-privilege) пользователю или роли. +`WITH REPLACE OPTION` заменяет все старые роли новыми ролями для пользователя `user` или `role`, Если не указано, добавьте новые роли в старые. ## Использование {#grant-usage} diff --git a/docs/zh/sql-reference/statements/grant.md b/docs/zh/sql-reference/statements/grant.md index bc8a0b3193d..c9794c0552c 100644 --- a/docs/zh/sql-reference/statements/grant.md +++ b/docs/zh/sql-reference/statements/grant.md @@ -12,27 +12,27 @@ toc_title: 授权操作 ## 授权操作语法 {#grant-privigele-syntax} ``` sql -[REPLACE] GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user | role | CURRENT_USER} [,...] [WITH GRANT OPTION] +GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user | role | CURRENT_USER} [,...] [WITH GRANT OPTION] [WITH REPLACE OPTION] ``` - `privilege` — 权限类型 - `role` — 用户角色 - `user` — 用户账号 -`REPLACE` 以当前sql里的新权限替代掉 `user` 或 `role`的旧权限。 `WITH GRANT OPTION` 授予 `user` 或 `role`执行 `GRANT` 操作的权限。用户可将在自身权限范围内的权限进行授权 +`WITH REPLACE OPTION` 以当前sql里的新权限替代掉 `user` 或 `role`的旧权限,如果没有该选项则是追加授权。 ## 角色分配的语法 {#assign-role-syntax} ``` sql -[REPLACE] GRANT [ON CLUSTER cluster_name] role [,...] TO {user | another_role | CURRENT_USER} [,...] [WITH ADMIN OPTION] +GRANT [ON CLUSTER cluster_name] role [,...] TO {user | another_role | CURRENT_USER} [,...] [WITH ADMIN OPTION] [WITH REPLACE OPTION] ``` - `role` — 角色 - `user` — 用户 -`REPLACE` 以当前sql里的新role替代掉 `user` 或 `role`的旧role `WITH ADMIN OPTION` 授予 `user` 或 `role` 执行[ADMIN OPTION](#admin-option-privilege) 的权限 +`WITH REPLACE OPTION` 以当前sql里的新role替代掉 `user` 或 `role`的旧role,如果没有该选项则是追加roles。 ## 用法 {#grant-usage} diff --git a/src/Parsers/ParserGrantQuery.cpp b/src/Parsers/ParserGrantQuery.cpp index 5c7365528c0..5ea6ac0ec92 100644 --- a/src/Parsers/ParserGrantQuery.cpp +++ b/src/Parsers/ParserGrantQuery.cpp @@ -232,19 +232,12 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) return false; bool is_replace = false; - bool replace_access = false; - if (ParserKeyword{"REPLACE"}.ignore(pos, expected)) - is_replace = true; - bool is_revoke = false; if (ParserKeyword{"REVOKE"}.ignore(pos, expected)) is_revoke = true; else if (!ParserKeyword{"GRANT"}.ignore(pos, expected)) return false; - if (is_replace && is_revoke) - return false; - String cluster; parseOnCluster(pos, expected, cluster); @@ -279,6 +272,9 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) grant_option = true; else if (ParserKeyword{"WITH ADMIN OPTION"}.ignore(pos, expected)) admin_option = true; + + if (ParserKeyword{"WITH REPLACE OPTION"}.ignore(pos, expected)) + is_replace = true; } if (cluster.empty()) @@ -295,31 +291,42 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) element.grant_option = true; } - if (is_replace && !elements.empty()) - { - replace_access = true; - bool new_access = false; - bool none_on_all = false; - for (auto & element : elements) - { - if (element.access_flags.isEmpty()) - { - if (element.any_database) - none_on_all = true; - else - throw Exception("In REPLACE GRANT granting privilege sql, 'NONE ON db.*' should be 'NONE ON *.*', and can only be used alone to drop all privileges on any database", ErrorCodes::SYNTAX_ERROR); - } - else - { - new_access = true; - } - } - if (new_access && none_on_all) - throw Exception("In REPLACE GRANT granting privilege sql, 'NONE ON db.*' should be 'NONE ON *.*', and can only be used alone to drop all privileges on any database", ErrorCodes::SYNTAX_ERROR); + bool replace_access = false; + if (is_replace) + { + if (roles) + { // assigning role mode + if (!roles->empty() && roles->none_role_parsed) + throw Exception("In assigning role WITH REPLACE OPTION sql, 'NONE' can only be used alone to rovoke all roles", ErrorCodes::SYNTAX_ERROR); + } + else + { + // granting privilege mode + replace_access = true; + bool new_access = false; + bool none_on_all = false; + for (auto & element : elements) + { + if (element.access_flags.isEmpty()) + { + if (element.any_database) + none_on_all = true; + else + throw Exception("In granting privilege WITH REPLACE OPTION sql, 'NONE ON db.*' should be 'NONE ON *.*', and can only be used alone to drop all privileges on any database", ErrorCodes::SYNTAX_ERROR); + } + else + { + new_access = true; + } + } + + if (new_access && none_on_all) + throw Exception("In granting privilege WITH REPLACE OPTION sql, 'NONE ON db.*' should be 'NONE ON *.*', and can only be used alone to drop all privileges on any database", ErrorCodes::SYNTAX_ERROR); + } } - if (is_replace && !replace_access && !roles->empty() && roles->none_role_parsed) + if (is_replace && !replace_access && roles && !roles->empty() && roles->none_role_parsed) throw Exception("In REPLACE GRANT assigning role sql, 'NONE' can only be used alone to rovoke all roles", ErrorCodes::SYNTAX_ERROR); if (!is_revoke) diff --git a/tests/queries/0_stateless/01999_replace_grant.reference b/tests/queries/0_stateless/01999_grant_with_replace.reference similarity index 100% rename from tests/queries/0_stateless/01999_replace_grant.reference rename to tests/queries/0_stateless/01999_grant_with_replace.reference diff --git a/tests/queries/0_stateless/01999_replace_grant.sql b/tests/queries/0_stateless/01999_grant_with_replace.sql similarity index 65% rename from tests/queries/0_stateless/01999_replace_grant.sql rename to tests/queries/0_stateless/01999_grant_with_replace.sql index 6585054abf7..9c3f68fff7e 100644 --- a/tests/queries/0_stateless/01999_replace_grant.sql +++ b/tests/queries/0_stateless/01999_grant_with_replace.sql @@ -12,27 +12,27 @@ GRANT SHOW ON db2.tb2 TO test_user_01999; SELECT 'B'; SHOW GRANTS FOR test_user_01999; -REPLACE GRANT SELECT(col1) ON db3.table TO test_user_01999; +GRANT SELECT(col1) ON db3.table TO test_user_01999 WITH REPLACE OPTION; SELECT 'C'; SHOW GRANTS FOR test_user_01999; -REPLACE GRANT SELECT(col3) ON db3.table3, SELECT(col1, col2) ON db4.table4 TO test_user_01999; +GRANT SELECT(col3) ON db3.table3, SELECT(col1, col2) ON db4.table4 TO test_user_01999 WITH REPLACE OPTION; SELECT 'D'; SHOW GRANTS FOR test_user_01999; -REPLACE GRANT SELECT(cola) ON db5.table, INSERT(colb) ON db6.tb61, SHOW ON db7.* TO test_user_01999; +GRANT SELECT(cola) ON db5.table, INSERT(colb) ON db6.tb61, SHOW ON db7.* TO test_user_01999 WITH REPLACE OPTION; SELECT 'E'; SHOW GRANTS FOR test_user_01999; SELECT 'F'; -REPLACE GRANT SELECT ON all.* TO test_user_01999; +GRANT SELECT ON all.* TO test_user_01999 WITH REPLACE OPTION; SHOW GRANTS FOR test_user_01999; SELECT 'G'; -REPLACE GRANT USAGE ON *.* TO test_user_01999; +GRANT USAGE ON *.* TO test_user_01999 WITH REPLACE OPTION; SHOW GRANTS FOR test_user_01999; SELECT 'H'; @@ -43,7 +43,7 @@ GRANT SELECT ON db1.tb1 TO test_user_01999; SHOW GRANTS FOR test_user_01999; SELECT 'I'; -REPLACE GRANT NONE ON *.* TO test_user_01999; +GRANT NONE ON *.* TO test_user_01999 WITH REPLACE OPTION; SHOW GRANTS FOR test_user_01999; SELECT 'J'; @@ -51,7 +51,7 @@ GRANT SHOW ON db8.* TO test_user_01999; SHOW GRANTS FOR test_user_01999; SELECT 'K'; -REPLACE GRANT NONE TO test_user_01999; +GRANT NONE TO test_user_01999 WITH REPLACE OPTION; SHOW GRANTS FOR test_user_01999; DROP USER IF EXISTS test_user_01999; diff --git a/tests/queries/skip_list.json b/tests/queries/skip_list.json index 0e97750a3d2..6ea8638f672 100644 --- a/tests/queries/skip_list.json +++ b/tests/queries/skip_list.json @@ -515,7 +515,7 @@ "01915_create_or_replace_dictionary", "01925_test_storage_merge_aliases", "01933_client_replxx_convert_history", /// Uses non unique history file - "01999_replace_grant", + "01999_grant_with_replace", "01902_table_function_merge_db_repr", "01946_test_wrong_host_name_access" ]