diff --git a/.gitattributes b/.gitattributes index bcc7d57b904..efb059f169a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ contrib/* linguist-vendored *.h linguist-language=C++ +# to avoid frequent conflicts +tests/queries/0_stateless/arcadia_skip_list.txt text merge=union diff --git a/CHANGELOG.md b/CHANGELOG.md index e2c777b3bcf..928991dc937 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,159 @@ +## ClickHouse release 21.3 + +### ClickHouse release v21.3, 2021-03-12 + +#### Backward Incompatible Change + +* Now it's not allowed to create MergeTree tables in old syntax with table TTL because it's just ignored. Attach of old tables is still possible. [#20282](https://github.com/ClickHouse/ClickHouse/pull/20282) ([alesapin](https://github.com/alesapin)). +* Now all case-insensitive function names will be rewritten to their canonical representations. This is needed for projection query routing (the upcoming feature). [#20174](https://github.com/ClickHouse/ClickHouse/pull/20174) ([Amos Bird](https://github.com/amosbird)). +* Fix creation of `TTL` in cases, when its expression is a function and it is the same as `ORDER BY` key. Now it's allowed to set custom aggregation to primary key columns in `TTL` with `GROUP BY`. Backward incompatible: For primary key columns, which are not in `GROUP BY` and aren't set explicitly now is applied function `any` instead of `max`, when TTL is expired. Also if you use TTL with `WHERE` or `GROUP BY` you can see exceptions at merges, while making rolling update. [#15450](https://github.com/ClickHouse/ClickHouse/pull/15450) ([Anton Popov](https://github.com/CurtizJ)). + +#### New Feature + +* Add file engine settings: `engine_file_empty_if_not_exists` and `engine_file_truncate_on_insert`. [#20620](https://github.com/ClickHouse/ClickHouse/pull/20620) ([M0r64n](https://github.com/M0r64n)). +* Add aggregate function `deltaSum` for summing the differences between consecutive rows. [#20057](https://github.com/ClickHouse/ClickHouse/pull/20057) ([Russ Frank](https://github.com/rf)). +* New `event_time_microseconds` column in `system.part_log` table. [#20027](https://github.com/ClickHouse/ClickHouse/pull/20027) ([Bharat Nallan](https://github.com/bharatnc)). +* Added `timezoneOffset(datetime)` function which will give the offset from UTC in seconds. This close [#issue:19850](https://github.com/ClickHouse/ClickHouse/issues/19850). [#19962](https://github.com/ClickHouse/ClickHouse/pull/19962) ([keenwolf](https://github.com/keen-wolf)). +* Add setting `insert_shard_id` to support insert data into specific shard from distributed table. [#19961](https://github.com/ClickHouse/ClickHouse/pull/19961) ([flynn](https://github.com/ucasFL)). +* Function `reinterpretAs` updated to support big integers. Fixes [#19691](https://github.com/ClickHouse/ClickHouse/issues/19691). [#19858](https://github.com/ClickHouse/ClickHouse/pull/19858) ([Maksim Kita](https://github.com/kitaisreal)). +* Added Server Side Encryption Customer Keys (the `x-amz-server-side-encryption-customer-(key/md5)` header) support in S3 client. See [the link](https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html). Closes [#19428](https://github.com/ClickHouse/ClickHouse/issues/19428). [#19748](https://github.com/ClickHouse/ClickHouse/pull/19748) ([Vladimir Chebotarev](https://github.com/excitoon)). +* Added `implicit_key` option for `executable` dictionary source. It allows to avoid printing key for every record if records comes in the same order as the input keys. Implements [#14527](https://github.com/ClickHouse/ClickHouse/issues/14527). [#19677](https://github.com/ClickHouse/ClickHouse/pull/19677) ([Maksim Kita](https://github.com/kitaisreal)). +* Add quota type `query_selects` and `query_inserts`. [#19603](https://github.com/ClickHouse/ClickHouse/pull/19603) ([JackyWoo](https://github.com/JackyWoo)). +* Add function `extractTextFromHTML` [#19600](https://github.com/ClickHouse/ClickHouse/pull/19600) ([zlx19950903](https://github.com/zlx19950903)), ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Tables with `MergeTree*` engine now have two new table-level settings for query concurrency control. Setting `max_concurrent_queries` limits the number of concurrently executed queries which are related to this table. Setting `min_marks_to_honor_max_concurrent_queries` tells to apply previous setting only if query reads at least this number of marks. [#19544](https://github.com/ClickHouse/ClickHouse/pull/19544) ([Amos Bird](https://github.com/amosbird)). +* Added `file` function to read file from user_files directory as a String. This is different from the `file` table function. This implements [#issue:18851](https://github.com/ClickHouse/ClickHouse/issues/18851). [#19204](https://github.com/ClickHouse/ClickHouse/pull/19204) ([keenwolf](https://github.com/keen-wolf)). + +#### Experimental feature + +* Add experimental `Replicated` database engine. It replicates DDL queries across multiple hosts. [#16193](https://github.com/ClickHouse/ClickHouse/pull/16193) ([tavplubix](https://github.com/tavplubix)). +* Introduce experimental support for window functions, enabled with `allow_experimental_functions = 1`. This is a preliminary, alpha-quality implementation that is not suitable for production use and will change in backward-incompatible ways in future releases. Please see [the documentation](https://github.com/ClickHouse/ClickHouse/blob/master/docs/en/sql-reference/window-functions/index.md#experimental-window-functions) for the list of supported features. [#20337](https://github.com/ClickHouse/ClickHouse/pull/20337) ([Alexander Kuzmenkov](https://github.com/akuzm)). +* Add the ability to backup/restore metadata files for DiskS3. [#18377](https://github.com/ClickHouse/ClickHouse/pull/18377) ([Pavel Kovalenko](https://github.com/Jokser)). + +#### Performance Improvement + +* Hedged requests for remote queries. When setting `use_hedged_requests` enabled (off by default), allow to establish many connections with different replicas for query. New connection is enabled in case existent connection(s) with replica(s) were not established within `hedged_connection_timeout` or no data was received within `receive_data_timeout`. Query uses the first connection which send non empty progress packet (or data packet, if `allow_changing_replica_until_first_data_packet`); other connections are cancelled. Queries with `max_parallel_replicas > 1` are supported. [#19291](https://github.com/ClickHouse/ClickHouse/pull/19291) ([Kruglov Pavel](https://github.com/Avogar)). This allows to significantly reduce tail latencies on very large clusters. +* Added support for `PREWHERE` (and enable the corresponding optimization) when tables have row-level security expressions specified. [#19576](https://github.com/ClickHouse/ClickHouse/pull/19576) ([Denis Glazachev](https://github.com/traceon)). +* The setting `distributed_aggregation_memory_efficient` is enabled by default. It will lower memory usage and improve performance of distributed queries. [#20599](https://github.com/ClickHouse/ClickHouse/pull/20599) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Improve performance of GROUP BY multiple fixed size keys. [#20472](https://github.com/ClickHouse/ClickHouse/pull/20472) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Improve performance of aggregate functions by more strict aliasing. [#19946](https://github.com/ClickHouse/ClickHouse/pull/19946) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Speed up reading from `Memory` tables in extreme cases (when reading speed is in order of 50 GB/sec) by simplification of pipeline and (consequently) less lock contention in pipeline scheduling. [#20468](https://github.com/ClickHouse/ClickHouse/pull/20468) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Partially reimplement HTTP server to make it making less copies of incoming and outgoing data. It gives up to 1.5 performance improvement on inserting long records over HTTP. [#19516](https://github.com/ClickHouse/ClickHouse/pull/19516) ([Ivan](https://github.com/abyss7)). +* Add `compress` setting for `Memory` tables. If it's enabled the table will use less RAM. On some machines and datasets it can also work faster on SELECT, but it is not always the case. This closes [#20093](https://github.com/ClickHouse/ClickHouse/issues/20093). Note: there are reasons why Memory tables can work slower than MergeTree: (1) lack of compression (2) static size of blocks (3) lack of indices and prewhere... [#20168](https://github.com/ClickHouse/ClickHouse/pull/20168) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Slightly better code in aggregation. [#20978](https://github.com/ClickHouse/ClickHouse/pull/20978) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Add back `intDiv`/`modulo` specializations for better performance. This fixes [#21293](https://github.com/ClickHouse/ClickHouse/issues/21293) . The regression was introduced in https://github.com/ClickHouse/ClickHouse/pull/18145 . [#21307](https://github.com/ClickHouse/ClickHouse/pull/21307) ([Amos Bird](https://github.com/amosbird)). +* Do not squash blocks too much on INSERT SELECT if inserting into Memory table. In previous versions inefficient data representation was created in Memory table after INSERT SELECT. This closes [#13052](https://github.com/ClickHouse/ClickHouse/issues/13052). [#20169](https://github.com/ClickHouse/ClickHouse/pull/20169) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Fix at least one case when DataType parser may have exponential complexity (found by fuzzer). This closes [#20096](https://github.com/ClickHouse/ClickHouse/issues/20096). [#20132](https://github.com/ClickHouse/ClickHouse/pull/20132) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Parallelize SELECT with FINAL for single part with level > 0 when `do_not_merge_across_partitions_select_final` setting is 1. [#19375](https://github.com/ClickHouse/ClickHouse/pull/19375) ([Kruglov Pavel](https://github.com/Avogar)). +* Fill only requested columns when querying `system.parts` and `system.parts_columns`. Closes [#19570](https://github.com/ClickHouse/ClickHouse/issues/19570). [#21035](https://github.com/ClickHouse/ClickHouse/pull/21035) ([Anmol Arora](https://github.com/anmolarora)). +* Perform algebraic optimizations of arithmetic expressions inside `avg` aggregate function. close [#20092](https://github.com/ClickHouse/ClickHouse/issues/20092). [#20183](https://github.com/ClickHouse/ClickHouse/pull/20183) ([flynn](https://github.com/ucasFL)). + +#### Improvement + +* Case-insensitive compression methods for table functions. Also fixed LZMA compression method which was checked in upper case. [#21416](https://github.com/ClickHouse/ClickHouse/pull/21416) ([Vladimir Chebotarev](https://github.com/excitoon)). +* Add two settings to delay or throw error during insertion when there are too many inactive parts. This is useful when server fails to clean up parts quickly enough. [#20178](https://github.com/ClickHouse/ClickHouse/pull/20178) ([Amos Bird](https://github.com/amosbird)). +* Provide better compatibility for mysql clients. 1. mysql jdbc 2. mycli. [#21367](https://github.com/ClickHouse/ClickHouse/pull/21367) ([Amos Bird](https://github.com/amosbird)). +* Forbid to drop a column if it's referenced by materialized view. Closes [#21164](https://github.com/ClickHouse/ClickHouse/issues/21164). [#21303](https://github.com/ClickHouse/ClickHouse/pull/21303) ([flynn](https://github.com/ucasFL)). +* MySQL dictionary source will now retry unexpected connection failures (Lost connection to MySQL server during query) which sometimes happen on SSL/TLS connections. [#21237](https://github.com/ClickHouse/ClickHouse/pull/21237) ([Alexander Kazakov](https://github.com/Akazz)). +* Usability improvement: more consistent `DateTime64` parsing: recognize the case when unix timestamp with subsecond resolution is specified as scaled integer (like `1111111111222` instead of `1111111111.222`). This closes [#13194](https://github.com/ClickHouse/ClickHouse/issues/13194). [#21053](https://github.com/ClickHouse/ClickHouse/pull/21053) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Do only merging of sorted blocks on initiator with distributed_group_by_no_merge. [#20882](https://github.com/ClickHouse/ClickHouse/pull/20882) ([Azat Khuzhin](https://github.com/azat)). +* When loading config for mysql source ClickHouse will now randomize the list of replicas with the same priority to ensure the round-robin logics of picking mysql endpoint. This closes [#20629](https://github.com/ClickHouse/ClickHouse/issues/20629). [#20632](https://github.com/ClickHouse/ClickHouse/pull/20632) ([Alexander Kazakov](https://github.com/Akazz)). +* Function 'reinterpretAs(x, Type)' renamed into 'reinterpret(x, Type)'. [#20611](https://github.com/ClickHouse/ClickHouse/pull/20611) ([Maksim Kita](https://github.com/kitaisreal)). +* Support vhost for RabbitMQ engine [#20576](https://github.com/ClickHouse/ClickHouse/issues/20576). [#20596](https://github.com/ClickHouse/ClickHouse/pull/20596) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Improved serialization for data types combined of Arrays and Tuples. Improved matching enum data types to protobuf enum type. Fixed serialization of the `Map` data type. Omitted values are now set by default. [#20506](https://github.com/ClickHouse/ClickHouse/pull/20506) ([Vitaly Baranov](https://github.com/vitlibar)). +* Fixed race between execution of distributed DDL tasks and cleanup of DDL queue. Now DDL task cannot be removed from ZooKeeper if there are active workers. Fixes [#20016](https://github.com/ClickHouse/ClickHouse/issues/20016). [#20448](https://github.com/ClickHouse/ClickHouse/pull/20448) ([tavplubix](https://github.com/tavplubix)). +* Make FQDN and other DNS related functions work correctly in alpine images. [#20336](https://github.com/ClickHouse/ClickHouse/pull/20336) ([filimonov](https://github.com/filimonov)). +* Do not allow early constant folding of explicitly forbidden functions. [#20303](https://github.com/ClickHouse/ClickHouse/pull/20303) ([Azat Khuzhin](https://github.com/azat)). +* Implicit conversion from integer to Decimal type might succeeded if integer value doe not fit into Decimal type. Now it throws `ARGUMENT_OUT_OF_BOUND`. [#20232](https://github.com/ClickHouse/ClickHouse/pull/20232) ([tavplubix](https://github.com/tavplubix)). +* Lockless `SYSTEM FLUSH DISTRIBUTED`. [#20215](https://github.com/ClickHouse/ClickHouse/pull/20215) ([Azat Khuzhin](https://github.com/azat)). +* Normalize count(constant), sum(1) to count(). This is needed for projection query routing. [#20175](https://github.com/ClickHouse/ClickHouse/pull/20175) ([Amos Bird](https://github.com/amosbird)). +* Support all native integer types in bitmap functions. [#20171](https://github.com/ClickHouse/ClickHouse/pull/20171) ([Amos Bird](https://github.com/amosbird)). +* Updated `CacheDictionary`, `ComplexCacheDictionary`, `SSDCacheDictionary`, `SSDComplexKeyDictionary` to use LRUHashMap as underlying index. [#20164](https://github.com/ClickHouse/ClickHouse/pull/20164) ([Maksim Kita](https://github.com/kitaisreal)). +* The setting `access_management` is now configurable on startup by providing `CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT`, defaults to disabled (`0`) which was the prior value. [#20139](https://github.com/ClickHouse/ClickHouse/pull/20139) ([Marquitos](https://github.com/sonirico)). +* Fix toDateTime64(toDate()/toDateTime()) for DateTime64 - Implement DateTime64 clamping to match DateTime behaviour. [#20131](https://github.com/ClickHouse/ClickHouse/pull/20131) ([Azat Khuzhin](https://github.com/azat)). +* Quota improvements: SHOW TABLES is now considered as one query in the quota calculations, not two queries. SYSTEM queries now consume quota. Fix calculation of interval's end in quota consumption. [#20106](https://github.com/ClickHouse/ClickHouse/pull/20106) ([Vitaly Baranov](https://github.com/vitlibar)). +* Supports `path IN (set)` expressions for `system.zookeeper` table. [#20105](https://github.com/ClickHouse/ClickHouse/pull/20105) ([小路](https://github.com/nicelulu)). +* Show full details of `MaterializeMySQL` tables in `system.tables`. [#20051](https://github.com/ClickHouse/ClickHouse/pull/20051) ([Stig Bakken](https://github.com/stigsb)). +* Fix data race in executable dictionary that was possible only on misuse (when the script returns data ignoring its input). [#20045](https://github.com/ClickHouse/ClickHouse/pull/20045) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* The value of MYSQL_OPT_RECONNECT option can now be controlled by "opt_reconnect" parameter in the config section of mysql replica. [#19998](https://github.com/ClickHouse/ClickHouse/pull/19998) ([Alexander Kazakov](https://github.com/Akazz)). +* If user calls `JSONExtract` function with `Float32` type requested, allow inaccurate conversion to the result type. For example the number `0.1` in JSON is double precision and is not representable in Float32, but the user still wants to get it. Previous versions return 0 for non-Nullable type and NULL for Nullable type to indicate that conversion is imprecise. The logic was 100% correct but it was surprising to users and leading to questions. This closes [#13962](https://github.com/ClickHouse/ClickHouse/issues/13962). [#19960](https://github.com/ClickHouse/ClickHouse/pull/19960) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Add conversion of block structure for INSERT into Distributed tables if it does not match. [#19947](https://github.com/ClickHouse/ClickHouse/pull/19947) ([Azat Khuzhin](https://github.com/azat)). +* Improvement for the `system.distributed_ddl_queue` table. Initialize MaxDDLEntryID to the last value after restarting. Before this PR, MaxDDLEntryID will remain zero until a new DDLTask is processed. [#19924](https://github.com/ClickHouse/ClickHouse/pull/19924) ([Amos Bird](https://github.com/amosbird)). +* Show `MaterializeMySQL` tables in `system.parts`. [#19770](https://github.com/ClickHouse/ClickHouse/pull/19770) ([Stig Bakken](https://github.com/stigsb)). +* Add separate config directive for `Buffer` profile. [#19721](https://github.com/ClickHouse/ClickHouse/pull/19721) ([Azat Khuzhin](https://github.com/azat)). +* Move conditions that are not related to JOIN to WHERE clause. [#18720](https://github.com/ClickHouse/ClickHouse/issues/18720). [#19685](https://github.com/ClickHouse/ClickHouse/pull/19685) ([hexiaoting](https://github.com/hexiaoting)). +* Add ability to throttle INSERT into Distributed based on amount of pending bytes for async send (`bytes_to_delay_insert`/`max_delay_to_insert` and `bytes_to_throw_insert` settings for `Distributed` engine has been added). [#19673](https://github.com/ClickHouse/ClickHouse/pull/19673) ([Azat Khuzhin](https://github.com/azat)). +* Fix some rare cases when write errors can be ignored in destructors. [#19451](https://github.com/ClickHouse/ClickHouse/pull/19451) ([Azat Khuzhin](https://github.com/azat)). +* Print inline frames in stack traces for fatal errors. [#19317](https://github.com/ClickHouse/ClickHouse/pull/19317) ([Ivan](https://github.com/abyss7)). + +#### Bug Fix + +* Fix redundant reconnects to ZooKeeper and the possibility of two active sessions for a single clickhouse server. Both problems introduced in #14678. [#21264](https://github.com/ClickHouse/ClickHouse/pull/21264) ([alesapin](https://github.com/alesapin)). +* Fix error `Bad cast from type ... to DB::ColumnLowCardinality` while inserting into table with `LowCardinality` column from `Values` format. Fixes #21140 [#21357](https://github.com/ClickHouse/ClickHouse/pull/21357) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix a deadlock in `ALTER DELETE` mutations for non replicated MergeTree table engines when the predicate contains the table itself. Fixes [#20558](https://github.com/ClickHouse/ClickHouse/issues/20558). [#21477](https://github.com/ClickHouse/ClickHouse/pull/21477) ([alesapin](https://github.com/alesapin)). +* Fix SIGSEGV for distributed queries on failures. [#21434](https://github.com/ClickHouse/ClickHouse/pull/21434) ([Azat Khuzhin](https://github.com/azat)). +* Now `ALTER MODIFY COLUMN` queries will correctly affect changes in partition key, skip indices, TTLs, and so on. Fixes [#13675](https://github.com/ClickHouse/ClickHouse/issues/13675). [#21334](https://github.com/ClickHouse/ClickHouse/pull/21334) ([alesapin](https://github.com/alesapin)). +* Fix bug with `join_use_nulls` and joining `TOTALS` from subqueries. This closes [#19362](https://github.com/ClickHouse/ClickHouse/issues/19362) and [#21137](https://github.com/ClickHouse/ClickHouse/issues/21137). [#21248](https://github.com/ClickHouse/ClickHouse/pull/21248) ([vdimir](https://github.com/vdimir)). +* Fix crash in `EXPLAIN` for query with `UNION`. Fixes [#20876](https://github.com/ClickHouse/ClickHouse/issues/20876), [#21170](https://github.com/ClickHouse/ClickHouse/issues/21170). [#21246](https://github.com/ClickHouse/ClickHouse/pull/21246) ([flynn](https://github.com/ucasFL)). +* Now mutations allowed only for table engines that support them (MergeTree family, Memory, MaterializedView). Other engines will report a more clear error. Fixes [#21168](https://github.com/ClickHouse/ClickHouse/issues/21168). [#21183](https://github.com/ClickHouse/ClickHouse/pull/21183) ([alesapin](https://github.com/alesapin)). +* Fixes [#21112](https://github.com/ClickHouse/ClickHouse/issues/21112). Fixed bug that could cause duplicates with insert query (if one of the callbacks came a little too late). [#21138](https://github.com/ClickHouse/ClickHouse/pull/21138) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix `input_format_null_as_default` take effective when types are nullable. This fixes [#21116](https://github.com/ClickHouse/ClickHouse/issues/21116) . [#21121](https://github.com/ClickHouse/ClickHouse/pull/21121) ([Amos Bird](https://github.com/amosbird)). +* fix bug related to cast Tuple to Map. Closes [#21029](https://github.com/ClickHouse/ClickHouse/issues/21029). [#21120](https://github.com/ClickHouse/ClickHouse/pull/21120) ([hexiaoting](https://github.com/hexiaoting)). +* Fix the metadata leak when the Replicated*MergeTree with custom (non default) ZooKeeper cluster is dropped. [#21119](https://github.com/ClickHouse/ClickHouse/pull/21119) ([fastio](https://github.com/fastio)). +* Fix type mismatch issue when using LowCardinality keys in joinGet. This fixes [#21114](https://github.com/ClickHouse/ClickHouse/issues/21114). [#21117](https://github.com/ClickHouse/ClickHouse/pull/21117) ([Amos Bird](https://github.com/amosbird)). +* fix default_replica_path and default_replica_name values are useless on Replicated(*)MergeTree engine when the engine needs specify other parameters. [#21060](https://github.com/ClickHouse/ClickHouse/pull/21060) ([mxzlxy](https://github.com/mxzlxy)). +* Out of bound memory access was possible when formatting specifically crafted out of range value of type `DateTime64`. This closes [#20494](https://github.com/ClickHouse/ClickHouse/issues/20494). This closes [#20543](https://github.com/ClickHouse/ClickHouse/issues/20543). [#21023](https://github.com/ClickHouse/ClickHouse/pull/21023) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Block parallel insertions into storage join. [#21009](https://github.com/ClickHouse/ClickHouse/pull/21009) ([vdimir](https://github.com/vdimir)). +* Fixed behaviour, when `ALTER MODIFY COLUMN` created mutation, that will knowingly fail. [#21007](https://github.com/ClickHouse/ClickHouse/pull/21007) ([Anton Popov](https://github.com/CurtizJ)). +* Closes [#9969](https://github.com/ClickHouse/ClickHouse/issues/9969). Fixed Brotli http compression error, which reproduced for large data sizes, slightly complicated structure and with json output format. Update Brotli to the latest version to include the "fix rare access to uninitialized data in ring-buffer". [#20991](https://github.com/ClickHouse/ClickHouse/pull/20991) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix 'Empty task was returned from async task queue' on query cancellation. [#20881](https://github.com/ClickHouse/ClickHouse/pull/20881) ([Azat Khuzhin](https://github.com/azat)). +* `USE database;` query did not work when using MySQL 5.7 client to connect to ClickHouse server, it's fixed. Fixes [#18926](https://github.com/ClickHouse/ClickHouse/issues/18926). [#20878](https://github.com/ClickHouse/ClickHouse/pull/20878) ([tavplubix](https://github.com/tavplubix)). +* Fix usage of `-Distinct` combinator with `-State` combinator in aggregate functions. [#20866](https://github.com/ClickHouse/ClickHouse/pull/20866) ([Anton Popov](https://github.com/CurtizJ)). +* Fix subquery with union distinct and limit clause. close [#20597](https://github.com/ClickHouse/ClickHouse/issues/20597). [#20610](https://github.com/ClickHouse/ClickHouse/pull/20610) ([flynn](https://github.com/ucasFL)). +* Fixed inconsistent behavior of dictionary in case of queries where we look for absent keys in dictionary. [#20578](https://github.com/ClickHouse/ClickHouse/pull/20578) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)). +* Fix the number of threads for scalar subqueries and subqueries for index (after [#19007](https://github.com/ClickHouse/ClickHouse/issues/19007) single thread was always used). Fixes [#20457](https://github.com/ClickHouse/ClickHouse/issues/20457), [#20512](https://github.com/ClickHouse/ClickHouse/issues/20512). [#20550](https://github.com/ClickHouse/ClickHouse/pull/20550) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix crash which could happen if unknown packet was received from remove query (was introduced in [#17868](https://github.com/ClickHouse/ClickHouse/issues/17868)). [#20547](https://github.com/ClickHouse/ClickHouse/pull/20547) ([Azat Khuzhin](https://github.com/azat)). +* Add proper checks while parsing directory names for async INSERT (fixes SIGSEGV). [#20498](https://github.com/ClickHouse/ClickHouse/pull/20498) ([Azat Khuzhin](https://github.com/azat)). +* Fix function `transform` does not work properly for floating point keys. Closes [#20460](https://github.com/ClickHouse/ClickHouse/issues/20460). [#20479](https://github.com/ClickHouse/ClickHouse/pull/20479) ([flynn](https://github.com/ucasFL)). +* Fix infinite loop when propagating WITH aliases to subqueries. This fixes [#20388](https://github.com/ClickHouse/ClickHouse/issues/20388). [#20476](https://github.com/ClickHouse/ClickHouse/pull/20476) ([Amos Bird](https://github.com/amosbird)). +* Fix abnormal server termination when http client goes away. [#20464](https://github.com/ClickHouse/ClickHouse/pull/20464) ([Azat Khuzhin](https://github.com/azat)). +* Fix `LOGICAL_ERROR` for `join_use_nulls=1` when JOIN contains const from SELECT. [#20461](https://github.com/ClickHouse/ClickHouse/pull/20461) ([Azat Khuzhin](https://github.com/azat)). +* Check if table function `view` is used in expression list and throw an error. This fixes [#20342](https://github.com/ClickHouse/ClickHouse/issues/20342). [#20350](https://github.com/ClickHouse/ClickHouse/pull/20350) ([Amos Bird](https://github.com/amosbird)). +* Avoid invalid dereference in RANGE_HASHED() dictionary. [#20345](https://github.com/ClickHouse/ClickHouse/pull/20345) ([Azat Khuzhin](https://github.com/azat)). +* Fix null dereference with `join_use_nulls=1`. [#20344](https://github.com/ClickHouse/ClickHouse/pull/20344) ([Azat Khuzhin](https://github.com/azat)). +* Fix incorrect result of binary operations between two constant decimals of different scale. Fixes [#20283](https://github.com/ClickHouse/ClickHouse/issues/20283). [#20339](https://github.com/ClickHouse/ClickHouse/pull/20339) ([Maksim Kita](https://github.com/kitaisreal)). +* Fix too often retries of failed background tasks for `ReplicatedMergeTree` table engines family. This could lead to too verbose logging and increased CPU load. Fixes [#20203](https://github.com/ClickHouse/ClickHouse/issues/20203). [#20335](https://github.com/ClickHouse/ClickHouse/pull/20335) ([alesapin](https://github.com/alesapin)). +* Restrict to `DROP` or `RENAME` version column of `*CollapsingMergeTree` and `ReplacingMergeTree` table engines. [#20300](https://github.com/ClickHouse/ClickHouse/pull/20300) ([alesapin](https://github.com/alesapin)). +* Fixed the behavior when in case of broken JSON we tried to read the whole file into memory which leads to exception from the allocator. Fixes [#19719](https://github.com/ClickHouse/ClickHouse/issues/19719). [#20286](https://github.com/ClickHouse/ClickHouse/pull/20286) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)). +* Fix exception during vertical merge for `MergeTree` table engines family which don't allow to perform vertical merges. Fixes [#20259](https://github.com/ClickHouse/ClickHouse/issues/20259). [#20279](https://github.com/ClickHouse/ClickHouse/pull/20279) ([alesapin](https://github.com/alesapin)). +* Fix rare server crash on config reload during the shutdown. Fixes [#19689](https://github.com/ClickHouse/ClickHouse/issues/19689). [#20224](https://github.com/ClickHouse/ClickHouse/pull/20224) ([alesapin](https://github.com/alesapin)). +* Fix CTE when using in INSERT SELECT. This fixes [#20187](https://github.com/ClickHouse/ClickHouse/issues/20187), fixes [#20195](https://github.com/ClickHouse/ClickHouse/issues/20195). [#20211](https://github.com/ClickHouse/ClickHouse/pull/20211) ([Amos Bird](https://github.com/amosbird)). +* Fixes [#19314](https://github.com/ClickHouse/ClickHouse/issues/19314). [#20156](https://github.com/ClickHouse/ClickHouse/pull/20156) ([Ivan](https://github.com/abyss7)). +* fix toMinute function to handle special timezone correctly. [#20149](https://github.com/ClickHouse/ClickHouse/pull/20149) ([keenwolf](https://github.com/keen-wolf)). +* Fix server crash after query with `if` function with `Tuple` type of then/else branches result. `Tuple` type must contain `Array` or another complex type. Fixes [#18356](https://github.com/ClickHouse/ClickHouse/issues/18356). [#20133](https://github.com/ClickHouse/ClickHouse/pull/20133) ([alesapin](https://github.com/alesapin)). +* The `MongoDB` table engine now establishes connection only when it's going to read data. `ATTACH TABLE` won't try to connect anymore. [#20110](https://github.com/ClickHouse/ClickHouse/pull/20110) ([Vitaly Baranov](https://github.com/vitlibar)). +* Bugfix in StorageJoin. [#20079](https://github.com/ClickHouse/ClickHouse/pull/20079) ([vdimir](https://github.com/vdimir)). +* Fix the case when calculating modulo of division of negative number by small divisor, the resulting data type was not large enough to accomodate the negative result. This closes [#20052](https://github.com/ClickHouse/ClickHouse/issues/20052). [#20067](https://github.com/ClickHouse/ClickHouse/pull/20067) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* MaterializeMySQL: Fix replication for statements that update several tables. [#20066](https://github.com/ClickHouse/ClickHouse/pull/20066) ([Håvard Kvålen](https://github.com/havardk)). +* Prevent "Connection refused" in docker during initialization script execution. [#20012](https://github.com/ClickHouse/ClickHouse/pull/20012) ([filimonov](https://github.com/filimonov)). +* `EmbeddedRocksDB` is an experimental storage. Fix the issue with lack of proper type checking. Simplified code. This closes [#19967](https://github.com/ClickHouse/ClickHouse/issues/19967). [#19972](https://github.com/ClickHouse/ClickHouse/pull/19972) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Fix a segfault in function `fromModifiedJulianDay` when the argument type is `Nullable(T)` for any integral types other than Int32. [#19959](https://github.com/ClickHouse/ClickHouse/pull/19959) ([PHO](https://github.com/depressed-pho)). +* BloomFilter index crash fix. Fixes [#19757](https://github.com/ClickHouse/ClickHouse/issues/19757). [#19884](https://github.com/ClickHouse/ClickHouse/pull/19884) ([Maksim Kita](https://github.com/kitaisreal)). +* Deadlock was possible if system.text_log is enabled. This fixes [#19874](https://github.com/ClickHouse/ClickHouse/issues/19874). [#19875](https://github.com/ClickHouse/ClickHouse/pull/19875) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Fix starting the server with tables having default expressions containing dictGet(). Allow getting return type of dictGet() without loading dictionary. [#19805](https://github.com/ClickHouse/ClickHouse/pull/19805) ([Vitaly Baranov](https://github.com/vitlibar)). +* Fix clickhouse-client abort exception while executing only `select`. [#19790](https://github.com/ClickHouse/ClickHouse/pull/19790) ([taiyang-li](https://github.com/taiyang-li)). +* Fix a bug that moving pieces to destination table may failed in case of launching multiple clickhouse-copiers. [#19743](https://github.com/ClickHouse/ClickHouse/pull/19743) ([madianjun](https://github.com/mdianjun)). +* Background thread which executes `ON CLUSTER` queries might hang waiting for dropped replicated table to do something. It's fixed. [#19684](https://github.com/ClickHouse/ClickHouse/pull/19684) ([yiguolei](https://github.com/yiguolei)). + +#### Build/Testing/Packaging Improvement + +* Allow to build ClickHouse with AVX-2 enabled globally. It gives slight performance benefits on modern CPUs. Not recommended for production and will not be supported as official build for now. [#20180](https://github.com/ClickHouse/ClickHouse/pull/20180) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Fix some of the issues found by Coverity. See [#19964](https://github.com/ClickHouse/ClickHouse/issues/19964). [#20010](https://github.com/ClickHouse/ClickHouse/pull/20010) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Allow to start up with modified binary under gdb. In previous version if you set up breakpoint in gdb before start, server will refuse to start up due to failed integrity check. [#21258](https://github.com/ClickHouse/ClickHouse/pull/21258) ([alexey-milovidov](https://github.com/alexey-milovidov)). +* Add a test for different compression methods in Kafka. [#21111](https://github.com/ClickHouse/ClickHouse/pull/21111) ([filimonov](https://github.com/filimonov)). +* Fixed port clash from test_storage_kerberized_hdfs test. [#19974](https://github.com/ClickHouse/ClickHouse/pull/19974) ([Ilya Yatsishin](https://github.com/qoega)). +* Print `stdout` and `stderr` to log when failed to start docker in integration tests. Before this PR there was a very short error message in this case which didn't help to investigate the problems. [#20631](https://github.com/ClickHouse/ClickHouse/pull/20631) ([Vitaly Baranov](https://github.com/vitlibar)). + + ## ClickHouse release 21.2 ### ClickHouse release v21.2.2.8-stable, 2021-02-07 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9002f1df140..d310f7c298c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,7 +155,6 @@ option(ENABLE_TESTS "Provide unit_test_dbms target with Google.Test unit tests" if (OS_LINUX AND NOT UNBUNDLED AND MAKE_STATIC_LIBRARIES AND NOT SPLIT_SHARED_LIBRARIES AND CMAKE_VERSION VERSION_GREATER "3.9.0") # Only for Linux, x86_64. - # Implies ${ENABLE_FASTMEMCPY} option(GLIBC_COMPATIBILITY "Enable compatibility with older glibc libraries." ON) elseif(GLIBC_COMPATIBILITY) message (${RECONFIGURE_MESSAGE_LEVEL} "Glibc compatibility cannot be enabled in current configuration") @@ -169,7 +168,7 @@ endif () set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic") if (OS_LINUX) - find_program (OBJCOPY_PATH NAMES "llvm-objcopy" "llvm-objcopy-11" "llvm-objcopy-10" "llvm-objcopy-9" "llvm-objcopy-8" "objcopy") + find_program (OBJCOPY_PATH NAMES "llvm-objcopy" "llvm-objcopy-12" "llvm-objcopy-11" "llvm-objcopy-10" "llvm-objcopy-9" "llvm-objcopy-8" "objcopy") if (OBJCOPY_PATH) message(STATUS "Using objcopy: ${OBJCOPY_PATH}.") @@ -241,9 +240,7 @@ else() message(STATUS "Disabling compiler -pipe option (have only ${AVAILABLE_PHYSICAL_MEMORY} mb of memory)") endif() -if(NOT DISABLE_CPU_OPTIMIZE) - include(cmake/cpu_features.cmake) -endif() +include(cmake/cpu_features.cmake) option(ARCH_NATIVE "Add -march=native compiler flag") @@ -331,7 +328,7 @@ if (COMPILER_CLANG) endif () # Always prefer llvm tools when using clang. For instance, we cannot use GNU ar when llvm LTO is enabled - find_program (LLVM_AR_PATH NAMES "llvm-ar" "llvm-ar-11" "llvm-ar-10" "llvm-ar-9" "llvm-ar-8") + find_program (LLVM_AR_PATH NAMES "llvm-ar" "llvm-ar-12" "llvm-ar-11" "llvm-ar-10" "llvm-ar-9" "llvm-ar-8") if (LLVM_AR_PATH) message(STATUS "Using llvm-ar: ${LLVM_AR_PATH}.") @@ -340,7 +337,7 @@ if (COMPILER_CLANG) message(WARNING "Cannot find llvm-ar. System ar will be used instead. It does not work with ThinLTO.") endif () - find_program (LLVM_RANLIB_PATH NAMES "llvm-ranlib" "llvm-ranlib-11" "llvm-ranlib-10" "llvm-ranlib-9" "llvm-ranlib-8") + find_program (LLVM_RANLIB_PATH NAMES "llvm-ranlib" "llvm-ranlib-12" "llvm-ranlib-11" "llvm-ranlib-10" "llvm-ranlib-9" "llvm-ranlib-8") if (LLVM_RANLIB_PATH) message(STATUS "Using llvm-ranlib: ${LLVM_RANLIB_PATH}.") @@ -536,7 +533,7 @@ macro (add_executable target) # explicitly acquire and interpose malloc symbols by clickhouse_malloc # if GLIBC_COMPATIBILITY is ON and ENABLE_THINLTO is on than provide memcpy symbol explicitly to neutrialize thinlto's libcall generation. if (GLIBC_COMPATIBILITY AND ENABLE_THINLTO) - _add_executable (${ARGV} $ $) + _add_executable (${ARGV} $ $) else () _add_executable (${ARGV} $) endif () diff --git a/base/common/CMakeLists.txt b/base/common/CMakeLists.txt index cea52b443dd..b4bf4f55466 100644 --- a/base/common/CMakeLists.txt +++ b/base/common/CMakeLists.txt @@ -74,7 +74,6 @@ target_link_libraries (common ${CITYHASH_LIBRARIES} boost::headers_only boost::system - FastMemcpy Poco::Net Poco::Net::SSL Poco::Util diff --git a/base/common/defines.h b/base/common/defines.h index 367bdd64234..ada8245f494 100644 --- a/base/common/defines.h +++ b/base/common/defines.h @@ -76,6 +76,16 @@ # endif #endif +#if !defined(UNDEFINED_BEHAVIOR_SANITIZER) +# if defined(__has_feature) +# if __has_feature(undefined_behavior_sanitizer) +# define UNDEFINED_BEHAVIOR_SANITIZER 1 +# endif +# elif defined(__UNDEFINED_BEHAVIOR_SANITIZER__) +# define UNDEFINED_BEHAVIOR_SANITIZER 1 +# endif +#endif + #if defined(ADDRESS_SANITIZER) # define BOOST_USE_ASAN 1 # define BOOST_USE_UCONTEXT 1 diff --git a/base/common/tests/CMakeLists.txt b/base/common/tests/CMakeLists.txt index b7082ee9900..6775d443fb6 100644 --- a/base/common/tests/CMakeLists.txt +++ b/base/common/tests/CMakeLists.txt @@ -11,7 +11,7 @@ set(PLATFORM_LIBS ${CMAKE_DL_LIBS}) target_link_libraries (date_lut2 PRIVATE common ${PLATFORM_LIBS}) target_link_libraries (date_lut3 PRIVATE common ${PLATFORM_LIBS}) target_link_libraries (date_lut_default_timezone PRIVATE common ${PLATFORM_LIBS}) -target_link_libraries (local_date_time_comparison PRIVATE common) +target_link_libraries (local_date_time_comparison PRIVATE common ${PLATFORM_LIBS}) target_link_libraries (realloc-perf PRIVATE common) add_check(local_date_time_comparison) diff --git a/base/common/wide_integer_impl.h b/base/common/wide_integer_impl.h index a34e757eaa5..5b981326e25 100644 --- a/base/common/wide_integer_impl.h +++ b/base/common/wide_integer_impl.h @@ -249,15 +249,15 @@ struct integer::_impl return; } - const T alpha = t / max_int; + const T alpha = t / static_cast(max_int); - if (alpha <= max_int) + if (alpha <= static_cast(max_int)) self = static_cast(alpha); else // max(double) / 2^64 will surely contain less than 52 precision bits, so speed up computations. set_multiplier(self, alpha); self *= max_int; - self += static_cast(t - alpha * max_int); // += b_i + self += static_cast(t - alpha * static_cast(max_int)); // += b_i } constexpr static void wide_integer_from_bultin(integer& self, double rhs) noexcept { @@ -275,7 +275,7 @@ struct integer::_impl "On your system long double has less than 64 precision bits," "which may result in UB when initializing double from int64_t"); - if ((rhs > 0 && rhs < max_int) || (rhs < 0 && rhs > min_int)) + if ((rhs > 0 && rhs < static_cast(max_int)) || (rhs < 0 && rhs > static_cast(min_int))) { self = static_cast(rhs); return; diff --git a/base/glibc-compatibility/CMakeLists.txt b/base/glibc-compatibility/CMakeLists.txt index 684c6162941..e785e2ab2ce 100644 --- a/base/glibc-compatibility/CMakeLists.txt +++ b/base/glibc-compatibility/CMakeLists.txt @@ -1,5 +1,8 @@ if (GLIBC_COMPATIBILITY) - set (ENABLE_FASTMEMCPY ON) + add_subdirectory(memcpy) + if(TARGET memcpy) + set(MEMCPY_LIBRARY memcpy) + endif() enable_language(ASM) include(CheckIncludeFile) @@ -27,13 +30,6 @@ if (GLIBC_COMPATIBILITY) list(APPEND glibc_compatibility_sources musl/getentropy.c) endif() - if (NOT ARCH_ARM) - # clickhouse_memcpy don't support ARCH_ARM, see https://github.com/ClickHouse/ClickHouse/issues/18951 - add_library (clickhouse_memcpy OBJECT - ${ClickHouse_SOURCE_DIR}/contrib/FastMemcpy/memcpy_wrapper.c - ) - endif() - # Need to omit frame pointers to match the performance of glibc set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer") @@ -51,15 +47,16 @@ if (GLIBC_COMPATIBILITY) target_compile_options(glibc-compatibility PRIVATE -fPIC) endif () - target_link_libraries(global-libs INTERFACE glibc-compatibility) + target_link_libraries(global-libs INTERFACE glibc-compatibility ${MEMCPY_LIBRARY}) install( - TARGETS glibc-compatibility + TARGETS glibc-compatibility ${MEMCPY_LIBRARY} EXPORT global ARCHIVE DESTINATION lib ) message (STATUS "Some symbols from glibc will be replaced for compatibility") + elseif (YANDEX_OFFICIAL_BUILD) message (WARNING "Option GLIBC_COMPATIBILITY must be turned on for production builds.") endif () diff --git a/base/glibc-compatibility/memcpy/CMakeLists.txt b/base/glibc-compatibility/memcpy/CMakeLists.txt new file mode 100644 index 00000000000..133995d9b96 --- /dev/null +++ b/base/glibc-compatibility/memcpy/CMakeLists.txt @@ -0,0 +1,8 @@ +if (ARCH_AMD64) + add_library(memcpy STATIC memcpy.cpp) + + # We allow to include memcpy.h from user code for better inlining. + target_include_directories(memcpy PUBLIC $) + + target_compile_options(memcpy PRIVATE -fno-builtin-memcpy) +endif () diff --git a/base/glibc-compatibility/memcpy/memcpy.cpp b/base/glibc-compatibility/memcpy/memcpy.cpp new file mode 100644 index 00000000000..ec43a2c3649 --- /dev/null +++ b/base/glibc-compatibility/memcpy/memcpy.cpp @@ -0,0 +1,6 @@ +#include "memcpy.h" + +extern "C" void * memcpy(void * __restrict dst, const void * __restrict src, size_t size) +{ + return inline_memcpy(dst, src, size); +} diff --git a/base/glibc-compatibility/memcpy/memcpy.h b/base/glibc-compatibility/memcpy/memcpy.h new file mode 100644 index 00000000000..f9f81bcb0fe --- /dev/null +++ b/base/glibc-compatibility/memcpy/memcpy.h @@ -0,0 +1,217 @@ +#include + +#include + + +/** Custom memcpy implementation for ClickHouse. + * It has the following benefits over using glibc's implementation: + * 1. Avoiding dependency on specific version of glibc's symbol, like memcpy@@GLIBC_2.14 for portability. + * 2. Avoiding indirect call via PLT due to shared linking, that can be less efficient. + * 3. It's possible to include this header and call inline_memcpy directly for better inlining or interprocedural analysis. + * 4. Better results on our performance tests on current CPUs: up to 25% on some queries and up to 0.7%..1% in average across all queries. + * + * Writing our own memcpy is extremely difficult for the following reasons: + * 1. The optimal variant depends on the specific CPU model. + * 2. The optimal variant depends on the distribution of size arguments. + * 3. It depends on the number of threads copying data concurrently. + * 4. It also depends on how the calling code is using the copied data and how the different memcpy calls are related to each other. + * Due to vast range of scenarios it makes proper testing especially difficult. + * When writing our own memcpy there is a risk to overoptimize it + * on non-representative microbenchmarks while making real-world use cases actually worse. + * + * Most of the benchmarks for memcpy on the internet are wrong. + * + * Let's look at the details: + * + * For small size, the order of branches in code is important. + * There are variants with specific order of branches (like here or in glibc) + * or with jump table (in asm code see example from Cosmopolitan libc: + * https://github.com/jart/cosmopolitan/blob/de09bec215675e9b0beb722df89c6f794da74f3f/libc/nexgen32e/memcpy.S#L61) + * or with Duff device in C (see https://github.com/skywind3000/FastMemcpy/) + * + * It's also important how to copy uneven sizes. + * Almost every implementation, including this, is using two overlapping movs. + * + * It is important to disable -ftree-loop-distribute-patterns when compiling memcpy implementation, + * otherwise the compiler can replace internal loops to a call to memcpy that will lead to infinite recursion. + * + * For larger sizes it's important to choose the instructions used: + * - SSE or AVX or AVX-512; + * - rep movsb; + * Performance will depend on the size threshold, on the CPU model, on the "erms" flag + * ("Enhansed Rep MovS" - it indicates that performance of "rep movsb" is decent for large sizes) + * https://stackoverflow.com/questions/43343231/enhanced-rep-movsb-for-memcpy + * + * Using AVX-512 can be bad due to throttling. + * Using AVX can be bad if most code is using SSE due to switching penalty + * (it also depends on the usage of "vzeroupper" instruction). + * But in some cases AVX gives a win. + * + * It also depends on how many times the loop will be unrolled. + * We are unrolling the loop 8 times (by the number of available registers), but it not always the best. + * + * It also depends on the usage of aligned or unaligned loads/stores. + * We are using unaligned loads and aligned stores. + * + * It also depends on the usage of prefetch instructions. It makes sense on some Intel CPUs but can slow down performance on AMD. + * Setting up correct offset for prefetching is non-obvious. + * + * Non-temporary (cache bypassing) stores can be used for very large sizes (more than a half of L3 cache). + * But the exact threshold is unclear - when doing memcpy from multiple threads the optimal threshold can be lower, + * because L3 cache is shared (and L2 cache is partially shared). + * + * Very large size of memcpy typically indicates suboptimal (not cache friendly) algorithms in code or unrealistic scenarios, + * so we don't pay attention to using non-temporary stores. + * + * On recent Intel CPUs, the presence of "erms" makes "rep movsb" the most benefitial, + * even comparing to non-temporary aligned unrolled stores even with the most wide registers. + * + * memcpy can be written in asm, C or C++. The latter can also use inline asm. + * The asm implementation can be better to make sure that compiler won't make the code worse, + * to ensure the order of branches, the code layout, the usage of all required registers. + * But if it is located in separate translation unit, inlining will not be possible + * (inline asm can be used to overcome this limitation). + * Sometimes C or C++ code can be further optimized by compiler. + * For example, clang is capable replacing SSE intrinsics to AVX code if -mavx is used. + * + * Please note that compiler can replace plain code to memcpy and vice versa. + * - memcpy with compile-time known small size is replaced to simple instructions without a call to memcpy; + * it is controlled by -fbuiltin-memcpy and can be manually ensured by calling __builtin_memcpy. + * This is often used to implement unaligned load/store without undefined behaviour in C++. + * - a loop with copying bytes can be recognized and replaced by a call to memcpy; + * it is controlled by -ftree-loop-distribute-patterns. + * - also note that a loop with copying bytes can be unrolled, peeled and vectorized that will give you + * inline code somewhat similar to a decent implementation of memcpy. + * + * This description is up to date as of Mar 2021. + * + * How to test the memcpy implementation for performance: + * 1. Test on real production workload. + * 2. For synthetic test, see utils/memcpy-bench, but make sure you will do the best to exhaust the wide range of scenarios. + * + * TODO: Add self-tuning memcpy with bayesian bandits algorithm for large sizes. + * See https://habr.com/en/company/yandex/blog/457612/ + */ + + +static inline void * inline_memcpy(void * __restrict dst_, const void * __restrict src_, size_t size) +{ + /// We will use pointer arithmetic, so char pointer will be used. + /// Note that __restrict makes sense (otherwise compiler will reload data from memory + /// instead of using the value of registers due to possible aliasing). + char * __restrict dst = reinterpret_cast(dst_); + const char * __restrict src = reinterpret_cast(src_); + + /// Standard memcpy returns the original value of dst. It is rarely used but we have to do it. + /// If you use memcpy with small but non-constant sizes, you can call inline_memcpy directly + /// for inlining and removing this single instruction. + void * ret = dst; + +tail: + /// Small sizes and tails after the loop for large sizes. + /// The order of branches is important but in fact the optimal order depends on the distribution of sizes in your application. + /// This order of branches is from the disassembly of glibc's code. + /// We copy chunks of possibly uneven size with two overlapping movs. + /// Example: to copy 5 bytes [0, 1, 2, 3, 4] we will copy tail [1, 2, 3, 4] first and then head [0, 1, 2, 3]. + if (size <= 16) + { + if (size >= 8) + { + /// Chunks of 8..16 bytes. + __builtin_memcpy(dst + size - 8, src + size - 8, 8); + __builtin_memcpy(dst, src, 8); + } + else if (size >= 4) + { + /// Chunks of 4..7 bytes. + __builtin_memcpy(dst + size - 4, src + size - 4, 4); + __builtin_memcpy(dst, src, 4); + } + else if (size >= 2) + { + /// Chunks of 2..3 bytes. + __builtin_memcpy(dst + size - 2, src + size - 2, 2); + __builtin_memcpy(dst, src, 2); + } + else if (size >= 1) + { + /// A single byte. + *dst = *src; + } + /// No bytes remaining. + } + else + { + /// Medium and large sizes. + if (size <= 128) + { + /// Medium size, not enough for full loop unrolling. + + /// We will copy the last 16 bytes. + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + size - 16), _mm_loadu_si128(reinterpret_cast(src + size - 16))); + + /// Then we will copy every 16 bytes from the beginning in a loop. + /// The last loop iteration will possibly overwrite some part of already copied last 16 bytes. + /// This is Ok, similar to the code for small sizes above. + while (size > 16) + { + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), _mm_loadu_si128(reinterpret_cast(src))); + dst += 16; + src += 16; + size -= 16; + } + } + else + { + /// Large size with fully unrolled loop. + + /// Align destination to 16 bytes boundary. + size_t padding = (16 - (reinterpret_cast(dst) & 15)) & 15; + + /// If not aligned - we will copy first 16 bytes with unaligned stores. + if (padding > 0) + { + __m128i head = _mm_loadu_si128(reinterpret_cast(src)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), head); + dst += padding; + src += padding; + size -= padding; + } + + /// Aligned unrolled copy. We will use all available SSE registers. + /// It's not possible to have both src and dst aligned. + /// So, we will use aligned stores and unaligned loads. + __m128i c0, c1, c2, c3, c4, c5, c6, c7; + + while (size >= 128) + { + c0 = _mm_loadu_si128(reinterpret_cast(src) + 0); + c1 = _mm_loadu_si128(reinterpret_cast(src) + 1); + c2 = _mm_loadu_si128(reinterpret_cast(src) + 2); + c3 = _mm_loadu_si128(reinterpret_cast(src) + 3); + c4 = _mm_loadu_si128(reinterpret_cast(src) + 4); + c5 = _mm_loadu_si128(reinterpret_cast(src) + 5); + c6 = _mm_loadu_si128(reinterpret_cast(src) + 6); + c7 = _mm_loadu_si128(reinterpret_cast(src) + 7); + src += 128; + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 0), c0); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 1), c1); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 2), c2); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 3), c3); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 4), c4); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 5), c5); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 6), c6); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 7), c7); + dst += 128; + + size -= 128; + } + + /// The latest remaining 0..127 bytes will be processed as usual. + goto tail; + } + } + + return ret; +} + diff --git a/base/mysqlxx/Pool.cpp b/base/mysqlxx/Pool.cpp index cf8b3cf9267..386b4544b78 100644 --- a/base/mysqlxx/Pool.cpp +++ b/base/mysqlxx/Pool.cpp @@ -174,9 +174,11 @@ Pool::Entry Pool::tryGet() /// Fixme: There is a race condition here b/c we do not synchronize with Pool::Entry's copy-assignment operator if (connection_ptr->ref_count == 0) { - Entry res(connection_ptr, this); - if (res.tryForceConnected()) /// Tries to reestablish connection as well - return res; + { + Entry res(connection_ptr, this); + if (res.tryForceConnected()) /// Tries to reestablish connection as well + return res; + } logger.debug("(%s): Idle connection to MySQL server cannot be recovered, dropping it.", getDescription()); diff --git a/base/readpassphrase/CMakeLists.txt b/base/readpassphrase/CMakeLists.txt index 574130ce6e3..51b12106eca 100644 --- a/base/readpassphrase/CMakeLists.txt +++ b/base/readpassphrase/CMakeLists.txt @@ -4,5 +4,5 @@ add_library(readpassphrase readpassphrase.c) set_target_properties(readpassphrase PROPERTIES LINKER_LANGUAGE C) -target_compile_options(readpassphrase PRIVATE -Wno-unused-result -Wno-reserved-id-macro) +target_compile_options(readpassphrase PRIVATE -Wno-unused-result -Wno-reserved-id-macro -Wno-disabled-macro-expansion) target_include_directories(readpassphrase PUBLIC .) diff --git a/base/readpassphrase/readpassphrase.c b/base/readpassphrase/readpassphrase.c index 9e8097643bb..8a7d3153915 100644 --- a/base/readpassphrase/readpassphrase.c +++ b/base/readpassphrase/readpassphrase.c @@ -94,7 +94,7 @@ restart: if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { memcpy(&term, &oterm, sizeof(term)); if (!(flags & RPP_ECHO_ON)) - term.c_lflag &= ~(ECHO | ECHONL); + term.c_lflag &= ~((unsigned int) (ECHO | ECHONL)); #ifdef VSTATUS if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) term.c_cc[VSTATUS] = _POSIX_VDISABLE; diff --git a/cmake/find/krb5.cmake b/cmake/find/krb5.cmake index bd9c8e239cd..49b7462b710 100644 --- a/cmake/find/krb5.cmake +++ b/cmake/find/krb5.cmake @@ -5,8 +5,8 @@ if (NOT EXISTS "${ClickHouse_SOURCE_DIR}/contrib/krb5/README") set (ENABLE_KRB5 0) endif () -if (NOT CMAKE_SYSTEM_NAME MATCHES "Linux") - message (WARNING "krb5 disabled in non-Linux environments") +if (NOT CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT (CMAKE_SYSTEM_NAME MATCHES "Darwin" AND NOT CMAKE_CROSSCOMPILING)) + message (WARNING "krb5 disabled in non-Linux and non-native-Darwin environments") set (ENABLE_KRB5 0) endif () diff --git a/cmake/tools.cmake b/cmake/tools.cmake index cc4046d2469..abb11843d59 100644 --- a/cmake/tools.cmake +++ b/cmake/tools.cmake @@ -75,8 +75,13 @@ if (OS_LINUX AND NOT LINKER_NAME) endif () if (LINKER_NAME) - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=${LINKER_NAME}") - set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=${LINKER_NAME}") + if (COMPILER_CLANG AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 12.0.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 12.0.0)) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --ld-path=${LINKER_NAME}") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --ld-path=${LINKER_NAME}") + else () + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=${LINKER_NAME}") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=${LINKER_NAME}") + endif () message(STATUS "Using custom linker by name: ${LINKER_NAME}") endif () diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index bf4bf5eb472..6a56b4cc733 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -38,7 +38,6 @@ add_subdirectory (boost-cmake) add_subdirectory (cctz-cmake) add_subdirectory (consistent-hashing) add_subdirectory (dragonbox-cmake) -add_subdirectory (FastMemcpy) add_subdirectory (hyperscan-cmake) add_subdirectory (jemalloc-cmake) add_subdirectory (libcpuid-cmake) diff --git a/contrib/FastMemcpy/CMakeLists.txt b/contrib/FastMemcpy/CMakeLists.txt deleted file mode 100644 index 8efe6d45dff..00000000000 --- a/contrib/FastMemcpy/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -option (ENABLE_FASTMEMCPY "Enable FastMemcpy library (only internal)" ${ENABLE_LIBRARIES}) - -if (NOT OS_LINUX OR ARCH_AARCH64) - set (ENABLE_FASTMEMCPY OFF) -endif () - -if (ENABLE_FASTMEMCPY) - set (LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/FastMemcpy) - - set (SRCS - ${LIBRARY_DIR}/FastMemcpy.c - - memcpy_wrapper.c - ) - - add_library (FastMemcpy ${SRCS}) - target_include_directories (FastMemcpy PUBLIC ${LIBRARY_DIR}) - - target_compile_definitions(FastMemcpy PUBLIC USE_FASTMEMCPY=1) - - message (STATUS "Using FastMemcpy") -else () - add_library (FastMemcpy INTERFACE) - - target_compile_definitions(FastMemcpy INTERFACE USE_FASTMEMCPY=0) - - message (STATUS "Not using FastMemcpy") -endif () diff --git a/contrib/FastMemcpy/FastMemcpy.c b/contrib/FastMemcpy/FastMemcpy.c deleted file mode 100644 index 5021bcc7d16..00000000000 --- a/contrib/FastMemcpy/FastMemcpy.c +++ /dev/null @@ -1,220 +0,0 @@ -//===================================================================== -// -// FastMemcpy.c - skywind3000@163.com, 2015 -// -// feature: -// 50% speed up in avg. vs standard memcpy (tested in vc2012/gcc4.9) -// -//===================================================================== -#include -#include -#include -#include - -#if (defined(_WIN32) || defined(WIN32)) -#include -#include -#ifdef _MSC_VER -#pragma comment(lib, "winmm.lib") -#endif -#elif defined(__unix) -#include -#include -#else -#error it can only be compiled under windows or unix -#endif - -#include "FastMemcpy.h" - -unsigned int gettime() -{ - #if (defined(_WIN32) || defined(WIN32)) - return timeGetTime(); - #else - static struct timezone tz={ 0,0 }; - struct timeval time; - gettimeofday(&time,&tz); - return (time.tv_sec * 1000 + time.tv_usec / 1000); - #endif -} - -void sleepms(unsigned int millisec) -{ -#if defined(_WIN32) || defined(WIN32) - Sleep(millisec); -#else - usleep(millisec * 1000); -#endif -} - - -void benchmark(int dstalign, int srcalign, size_t size, int times) -{ - char *DATA1 = (char*)malloc(size + 64); - char *DATA2 = (char*)malloc(size + 64); - size_t LINEAR1 = ((size_t)DATA1); - size_t LINEAR2 = ((size_t)DATA2); - char *ALIGN1 = (char*)(((64 - (LINEAR1 & 63)) & 63) + LINEAR1); - char *ALIGN2 = (char*)(((64 - (LINEAR2 & 63)) & 63) + LINEAR2); - char *dst = (dstalign)? ALIGN1 : (ALIGN1 + 1); - char *src = (srcalign)? ALIGN2 : (ALIGN2 + 3); - unsigned int t1, t2; - int k; - - sleepms(100); - t1 = gettime(); - for (k = times; k > 0; k--) { - memcpy(dst, src, size); - } - t1 = gettime() - t1; - sleepms(100); - t2 = gettime(); - for (k = times; k > 0; k--) { - memcpy_fast(dst, src, size); - } - t2 = gettime() - t2; - - free(DATA1); - free(DATA2); - - printf("result(dst %s, src %s): memcpy_fast=%dms memcpy=%d ms\n", - dstalign? "aligned" : "unalign", - srcalign? "aligned" : "unalign", (int)t2, (int)t1); -} - - -void bench(int copysize, int times) -{ - printf("benchmark(size=%d bytes, times=%d):\n", copysize, times); - benchmark(1, 1, copysize, times); - benchmark(1, 0, copysize, times); - benchmark(0, 1, copysize, times); - benchmark(0, 0, copysize, times); - printf("\n"); -} - - -void random_bench(int maxsize, int times) -{ - static char A[11 * 1024 * 1024 + 2]; - static char B[11 * 1024 * 1024 + 2]; - static int random_offsets[0x10000]; - static int random_sizes[0x8000]; - unsigned int i, p1, p2; - unsigned int t1, t2; - for (i = 0; i < 0x10000; i++) { // generate random offsets - random_offsets[i] = rand() % (10 * 1024 * 1024 + 1); - } - for (i = 0; i < 0x8000; i++) { // generate random sizes - random_sizes[i] = 1 + rand() % maxsize; - } - sleepms(100); - t1 = gettime(); - for (p1 = 0, p2 = 0, i = 0; i < times; i++) { - int offset1 = random_offsets[(p1++) & 0xffff]; - int offset2 = random_offsets[(p1++) & 0xffff]; - int size = random_sizes[(p2++) & 0x7fff]; - memcpy(A + offset1, B + offset2, size); - } - t1 = gettime() - t1; - sleepms(100); - t2 = gettime(); - for (p1 = 0, p2 = 0, i = 0; i < times; i++) { - int offset1 = random_offsets[(p1++) & 0xffff]; - int offset2 = random_offsets[(p1++) & 0xffff]; - int size = random_sizes[(p2++) & 0x7fff]; - memcpy_fast(A + offset1, B + offset2, size); - } - t2 = gettime() - t2; - printf("benchmark random access:\n"); - printf("memcpy_fast=%dms memcpy=%dms\n\n", (int)t2, (int)t1); -} - - -#ifdef _MSC_VER -#pragma comment(lib, "winmm.lib") -#endif - -int main(void) -{ - bench(32, 0x1000000); - bench(64, 0x1000000); - bench(512, 0x800000); - bench(1024, 0x400000); - bench(4096, 0x80000); - bench(8192, 0x40000); - bench(1024 * 1024 * 1, 0x800); - bench(1024 * 1024 * 4, 0x200); - bench(1024 * 1024 * 8, 0x100); - - random_bench(2048, 8000000); - - return 0; -} - - - - -/* -benchmark(size=32 bytes, times=16777216): -result(dst aligned, src aligned): memcpy_fast=78ms memcpy=260 ms -result(dst aligned, src unalign): memcpy_fast=78ms memcpy=250 ms -result(dst unalign, src aligned): memcpy_fast=78ms memcpy=266 ms -result(dst unalign, src unalign): memcpy_fast=78ms memcpy=234 ms - -benchmark(size=64 bytes, times=16777216): -result(dst aligned, src aligned): memcpy_fast=109ms memcpy=281 ms -result(dst aligned, src unalign): memcpy_fast=109ms memcpy=328 ms -result(dst unalign, src aligned): memcpy_fast=109ms memcpy=343 ms -result(dst unalign, src unalign): memcpy_fast=93ms memcpy=344 ms - -benchmark(size=512 bytes, times=8388608): -result(dst aligned, src aligned): memcpy_fast=125ms memcpy=218 ms -result(dst aligned, src unalign): memcpy_fast=156ms memcpy=484 ms -result(dst unalign, src aligned): memcpy_fast=172ms memcpy=546 ms -result(dst unalign, src unalign): memcpy_fast=172ms memcpy=515 ms - -benchmark(size=1024 bytes, times=4194304): -result(dst aligned, src aligned): memcpy_fast=109ms memcpy=172 ms -result(dst aligned, src unalign): memcpy_fast=187ms memcpy=453 ms -result(dst unalign, src aligned): memcpy_fast=172ms memcpy=437 ms -result(dst unalign, src unalign): memcpy_fast=156ms memcpy=452 ms - -benchmark(size=4096 bytes, times=524288): -result(dst aligned, src aligned): memcpy_fast=62ms memcpy=78 ms -result(dst aligned, src unalign): memcpy_fast=109ms memcpy=202 ms -result(dst unalign, src aligned): memcpy_fast=94ms memcpy=203 ms -result(dst unalign, src unalign): memcpy_fast=110ms memcpy=218 ms - -benchmark(size=8192 bytes, times=262144): -result(dst aligned, src aligned): memcpy_fast=62ms memcpy=78 ms -result(dst aligned, src unalign): memcpy_fast=78ms memcpy=202 ms -result(dst unalign, src aligned): memcpy_fast=78ms memcpy=203 ms -result(dst unalign, src unalign): memcpy_fast=94ms memcpy=203 ms - -benchmark(size=1048576 bytes, times=2048): -result(dst aligned, src aligned): memcpy_fast=203ms memcpy=191 ms -result(dst aligned, src unalign): memcpy_fast=219ms memcpy=281 ms -result(dst unalign, src aligned): memcpy_fast=218ms memcpy=328 ms -result(dst unalign, src unalign): memcpy_fast=218ms memcpy=312 ms - -benchmark(size=4194304 bytes, times=512): -result(dst aligned, src aligned): memcpy_fast=312ms memcpy=406 ms -result(dst aligned, src unalign): memcpy_fast=296ms memcpy=421 ms -result(dst unalign, src aligned): memcpy_fast=312ms memcpy=468 ms -result(dst unalign, src unalign): memcpy_fast=297ms memcpy=452 ms - -benchmark(size=8388608 bytes, times=256): -result(dst aligned, src aligned): memcpy_fast=281ms memcpy=452 ms -result(dst aligned, src unalign): memcpy_fast=280ms memcpy=468 ms -result(dst unalign, src aligned): memcpy_fast=298ms memcpy=514 ms -result(dst unalign, src unalign): memcpy_fast=344ms memcpy=472 ms - -benchmark random access: -memcpy_fast=515ms memcpy=1014ms - -*/ - - - - diff --git a/contrib/FastMemcpy/FastMemcpy.h b/contrib/FastMemcpy/FastMemcpy.h deleted file mode 100644 index 5dcbfcf1656..00000000000 --- a/contrib/FastMemcpy/FastMemcpy.h +++ /dev/null @@ -1,694 +0,0 @@ -//===================================================================== -// -// FastMemcpy.c - skywind3000@163.com, 2015 -// -// feature: -// 50% speed up in avg. vs standard memcpy (tested in vc2012/gcc5.1) -// -//===================================================================== -#ifndef __FAST_MEMCPY_H__ -#define __FAST_MEMCPY_H__ - -#include -#include -#include - - -//--------------------------------------------------------------------- -// force inline for compilers -//--------------------------------------------------------------------- -#ifndef INLINE -#ifdef __GNUC__ -#if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) - #define INLINE __inline__ __attribute__((always_inline)) -#else - #define INLINE __inline__ -#endif -#elif defined(_MSC_VER) - #define INLINE __forceinline -#elif (defined(__BORLANDC__) || defined(__WATCOMC__)) - #define INLINE __inline -#else - #define INLINE -#endif -#endif - -typedef __attribute__((__aligned__(1))) uint16_t uint16_unaligned_t; -typedef __attribute__((__aligned__(1))) uint32_t uint32_unaligned_t; -typedef __attribute__((__aligned__(1))) uint64_t uint64_unaligned_t; - -//--------------------------------------------------------------------- -// fast copy for different sizes -//--------------------------------------------------------------------- -static INLINE void memcpy_sse2_16(void *dst, const void *src) { - __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); - _mm_storeu_si128(((__m128i*)dst) + 0, m0); -} - -static INLINE void memcpy_sse2_32(void *dst, const void *src) { - __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); - __m128i m1 = _mm_loadu_si128(((const __m128i*)src) + 1); - _mm_storeu_si128(((__m128i*)dst) + 0, m0); - _mm_storeu_si128(((__m128i*)dst) + 1, m1); -} - -static INLINE void memcpy_sse2_64(void *dst, const void *src) { - __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); - __m128i m1 = _mm_loadu_si128(((const __m128i*)src) + 1); - __m128i m2 = _mm_loadu_si128(((const __m128i*)src) + 2); - __m128i m3 = _mm_loadu_si128(((const __m128i*)src) + 3); - _mm_storeu_si128(((__m128i*)dst) + 0, m0); - _mm_storeu_si128(((__m128i*)dst) + 1, m1); - _mm_storeu_si128(((__m128i*)dst) + 2, m2); - _mm_storeu_si128(((__m128i*)dst) + 3, m3); -} - -static INLINE void memcpy_sse2_128(void *dst, const void *src) { - __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); - __m128i m1 = _mm_loadu_si128(((const __m128i*)src) + 1); - __m128i m2 = _mm_loadu_si128(((const __m128i*)src) + 2); - __m128i m3 = _mm_loadu_si128(((const __m128i*)src) + 3); - __m128i m4 = _mm_loadu_si128(((const __m128i*)src) + 4); - __m128i m5 = _mm_loadu_si128(((const __m128i*)src) + 5); - __m128i m6 = _mm_loadu_si128(((const __m128i*)src) + 6); - __m128i m7 = _mm_loadu_si128(((const __m128i*)src) + 7); - _mm_storeu_si128(((__m128i*)dst) + 0, m0); - _mm_storeu_si128(((__m128i*)dst) + 1, m1); - _mm_storeu_si128(((__m128i*)dst) + 2, m2); - _mm_storeu_si128(((__m128i*)dst) + 3, m3); - _mm_storeu_si128(((__m128i*)dst) + 4, m4); - _mm_storeu_si128(((__m128i*)dst) + 5, m5); - _mm_storeu_si128(((__m128i*)dst) + 6, m6); - _mm_storeu_si128(((__m128i*)dst) + 7, m7); -} - - -//--------------------------------------------------------------------- -// tiny memory copy with jump table optimized -//--------------------------------------------------------------------- -/// Attribute is used to avoid an error with undefined behaviour sanitizer -/// ../contrib/FastMemcpy/FastMemcpy.h:91:56: runtime error: applying zero offset to null pointer -/// Found by 01307_orc_output_format.sh, cause - ORCBlockInputFormat and external ORC library. -__attribute__((__no_sanitize__("undefined"))) static INLINE void *memcpy_tiny(void *dst, const void *src, size_t size) { - unsigned char *dd = ((unsigned char*)dst) + size; - const unsigned char *ss = ((const unsigned char*)src) + size; - - switch (size) { - case 64: - memcpy_sse2_64(dd - 64, ss - 64); - case 0: - break; - - case 65: - memcpy_sse2_64(dd - 65, ss - 65); - case 1: - dd[-1] = ss[-1]; - break; - - case 66: - memcpy_sse2_64(dd - 66, ss - 66); - case 2: - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 67: - memcpy_sse2_64(dd - 67, ss - 67); - case 3: - *((uint16_unaligned_t*)(dd - 3)) = *((uint16_unaligned_t*)(ss - 3)); - dd[-1] = ss[-1]; - break; - - case 68: - memcpy_sse2_64(dd - 68, ss - 68); - case 4: - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 69: - memcpy_sse2_64(dd - 69, ss - 69); - case 5: - *((uint32_unaligned_t*)(dd - 5)) = *((uint32_unaligned_t*)(ss - 5)); - dd[-1] = ss[-1]; - break; - - case 70: - memcpy_sse2_64(dd - 70, ss - 70); - case 6: - *((uint32_unaligned_t*)(dd - 6)) = *((uint32_unaligned_t*)(ss - 6)); - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 71: - memcpy_sse2_64(dd - 71, ss - 71); - case 7: - *((uint32_unaligned_t*)(dd - 7)) = *((uint32_unaligned_t*)(ss - 7)); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 72: - memcpy_sse2_64(dd - 72, ss - 72); - case 8: - *((uint64_unaligned_t*)(dd - 8)) = *((uint64_unaligned_t*)(ss - 8)); - break; - - case 73: - memcpy_sse2_64(dd - 73, ss - 73); - case 9: - *((uint64_unaligned_t*)(dd - 9)) = *((uint64_unaligned_t*)(ss - 9)); - dd[-1] = ss[-1]; - break; - - case 74: - memcpy_sse2_64(dd - 74, ss - 74); - case 10: - *((uint64_unaligned_t*)(dd - 10)) = *((uint64_unaligned_t*)(ss - 10)); - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 75: - memcpy_sse2_64(dd - 75, ss - 75); - case 11: - *((uint64_unaligned_t*)(dd - 11)) = *((uint64_unaligned_t*)(ss - 11)); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 76: - memcpy_sse2_64(dd - 76, ss - 76); - case 12: - *((uint64_unaligned_t*)(dd - 12)) = *((uint64_unaligned_t*)(ss - 12)); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 77: - memcpy_sse2_64(dd - 77, ss - 77); - case 13: - *((uint64_unaligned_t*)(dd - 13)) = *((uint64_unaligned_t*)(ss - 13)); - *((uint32_unaligned_t*)(dd - 5)) = *((uint32_unaligned_t*)(ss - 5)); - dd[-1] = ss[-1]; - break; - - case 78: - memcpy_sse2_64(dd - 78, ss - 78); - case 14: - *((uint64_unaligned_t*)(dd - 14)) = *((uint64_unaligned_t*)(ss - 14)); - *((uint64_unaligned_t*)(dd - 8)) = *((uint64_unaligned_t*)(ss - 8)); - break; - - case 79: - memcpy_sse2_64(dd - 79, ss - 79); - case 15: - *((uint64_unaligned_t*)(dd - 15)) = *((uint64_unaligned_t*)(ss - 15)); - *((uint64_unaligned_t*)(dd - 8)) = *((uint64_unaligned_t*)(ss - 8)); - break; - - case 80: - memcpy_sse2_64(dd - 80, ss - 80); - case 16: - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 81: - memcpy_sse2_64(dd - 81, ss - 81); - case 17: - memcpy_sse2_16(dd - 17, ss - 17); - dd[-1] = ss[-1]; - break; - - case 82: - memcpy_sse2_64(dd - 82, ss - 82); - case 18: - memcpy_sse2_16(dd - 18, ss - 18); - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 83: - memcpy_sse2_64(dd - 83, ss - 83); - case 19: - memcpy_sse2_16(dd - 19, ss - 19); - *((uint16_unaligned_t*)(dd - 3)) = *((uint16_unaligned_t*)(ss - 3)); - dd[-1] = ss[-1]; - break; - - case 84: - memcpy_sse2_64(dd - 84, ss - 84); - case 20: - memcpy_sse2_16(dd - 20, ss - 20); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 85: - memcpy_sse2_64(dd - 85, ss - 85); - case 21: - memcpy_sse2_16(dd - 21, ss - 21); - *((uint32_unaligned_t*)(dd - 5)) = *((uint32_unaligned_t*)(ss - 5)); - dd[-1] = ss[-1]; - break; - - case 86: - memcpy_sse2_64(dd - 86, ss - 86); - case 22: - memcpy_sse2_16(dd - 22, ss - 22); - *((uint32_unaligned_t*)(dd - 6)) = *((uint32_unaligned_t*)(ss - 6)); - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 87: - memcpy_sse2_64(dd - 87, ss - 87); - case 23: - memcpy_sse2_16(dd - 23, ss - 23); - *((uint32_unaligned_t*)(dd - 7)) = *((uint32_unaligned_t*)(ss - 7)); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 88: - memcpy_sse2_64(dd - 88, ss - 88); - case 24: - memcpy_sse2_16(dd - 24, ss - 24); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 89: - memcpy_sse2_64(dd - 89, ss - 89); - case 25: - memcpy_sse2_16(dd - 25, ss - 25); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 90: - memcpy_sse2_64(dd - 90, ss - 90); - case 26: - memcpy_sse2_16(dd - 26, ss - 26); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 91: - memcpy_sse2_64(dd - 91, ss - 91); - case 27: - memcpy_sse2_16(dd - 27, ss - 27); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 92: - memcpy_sse2_64(dd - 92, ss - 92); - case 28: - memcpy_sse2_16(dd - 28, ss - 28); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 93: - memcpy_sse2_64(dd - 93, ss - 93); - case 29: - memcpy_sse2_16(dd - 29, ss - 29); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 94: - memcpy_sse2_64(dd - 94, ss - 94); - case 30: - memcpy_sse2_16(dd - 30, ss - 30); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 95: - memcpy_sse2_64(dd - 95, ss - 95); - case 31: - memcpy_sse2_16(dd - 31, ss - 31); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 96: - memcpy_sse2_64(dd - 96, ss - 96); - case 32: - memcpy_sse2_32(dd - 32, ss - 32); - break; - - case 97: - memcpy_sse2_64(dd - 97, ss - 97); - case 33: - memcpy_sse2_32(dd - 33, ss - 33); - dd[-1] = ss[-1]; - break; - - case 98: - memcpy_sse2_64(dd - 98, ss - 98); - case 34: - memcpy_sse2_32(dd - 34, ss - 34); - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 99: - memcpy_sse2_64(dd - 99, ss - 99); - case 35: - memcpy_sse2_32(dd - 35, ss - 35); - *((uint16_unaligned_t*)(dd - 3)) = *((uint16_unaligned_t*)(ss - 3)); - dd[-1] = ss[-1]; - break; - - case 100: - memcpy_sse2_64(dd - 100, ss - 100); - case 36: - memcpy_sse2_32(dd - 36, ss - 36); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 101: - memcpy_sse2_64(dd - 101, ss - 101); - case 37: - memcpy_sse2_32(dd - 37, ss - 37); - *((uint32_unaligned_t*)(dd - 5)) = *((uint32_unaligned_t*)(ss - 5)); - dd[-1] = ss[-1]; - break; - - case 102: - memcpy_sse2_64(dd - 102, ss - 102); - case 38: - memcpy_sse2_32(dd - 38, ss - 38); - *((uint32_unaligned_t*)(dd - 6)) = *((uint32_unaligned_t*)(ss - 6)); - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 103: - memcpy_sse2_64(dd - 103, ss - 103); - case 39: - memcpy_sse2_32(dd - 39, ss - 39); - *((uint32_unaligned_t*)(dd - 7)) = *((uint32_unaligned_t*)(ss - 7)); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 104: - memcpy_sse2_64(dd - 104, ss - 104); - case 40: - memcpy_sse2_32(dd - 40, ss - 40); - *((uint64_unaligned_t*)(dd - 8)) = *((uint64_unaligned_t*)(ss - 8)); - break; - - case 105: - memcpy_sse2_64(dd - 105, ss - 105); - case 41: - memcpy_sse2_32(dd - 41, ss - 41); - *((uint64_unaligned_t*)(dd - 9)) = *((uint64_unaligned_t*)(ss - 9)); - dd[-1] = ss[-1]; - break; - - case 106: - memcpy_sse2_64(dd - 106, ss - 106); - case 42: - memcpy_sse2_32(dd - 42, ss - 42); - *((uint64_unaligned_t*)(dd - 10)) = *((uint64_unaligned_t*)(ss - 10)); - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 107: - memcpy_sse2_64(dd - 107, ss - 107); - case 43: - memcpy_sse2_32(dd - 43, ss - 43); - *((uint64_unaligned_t*)(dd - 11)) = *((uint64_unaligned_t*)(ss - 11)); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 108: - memcpy_sse2_64(dd - 108, ss - 108); - case 44: - memcpy_sse2_32(dd - 44, ss - 44); - *((uint64_unaligned_t*)(dd - 12)) = *((uint64_unaligned_t*)(ss - 12)); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 109: - memcpy_sse2_64(dd - 109, ss - 109); - case 45: - memcpy_sse2_32(dd - 45, ss - 45); - *((uint64_unaligned_t*)(dd - 13)) = *((uint64_unaligned_t*)(ss - 13)); - *((uint32_unaligned_t*)(dd - 5)) = *((uint32_unaligned_t*)(ss - 5)); - dd[-1] = ss[-1]; - break; - - case 110: - memcpy_sse2_64(dd - 110, ss - 110); - case 46: - memcpy_sse2_32(dd - 46, ss - 46); - *((uint64_unaligned_t*)(dd - 14)) = *((uint64_unaligned_t*)(ss - 14)); - *((uint64_unaligned_t*)(dd - 8)) = *((uint64_unaligned_t*)(ss - 8)); - break; - - case 111: - memcpy_sse2_64(dd - 111, ss - 111); - case 47: - memcpy_sse2_32(dd - 47, ss - 47); - *((uint64_unaligned_t*)(dd - 15)) = *((uint64_unaligned_t*)(ss - 15)); - *((uint64_unaligned_t*)(dd - 8)) = *((uint64_unaligned_t*)(ss - 8)); - break; - - case 112: - memcpy_sse2_64(dd - 112, ss - 112); - case 48: - memcpy_sse2_32(dd - 48, ss - 48); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 113: - memcpy_sse2_64(dd - 113, ss - 113); - case 49: - memcpy_sse2_32(dd - 49, ss - 49); - memcpy_sse2_16(dd - 17, ss - 17); - dd[-1] = ss[-1]; - break; - - case 114: - memcpy_sse2_64(dd - 114, ss - 114); - case 50: - memcpy_sse2_32(dd - 50, ss - 50); - memcpy_sse2_16(dd - 18, ss - 18); - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 115: - memcpy_sse2_64(dd - 115, ss - 115); - case 51: - memcpy_sse2_32(dd - 51, ss - 51); - memcpy_sse2_16(dd - 19, ss - 19); - *((uint16_unaligned_t*)(dd - 3)) = *((uint16_unaligned_t*)(ss - 3)); - dd[-1] = ss[-1]; - break; - - case 116: - memcpy_sse2_64(dd - 116, ss - 116); - case 52: - memcpy_sse2_32(dd - 52, ss - 52); - memcpy_sse2_16(dd - 20, ss - 20); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 117: - memcpy_sse2_64(dd - 117, ss - 117); - case 53: - memcpy_sse2_32(dd - 53, ss - 53); - memcpy_sse2_16(dd - 21, ss - 21); - *((uint32_unaligned_t*)(dd - 5)) = *((uint32_unaligned_t*)(ss - 5)); - dd[-1] = ss[-1]; - break; - - case 118: - memcpy_sse2_64(dd - 118, ss - 118); - case 54: - memcpy_sse2_32(dd - 54, ss - 54); - memcpy_sse2_16(dd - 22, ss - 22); - *((uint32_unaligned_t*)(dd - 6)) = *((uint32_unaligned_t*)(ss - 6)); - *((uint16_unaligned_t*)(dd - 2)) = *((uint16_unaligned_t*)(ss - 2)); - break; - - case 119: - memcpy_sse2_64(dd - 119, ss - 119); - case 55: - memcpy_sse2_32(dd - 55, ss - 55); - memcpy_sse2_16(dd - 23, ss - 23); - *((uint32_unaligned_t*)(dd - 7)) = *((uint32_unaligned_t*)(ss - 7)); - *((uint32_unaligned_t*)(dd - 4)) = *((uint32_unaligned_t*)(ss - 4)); - break; - - case 120: - memcpy_sse2_64(dd - 120, ss - 120); - case 56: - memcpy_sse2_32(dd - 56, ss - 56); - memcpy_sse2_16(dd - 24, ss - 24); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 121: - memcpy_sse2_64(dd - 121, ss - 121); - case 57: - memcpy_sse2_32(dd - 57, ss - 57); - memcpy_sse2_16(dd - 25, ss - 25); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 122: - memcpy_sse2_64(dd - 122, ss - 122); - case 58: - memcpy_sse2_32(dd - 58, ss - 58); - memcpy_sse2_16(dd - 26, ss - 26); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 123: - memcpy_sse2_64(dd - 123, ss - 123); - case 59: - memcpy_sse2_32(dd - 59, ss - 59); - memcpy_sse2_16(dd - 27, ss - 27); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 124: - memcpy_sse2_64(dd - 124, ss - 124); - case 60: - memcpy_sse2_32(dd - 60, ss - 60); - memcpy_sse2_16(dd - 28, ss - 28); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 125: - memcpy_sse2_64(dd - 125, ss - 125); - case 61: - memcpy_sse2_32(dd - 61, ss - 61); - memcpy_sse2_16(dd - 29, ss - 29); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 126: - memcpy_sse2_64(dd - 126, ss - 126); - case 62: - memcpy_sse2_32(dd - 62, ss - 62); - memcpy_sse2_16(dd - 30, ss - 30); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 127: - memcpy_sse2_64(dd - 127, ss - 127); - case 63: - memcpy_sse2_32(dd - 63, ss - 63); - memcpy_sse2_16(dd - 31, ss - 31); - memcpy_sse2_16(dd - 16, ss - 16); - break; - - case 128: - memcpy_sse2_128(dd - 128, ss - 128); - break; - } - - return dst; -} - - -//--------------------------------------------------------------------- -// main routine -//--------------------------------------------------------------------- -static void* memcpy_fast(void *destination, const void *source, size_t size) -{ - unsigned char *dst = (unsigned char*)destination; - const unsigned char *src = (const unsigned char*)source; - static size_t cachesize = 0x200000; // L2-cache size - size_t padding; - - // small memory copy - if (size <= 128) { - return memcpy_tiny(dst, src, size); - } - - // align destination to 16 bytes boundary - padding = (16 - (((size_t)dst) & 15)) & 15; - - if (padding > 0) { - __m128i head = _mm_loadu_si128((const __m128i*)src); - _mm_storeu_si128((__m128i*)dst, head); - dst += padding; - src += padding; - size -= padding; - } - - // medium size copy - if (size <= cachesize) { - __m128i c0, c1, c2, c3, c4, c5, c6, c7; - - for (; size >= 128; size -= 128) { - c0 = _mm_loadu_si128(((const __m128i*)src) + 0); - c1 = _mm_loadu_si128(((const __m128i*)src) + 1); - c2 = _mm_loadu_si128(((const __m128i*)src) + 2); - c3 = _mm_loadu_si128(((const __m128i*)src) + 3); - c4 = _mm_loadu_si128(((const __m128i*)src) + 4); - c5 = _mm_loadu_si128(((const __m128i*)src) + 5); - c6 = _mm_loadu_si128(((const __m128i*)src) + 6); - c7 = _mm_loadu_si128(((const __m128i*)src) + 7); - _mm_prefetch((const char*)(src + 256), _MM_HINT_NTA); - src += 128; - _mm_store_si128((((__m128i*)dst) + 0), c0); - _mm_store_si128((((__m128i*)dst) + 1), c1); - _mm_store_si128((((__m128i*)dst) + 2), c2); - _mm_store_si128((((__m128i*)dst) + 3), c3); - _mm_store_si128((((__m128i*)dst) + 4), c4); - _mm_store_si128((((__m128i*)dst) + 5), c5); - _mm_store_si128((((__m128i*)dst) + 6), c6); - _mm_store_si128((((__m128i*)dst) + 7), c7); - dst += 128; - } - } - else { // big memory copy - __m128i c0, c1, c2, c3, c4, c5, c6, c7; - - _mm_prefetch((const char*)(src), _MM_HINT_NTA); - - if ((((size_t)src) & 15) == 0) { // source aligned - for (; size >= 128; size -= 128) { - c0 = _mm_load_si128(((const __m128i*)src) + 0); - c1 = _mm_load_si128(((const __m128i*)src) + 1); - c2 = _mm_load_si128(((const __m128i*)src) + 2); - c3 = _mm_load_si128(((const __m128i*)src) + 3); - c4 = _mm_load_si128(((const __m128i*)src) + 4); - c5 = _mm_load_si128(((const __m128i*)src) + 5); - c6 = _mm_load_si128(((const __m128i*)src) + 6); - c7 = _mm_load_si128(((const __m128i*)src) + 7); - _mm_prefetch((const char*)(src + 256), _MM_HINT_NTA); - src += 128; - _mm_stream_si128((((__m128i*)dst) + 0), c0); - _mm_stream_si128((((__m128i*)dst) + 1), c1); - _mm_stream_si128((((__m128i*)dst) + 2), c2); - _mm_stream_si128((((__m128i*)dst) + 3), c3); - _mm_stream_si128((((__m128i*)dst) + 4), c4); - _mm_stream_si128((((__m128i*)dst) + 5), c5); - _mm_stream_si128((((__m128i*)dst) + 6), c6); - _mm_stream_si128((((__m128i*)dst) + 7), c7); - dst += 128; - } - } - else { // source unaligned - for (; size >= 128; size -= 128) { - c0 = _mm_loadu_si128(((const __m128i*)src) + 0); - c1 = _mm_loadu_si128(((const __m128i*)src) + 1); - c2 = _mm_loadu_si128(((const __m128i*)src) + 2); - c3 = _mm_loadu_si128(((const __m128i*)src) + 3); - c4 = _mm_loadu_si128(((const __m128i*)src) + 4); - c5 = _mm_loadu_si128(((const __m128i*)src) + 5); - c6 = _mm_loadu_si128(((const __m128i*)src) + 6); - c7 = _mm_loadu_si128(((const __m128i*)src) + 7); - _mm_prefetch((const char*)(src + 256), _MM_HINT_NTA); - src += 128; - _mm_stream_si128((((__m128i*)dst) + 0), c0); - _mm_stream_si128((((__m128i*)dst) + 1), c1); - _mm_stream_si128((((__m128i*)dst) + 2), c2); - _mm_stream_si128((((__m128i*)dst) + 3), c3); - _mm_stream_si128((((__m128i*)dst) + 4), c4); - _mm_stream_si128((((__m128i*)dst) + 5), c5); - _mm_stream_si128((((__m128i*)dst) + 6), c6); - _mm_stream_si128((((__m128i*)dst) + 7), c7); - dst += 128; - } - } - _mm_sfence(); - } - - memcpy_tiny(dst, src, size); - - return destination; -} - - -#endif diff --git a/contrib/FastMemcpy/FastMemcpy_Avx.c b/contrib/FastMemcpy/FastMemcpy_Avx.c deleted file mode 100644 index 6538c6b2126..00000000000 --- a/contrib/FastMemcpy/FastMemcpy_Avx.c +++ /dev/null @@ -1,171 +0,0 @@ -//===================================================================== -// -// FastMemcpy.c - skywind3000@163.com, 2015 -// -// feature: -// 50% speed up in avg. vs standard memcpy (tested in vc2012/gcc4.9) -// -//===================================================================== -#include -#include -#include -#include -#include - -#if (defined(_WIN32) || defined(WIN32)) -#include -#include -#ifdef _MSC_VER -#pragma comment(lib, "winmm.lib") -#endif -#elif defined(__unix) -#include -#include -#else -#error it can only be compiled under windows or unix -#endif - -#include "FastMemcpy_Avx.h" - - -unsigned int gettime() -{ - #if (defined(_WIN32) || defined(WIN32)) - return timeGetTime(); - #else - static struct timezone tz={ 0,0 }; - struct timeval time; - gettimeofday(&time,&tz); - return (time.tv_sec * 1000 + time.tv_usec / 1000); - #endif -} - -void sleepms(unsigned int millisec) -{ -#if defined(_WIN32) || defined(WIN32) - Sleep(millisec); -#else - usleep(millisec * 1000); -#endif -} - - - -void benchmark(int dstalign, int srcalign, size_t size, int times) -{ - char *DATA1 = (char*)malloc(size + 64); - char *DATA2 = (char*)malloc(size + 64); - size_t LINEAR1 = ((size_t)DATA1); - size_t LINEAR2 = ((size_t)DATA2); - char *ALIGN1 = (char*)(((64 - (LINEAR1 & 63)) & 63) + LINEAR1); - char *ALIGN2 = (char*)(((64 - (LINEAR2 & 63)) & 63) + LINEAR2); - char *dst = (dstalign)? ALIGN1 : (ALIGN1 + 1); - char *src = (srcalign)? ALIGN2 : (ALIGN2 + 3); - unsigned int t1, t2; - int k; - - sleepms(100); - t1 = gettime(); - for (k = times; k > 0; k--) { - memcpy(dst, src, size); - } - t1 = gettime() - t1; - sleepms(100); - t2 = gettime(); - for (k = times; k > 0; k--) { - memcpy_fast(dst, src, size); - } - t2 = gettime() - t2; - - free(DATA1); - free(DATA2); - - printf("result(dst %s, src %s): memcpy_fast=%dms memcpy=%d ms\n", - dstalign? "aligned" : "unalign", - srcalign? "aligned" : "unalign", (int)t2, (int)t1); -} - - -void bench(int copysize, int times) -{ - printf("benchmark(size=%d bytes, times=%d):\n", copysize, times); - benchmark(1, 1, copysize, times); - benchmark(1, 0, copysize, times); - benchmark(0, 1, copysize, times); - benchmark(0, 0, copysize, times); - printf("\n"); -} - - -void random_bench(int maxsize, int times) -{ - static char A[11 * 1024 * 1024 + 2]; - static char B[11 * 1024 * 1024 + 2]; - static int random_offsets[0x10000]; - static int random_sizes[0x8000]; - unsigned int i, p1, p2; - unsigned int t1, t2; - for (i = 0; i < 0x10000; i++) { // generate random offsets - random_offsets[i] = rand() % (10 * 1024 * 1024 + 1); - } - for (i = 0; i < 0x8000; i++) { // generate random sizes - random_sizes[i] = 1 + rand() % maxsize; - } - sleepms(100); - t1 = gettime(); - for (p1 = 0, p2 = 0, i = 0; i < times; i++) { - int offset1 = random_offsets[(p1++) & 0xffff]; - int offset2 = random_offsets[(p1++) & 0xffff]; - int size = random_sizes[(p2++) & 0x7fff]; - memcpy(A + offset1, B + offset2, size); - } - t1 = gettime() - t1; - sleepms(100); - t2 = gettime(); - for (p1 = 0, p2 = 0, i = 0; i < times; i++) { - int offset1 = random_offsets[(p1++) & 0xffff]; - int offset2 = random_offsets[(p1++) & 0xffff]; - int size = random_sizes[(p2++) & 0x7fff]; - memcpy_fast(A + offset1, B + offset2, size); - } - t2 = gettime() - t2; - printf("benchmark random access:\n"); - printf("memcpy_fast=%dms memcpy=%dms\n\n", (int)t2, (int)t1); -} - - -#ifdef _MSC_VER -#pragma comment(lib, "winmm.lib") -#endif - -int main(void) -{ -#if 1 - bench(32, 0x1000000); - bench(64, 0x1000000); - bench(512, 0x800000); - bench(1024, 0x400000); -#endif - bench(4096, 0x80000); - bench(8192, 0x40000); -#if 1 - bench(1024 * 1024 * 1, 0x800); - bench(1024 * 1024 * 4, 0x200); -#endif - bench(1024 * 1024 * 8, 0x100); - - random_bench(2048, 8000000); - - return 0; -} - - - - -/* - -*/ - - - - diff --git a/contrib/FastMemcpy/FastMemcpy_Avx.h b/contrib/FastMemcpy/FastMemcpy_Avx.h deleted file mode 100644 index 8ba064b0350..00000000000 --- a/contrib/FastMemcpy/FastMemcpy_Avx.h +++ /dev/null @@ -1,492 +0,0 @@ -//===================================================================== -// -// FastMemcpy.c - skywind3000@163.com, 2015 -// -// feature: -// 50% speed up in avg. vs standard memcpy (tested in vc2012/gcc5.1) -// -//===================================================================== -#ifndef __FAST_MEMCPY_H__ -#define __FAST_MEMCPY_H__ - -#include -#include -#include - - -//--------------------------------------------------------------------- -// force inline for compilers -//--------------------------------------------------------------------- -#ifndef INLINE -#ifdef __GNUC__ -#if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) - #define INLINE __inline__ __attribute__((always_inline)) -#else - #define INLINE __inline__ -#endif -#elif defined(_MSC_VER) - #define INLINE __forceinline -#elif (defined(__BORLANDC__) || defined(__WATCOMC__)) - #define INLINE __inline -#else - #define INLINE -#endif -#endif - - - -//--------------------------------------------------------------------- -// fast copy for different sizes -//--------------------------------------------------------------------- -static INLINE void memcpy_avx_16(void *dst, const void *src) { -#if 1 - __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); - _mm_storeu_si128(((__m128i*)dst) + 0, m0); -#else - *((uint64_t*)((char*)dst + 0)) = *((uint64_t*)((const char*)src + 0)); - *((uint64_t*)((char*)dst + 8)) = *((uint64_t*)((const char*)src + 8)); -#endif -} - -static INLINE void memcpy_avx_32(void *dst, const void *src) { - __m256i m0 = _mm256_loadu_si256(((const __m256i*)src) + 0); - _mm256_storeu_si256(((__m256i*)dst) + 0, m0); -} - -static INLINE void memcpy_avx_64(void *dst, const void *src) { - __m256i m0 = _mm256_loadu_si256(((const __m256i*)src) + 0); - __m256i m1 = _mm256_loadu_si256(((const __m256i*)src) + 1); - _mm256_storeu_si256(((__m256i*)dst) + 0, m0); - _mm256_storeu_si256(((__m256i*)dst) + 1, m1); -} - -static INLINE void memcpy_avx_128(void *dst, const void *src) { - __m256i m0 = _mm256_loadu_si256(((const __m256i*)src) + 0); - __m256i m1 = _mm256_loadu_si256(((const __m256i*)src) + 1); - __m256i m2 = _mm256_loadu_si256(((const __m256i*)src) + 2); - __m256i m3 = _mm256_loadu_si256(((const __m256i*)src) + 3); - _mm256_storeu_si256(((__m256i*)dst) + 0, m0); - _mm256_storeu_si256(((__m256i*)dst) + 1, m1); - _mm256_storeu_si256(((__m256i*)dst) + 2, m2); - _mm256_storeu_si256(((__m256i*)dst) + 3, m3); -} - -static INLINE void memcpy_avx_256(void *dst, const void *src) { - __m256i m0 = _mm256_loadu_si256(((const __m256i*)src) + 0); - __m256i m1 = _mm256_loadu_si256(((const __m256i*)src) + 1); - __m256i m2 = _mm256_loadu_si256(((const __m256i*)src) + 2); - __m256i m3 = _mm256_loadu_si256(((const __m256i*)src) + 3); - __m256i m4 = _mm256_loadu_si256(((const __m256i*)src) + 4); - __m256i m5 = _mm256_loadu_si256(((const __m256i*)src) + 5); - __m256i m6 = _mm256_loadu_si256(((const __m256i*)src) + 6); - __m256i m7 = _mm256_loadu_si256(((const __m256i*)src) + 7); - _mm256_storeu_si256(((__m256i*)dst) + 0, m0); - _mm256_storeu_si256(((__m256i*)dst) + 1, m1); - _mm256_storeu_si256(((__m256i*)dst) + 2, m2); - _mm256_storeu_si256(((__m256i*)dst) + 3, m3); - _mm256_storeu_si256(((__m256i*)dst) + 4, m4); - _mm256_storeu_si256(((__m256i*)dst) + 5, m5); - _mm256_storeu_si256(((__m256i*)dst) + 6, m6); - _mm256_storeu_si256(((__m256i*)dst) + 7, m7); -} - - -//--------------------------------------------------------------------- -// tiny memory copy with jump table optimized -//--------------------------------------------------------------------- -static INLINE void *memcpy_tiny(void *dst, const void *src, size_t size) { - unsigned char *dd = ((unsigned char*)dst) + size; - const unsigned char *ss = ((const unsigned char*)src) + size; - - switch (size) { - case 128: memcpy_avx_128(dd - 128, ss - 128); - case 0: break; - case 129: memcpy_avx_128(dd - 129, ss - 129); - case 1: dd[-1] = ss[-1]; break; - case 130: memcpy_avx_128(dd - 130, ss - 130); - case 2: *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; - case 131: memcpy_avx_128(dd - 131, ss - 131); - case 3: *((uint16_t*)(dd - 3)) = *((uint16_t*)(ss - 3)); dd[-1] = ss[-1]; break; - case 132: memcpy_avx_128(dd - 132, ss - 132); - case 4: *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 133: memcpy_avx_128(dd - 133, ss - 133); - case 5: *((uint32_t*)(dd - 5)) = *((uint32_t*)(ss - 5)); dd[-1] = ss[-1]; break; - case 134: memcpy_avx_128(dd - 134, ss - 134); - case 6: *((uint32_t*)(dd - 6)) = *((uint32_t*)(ss - 6)); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; - case 135: memcpy_avx_128(dd - 135, ss - 135); - case 7: *((uint32_t*)(dd - 7)) = *((uint32_t*)(ss - 7)); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 136: memcpy_avx_128(dd - 136, ss - 136); - case 8: *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 137: memcpy_avx_128(dd - 137, ss - 137); - case 9: *((uint64_t*)(dd - 9)) = *((uint64_t*)(ss - 9)); dd[-1] = ss[-1]; break; - case 138: memcpy_avx_128(dd - 138, ss - 138); - case 10: *((uint64_t*)(dd - 10)) = *((uint64_t*)(ss - 10)); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; - case 139: memcpy_avx_128(dd - 139, ss - 139); - case 11: *((uint64_t*)(dd - 11)) = *((uint64_t*)(ss - 11)); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 140: memcpy_avx_128(dd - 140, ss - 140); - case 12: *((uint64_t*)(dd - 12)) = *((uint64_t*)(ss - 12)); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 141: memcpy_avx_128(dd - 141, ss - 141); - case 13: *((uint64_t*)(dd - 13)) = *((uint64_t*)(ss - 13)); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 142: memcpy_avx_128(dd - 142, ss - 142); - case 14: *((uint64_t*)(dd - 14)) = *((uint64_t*)(ss - 14)); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 143: memcpy_avx_128(dd - 143, ss - 143); - case 15: *((uint64_t*)(dd - 15)) = *((uint64_t*)(ss - 15)); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 144: memcpy_avx_128(dd - 144, ss - 144); - case 16: memcpy_avx_16(dd - 16, ss - 16); break; - case 145: memcpy_avx_128(dd - 145, ss - 145); - case 17: memcpy_avx_16(dd - 17, ss - 17); dd[-1] = ss[-1]; break; - case 146: memcpy_avx_128(dd - 146, ss - 146); - case 18: memcpy_avx_16(dd - 18, ss - 18); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; - case 147: memcpy_avx_128(dd - 147, ss - 147); - case 19: memcpy_avx_16(dd - 19, ss - 19); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 148: memcpy_avx_128(dd - 148, ss - 148); - case 20: memcpy_avx_16(dd - 20, ss - 20); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 149: memcpy_avx_128(dd - 149, ss - 149); - case 21: memcpy_avx_16(dd - 21, ss - 21); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 150: memcpy_avx_128(dd - 150, ss - 150); - case 22: memcpy_avx_16(dd - 22, ss - 22); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 151: memcpy_avx_128(dd - 151, ss - 151); - case 23: memcpy_avx_16(dd - 23, ss - 23); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 152: memcpy_avx_128(dd - 152, ss - 152); - case 24: memcpy_avx_16(dd - 24, ss - 24); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 153: memcpy_avx_128(dd - 153, ss - 153); - case 25: memcpy_avx_16(dd - 25, ss - 25); memcpy_avx_16(dd - 16, ss - 16); break; - case 154: memcpy_avx_128(dd - 154, ss - 154); - case 26: memcpy_avx_16(dd - 26, ss - 26); memcpy_avx_16(dd - 16, ss - 16); break; - case 155: memcpy_avx_128(dd - 155, ss - 155); - case 27: memcpy_avx_16(dd - 27, ss - 27); memcpy_avx_16(dd - 16, ss - 16); break; - case 156: memcpy_avx_128(dd - 156, ss - 156); - case 28: memcpy_avx_16(dd - 28, ss - 28); memcpy_avx_16(dd - 16, ss - 16); break; - case 157: memcpy_avx_128(dd - 157, ss - 157); - case 29: memcpy_avx_16(dd - 29, ss - 29); memcpy_avx_16(dd - 16, ss - 16); break; - case 158: memcpy_avx_128(dd - 158, ss - 158); - case 30: memcpy_avx_16(dd - 30, ss - 30); memcpy_avx_16(dd - 16, ss - 16); break; - case 159: memcpy_avx_128(dd - 159, ss - 159); - case 31: memcpy_avx_16(dd - 31, ss - 31); memcpy_avx_16(dd - 16, ss - 16); break; - case 160: memcpy_avx_128(dd - 160, ss - 160); - case 32: memcpy_avx_32(dd - 32, ss - 32); break; - case 161: memcpy_avx_128(dd - 161, ss - 161); - case 33: memcpy_avx_32(dd - 33, ss - 33); dd[-1] = ss[-1]; break; - case 162: memcpy_avx_128(dd - 162, ss - 162); - case 34: memcpy_avx_32(dd - 34, ss - 34); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; - case 163: memcpy_avx_128(dd - 163, ss - 163); - case 35: memcpy_avx_32(dd - 35, ss - 35); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 164: memcpy_avx_128(dd - 164, ss - 164); - case 36: memcpy_avx_32(dd - 36, ss - 36); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 165: memcpy_avx_128(dd - 165, ss - 165); - case 37: memcpy_avx_32(dd - 37, ss - 37); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 166: memcpy_avx_128(dd - 166, ss - 166); - case 38: memcpy_avx_32(dd - 38, ss - 38); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 167: memcpy_avx_128(dd - 167, ss - 167); - case 39: memcpy_avx_32(dd - 39, ss - 39); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 168: memcpy_avx_128(dd - 168, ss - 168); - case 40: memcpy_avx_32(dd - 40, ss - 40); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 169: memcpy_avx_128(dd - 169, ss - 169); - case 41: memcpy_avx_32(dd - 41, ss - 41); memcpy_avx_16(dd - 16, ss - 16); break; - case 170: memcpy_avx_128(dd - 170, ss - 170); - case 42: memcpy_avx_32(dd - 42, ss - 42); memcpy_avx_16(dd - 16, ss - 16); break; - case 171: memcpy_avx_128(dd - 171, ss - 171); - case 43: memcpy_avx_32(dd - 43, ss - 43); memcpy_avx_16(dd - 16, ss - 16); break; - case 172: memcpy_avx_128(dd - 172, ss - 172); - case 44: memcpy_avx_32(dd - 44, ss - 44); memcpy_avx_16(dd - 16, ss - 16); break; - case 173: memcpy_avx_128(dd - 173, ss - 173); - case 45: memcpy_avx_32(dd - 45, ss - 45); memcpy_avx_16(dd - 16, ss - 16); break; - case 174: memcpy_avx_128(dd - 174, ss - 174); - case 46: memcpy_avx_32(dd - 46, ss - 46); memcpy_avx_16(dd - 16, ss - 16); break; - case 175: memcpy_avx_128(dd - 175, ss - 175); - case 47: memcpy_avx_32(dd - 47, ss - 47); memcpy_avx_16(dd - 16, ss - 16); break; - case 176: memcpy_avx_128(dd - 176, ss - 176); - case 48: memcpy_avx_32(dd - 48, ss - 48); memcpy_avx_16(dd - 16, ss - 16); break; - case 177: memcpy_avx_128(dd - 177, ss - 177); - case 49: memcpy_avx_32(dd - 49, ss - 49); memcpy_avx_32(dd - 32, ss - 32); break; - case 178: memcpy_avx_128(dd - 178, ss - 178); - case 50: memcpy_avx_32(dd - 50, ss - 50); memcpy_avx_32(dd - 32, ss - 32); break; - case 179: memcpy_avx_128(dd - 179, ss - 179); - case 51: memcpy_avx_32(dd - 51, ss - 51); memcpy_avx_32(dd - 32, ss - 32); break; - case 180: memcpy_avx_128(dd - 180, ss - 180); - case 52: memcpy_avx_32(dd - 52, ss - 52); memcpy_avx_32(dd - 32, ss - 32); break; - case 181: memcpy_avx_128(dd - 181, ss - 181); - case 53: memcpy_avx_32(dd - 53, ss - 53); memcpy_avx_32(dd - 32, ss - 32); break; - case 182: memcpy_avx_128(dd - 182, ss - 182); - case 54: memcpy_avx_32(dd - 54, ss - 54); memcpy_avx_32(dd - 32, ss - 32); break; - case 183: memcpy_avx_128(dd - 183, ss - 183); - case 55: memcpy_avx_32(dd - 55, ss - 55); memcpy_avx_32(dd - 32, ss - 32); break; - case 184: memcpy_avx_128(dd - 184, ss - 184); - case 56: memcpy_avx_32(dd - 56, ss - 56); memcpy_avx_32(dd - 32, ss - 32); break; - case 185: memcpy_avx_128(dd - 185, ss - 185); - case 57: memcpy_avx_32(dd - 57, ss - 57); memcpy_avx_32(dd - 32, ss - 32); break; - case 186: memcpy_avx_128(dd - 186, ss - 186); - case 58: memcpy_avx_32(dd - 58, ss - 58); memcpy_avx_32(dd - 32, ss - 32); break; - case 187: memcpy_avx_128(dd - 187, ss - 187); - case 59: memcpy_avx_32(dd - 59, ss - 59); memcpy_avx_32(dd - 32, ss - 32); break; - case 188: memcpy_avx_128(dd - 188, ss - 188); - case 60: memcpy_avx_32(dd - 60, ss - 60); memcpy_avx_32(dd - 32, ss - 32); break; - case 189: memcpy_avx_128(dd - 189, ss - 189); - case 61: memcpy_avx_32(dd - 61, ss - 61); memcpy_avx_32(dd - 32, ss - 32); break; - case 190: memcpy_avx_128(dd - 190, ss - 190); - case 62: memcpy_avx_32(dd - 62, ss - 62); memcpy_avx_32(dd - 32, ss - 32); break; - case 191: memcpy_avx_128(dd - 191, ss - 191); - case 63: memcpy_avx_32(dd - 63, ss - 63); memcpy_avx_32(dd - 32, ss - 32); break; - case 192: memcpy_avx_128(dd - 192, ss - 192); - case 64: memcpy_avx_64(dd - 64, ss - 64); break; - case 193: memcpy_avx_128(dd - 193, ss - 193); - case 65: memcpy_avx_64(dd - 65, ss - 65); dd[-1] = ss[-1]; break; - case 194: memcpy_avx_128(dd - 194, ss - 194); - case 66: memcpy_avx_64(dd - 66, ss - 66); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; - case 195: memcpy_avx_128(dd - 195, ss - 195); - case 67: memcpy_avx_64(dd - 67, ss - 67); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 196: memcpy_avx_128(dd - 196, ss - 196); - case 68: memcpy_avx_64(dd - 68, ss - 68); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; - case 197: memcpy_avx_128(dd - 197, ss - 197); - case 69: memcpy_avx_64(dd - 69, ss - 69); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 198: memcpy_avx_128(dd - 198, ss - 198); - case 70: memcpy_avx_64(dd - 70, ss - 70); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 199: memcpy_avx_128(dd - 199, ss - 199); - case 71: memcpy_avx_64(dd - 71, ss - 71); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 200: memcpy_avx_128(dd - 200, ss - 200); - case 72: memcpy_avx_64(dd - 72, ss - 72); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; - case 201: memcpy_avx_128(dd - 201, ss - 201); - case 73: memcpy_avx_64(dd - 73, ss - 73); memcpy_avx_16(dd - 16, ss - 16); break; - case 202: memcpy_avx_128(dd - 202, ss - 202); - case 74: memcpy_avx_64(dd - 74, ss - 74); memcpy_avx_16(dd - 16, ss - 16); break; - case 203: memcpy_avx_128(dd - 203, ss - 203); - case 75: memcpy_avx_64(dd - 75, ss - 75); memcpy_avx_16(dd - 16, ss - 16); break; - case 204: memcpy_avx_128(dd - 204, ss - 204); - case 76: memcpy_avx_64(dd - 76, ss - 76); memcpy_avx_16(dd - 16, ss - 16); break; - case 205: memcpy_avx_128(dd - 205, ss - 205); - case 77: memcpy_avx_64(dd - 77, ss - 77); memcpy_avx_16(dd - 16, ss - 16); break; - case 206: memcpy_avx_128(dd - 206, ss - 206); - case 78: memcpy_avx_64(dd - 78, ss - 78); memcpy_avx_16(dd - 16, ss - 16); break; - case 207: memcpy_avx_128(dd - 207, ss - 207); - case 79: memcpy_avx_64(dd - 79, ss - 79); memcpy_avx_16(dd - 16, ss - 16); break; - case 208: memcpy_avx_128(dd - 208, ss - 208); - case 80: memcpy_avx_64(dd - 80, ss - 80); memcpy_avx_16(dd - 16, ss - 16); break; - case 209: memcpy_avx_128(dd - 209, ss - 209); - case 81: memcpy_avx_64(dd - 81, ss - 81); memcpy_avx_32(dd - 32, ss - 32); break; - case 210: memcpy_avx_128(dd - 210, ss - 210); - case 82: memcpy_avx_64(dd - 82, ss - 82); memcpy_avx_32(dd - 32, ss - 32); break; - case 211: memcpy_avx_128(dd - 211, ss - 211); - case 83: memcpy_avx_64(dd - 83, ss - 83); memcpy_avx_32(dd - 32, ss - 32); break; - case 212: memcpy_avx_128(dd - 212, ss - 212); - case 84: memcpy_avx_64(dd - 84, ss - 84); memcpy_avx_32(dd - 32, ss - 32); break; - case 213: memcpy_avx_128(dd - 213, ss - 213); - case 85: memcpy_avx_64(dd - 85, ss - 85); memcpy_avx_32(dd - 32, ss - 32); break; - case 214: memcpy_avx_128(dd - 214, ss - 214); - case 86: memcpy_avx_64(dd - 86, ss - 86); memcpy_avx_32(dd - 32, ss - 32); break; - case 215: memcpy_avx_128(dd - 215, ss - 215); - case 87: memcpy_avx_64(dd - 87, ss - 87); memcpy_avx_32(dd - 32, ss - 32); break; - case 216: memcpy_avx_128(dd - 216, ss - 216); - case 88: memcpy_avx_64(dd - 88, ss - 88); memcpy_avx_32(dd - 32, ss - 32); break; - case 217: memcpy_avx_128(dd - 217, ss - 217); - case 89: memcpy_avx_64(dd - 89, ss - 89); memcpy_avx_32(dd - 32, ss - 32); break; - case 218: memcpy_avx_128(dd - 218, ss - 218); - case 90: memcpy_avx_64(dd - 90, ss - 90); memcpy_avx_32(dd - 32, ss - 32); break; - case 219: memcpy_avx_128(dd - 219, ss - 219); - case 91: memcpy_avx_64(dd - 91, ss - 91); memcpy_avx_32(dd - 32, ss - 32); break; - case 220: memcpy_avx_128(dd - 220, ss - 220); - case 92: memcpy_avx_64(dd - 92, ss - 92); memcpy_avx_32(dd - 32, ss - 32); break; - case 221: memcpy_avx_128(dd - 221, ss - 221); - case 93: memcpy_avx_64(dd - 93, ss - 93); memcpy_avx_32(dd - 32, ss - 32); break; - case 222: memcpy_avx_128(dd - 222, ss - 222); - case 94: memcpy_avx_64(dd - 94, ss - 94); memcpy_avx_32(dd - 32, ss - 32); break; - case 223: memcpy_avx_128(dd - 223, ss - 223); - case 95: memcpy_avx_64(dd - 95, ss - 95); memcpy_avx_32(dd - 32, ss - 32); break; - case 224: memcpy_avx_128(dd - 224, ss - 224); - case 96: memcpy_avx_64(dd - 96, ss - 96); memcpy_avx_32(dd - 32, ss - 32); break; - case 225: memcpy_avx_128(dd - 225, ss - 225); - case 97: memcpy_avx_64(dd - 97, ss - 97); memcpy_avx_64(dd - 64, ss - 64); break; - case 226: memcpy_avx_128(dd - 226, ss - 226); - case 98: memcpy_avx_64(dd - 98, ss - 98); memcpy_avx_64(dd - 64, ss - 64); break; - case 227: memcpy_avx_128(dd - 227, ss - 227); - case 99: memcpy_avx_64(dd - 99, ss - 99); memcpy_avx_64(dd - 64, ss - 64); break; - case 228: memcpy_avx_128(dd - 228, ss - 228); - case 100: memcpy_avx_64(dd - 100, ss - 100); memcpy_avx_64(dd - 64, ss - 64); break; - case 229: memcpy_avx_128(dd - 229, ss - 229); - case 101: memcpy_avx_64(dd - 101, ss - 101); memcpy_avx_64(dd - 64, ss - 64); break; - case 230: memcpy_avx_128(dd - 230, ss - 230); - case 102: memcpy_avx_64(dd - 102, ss - 102); memcpy_avx_64(dd - 64, ss - 64); break; - case 231: memcpy_avx_128(dd - 231, ss - 231); - case 103: memcpy_avx_64(dd - 103, ss - 103); memcpy_avx_64(dd - 64, ss - 64); break; - case 232: memcpy_avx_128(dd - 232, ss - 232); - case 104: memcpy_avx_64(dd - 104, ss - 104); memcpy_avx_64(dd - 64, ss - 64); break; - case 233: memcpy_avx_128(dd - 233, ss - 233); - case 105: memcpy_avx_64(dd - 105, ss - 105); memcpy_avx_64(dd - 64, ss - 64); break; - case 234: memcpy_avx_128(dd - 234, ss - 234); - case 106: memcpy_avx_64(dd - 106, ss - 106); memcpy_avx_64(dd - 64, ss - 64); break; - case 235: memcpy_avx_128(dd - 235, ss - 235); - case 107: memcpy_avx_64(dd - 107, ss - 107); memcpy_avx_64(dd - 64, ss - 64); break; - case 236: memcpy_avx_128(dd - 236, ss - 236); - case 108: memcpy_avx_64(dd - 108, ss - 108); memcpy_avx_64(dd - 64, ss - 64); break; - case 237: memcpy_avx_128(dd - 237, ss - 237); - case 109: memcpy_avx_64(dd - 109, ss - 109); memcpy_avx_64(dd - 64, ss - 64); break; - case 238: memcpy_avx_128(dd - 238, ss - 238); - case 110: memcpy_avx_64(dd - 110, ss - 110); memcpy_avx_64(dd - 64, ss - 64); break; - case 239: memcpy_avx_128(dd - 239, ss - 239); - case 111: memcpy_avx_64(dd - 111, ss - 111); memcpy_avx_64(dd - 64, ss - 64); break; - case 240: memcpy_avx_128(dd - 240, ss - 240); - case 112: memcpy_avx_64(dd - 112, ss - 112); memcpy_avx_64(dd - 64, ss - 64); break; - case 241: memcpy_avx_128(dd - 241, ss - 241); - case 113: memcpy_avx_64(dd - 113, ss - 113); memcpy_avx_64(dd - 64, ss - 64); break; - case 242: memcpy_avx_128(dd - 242, ss - 242); - case 114: memcpy_avx_64(dd - 114, ss - 114); memcpy_avx_64(dd - 64, ss - 64); break; - case 243: memcpy_avx_128(dd - 243, ss - 243); - case 115: memcpy_avx_64(dd - 115, ss - 115); memcpy_avx_64(dd - 64, ss - 64); break; - case 244: memcpy_avx_128(dd - 244, ss - 244); - case 116: memcpy_avx_64(dd - 116, ss - 116); memcpy_avx_64(dd - 64, ss - 64); break; - case 245: memcpy_avx_128(dd - 245, ss - 245); - case 117: memcpy_avx_64(dd - 117, ss - 117); memcpy_avx_64(dd - 64, ss - 64); break; - case 246: memcpy_avx_128(dd - 246, ss - 246); - case 118: memcpy_avx_64(dd - 118, ss - 118); memcpy_avx_64(dd - 64, ss - 64); break; - case 247: memcpy_avx_128(dd - 247, ss - 247); - case 119: memcpy_avx_64(dd - 119, ss - 119); memcpy_avx_64(dd - 64, ss - 64); break; - case 248: memcpy_avx_128(dd - 248, ss - 248); - case 120: memcpy_avx_64(dd - 120, ss - 120); memcpy_avx_64(dd - 64, ss - 64); break; - case 249: memcpy_avx_128(dd - 249, ss - 249); - case 121: memcpy_avx_64(dd - 121, ss - 121); memcpy_avx_64(dd - 64, ss - 64); break; - case 250: memcpy_avx_128(dd - 250, ss - 250); - case 122: memcpy_avx_64(dd - 122, ss - 122); memcpy_avx_64(dd - 64, ss - 64); break; - case 251: memcpy_avx_128(dd - 251, ss - 251); - case 123: memcpy_avx_64(dd - 123, ss - 123); memcpy_avx_64(dd - 64, ss - 64); break; - case 252: memcpy_avx_128(dd - 252, ss - 252); - case 124: memcpy_avx_64(dd - 124, ss - 124); memcpy_avx_64(dd - 64, ss - 64); break; - case 253: memcpy_avx_128(dd - 253, ss - 253); - case 125: memcpy_avx_64(dd - 125, ss - 125); memcpy_avx_64(dd - 64, ss - 64); break; - case 254: memcpy_avx_128(dd - 254, ss - 254); - case 126: memcpy_avx_64(dd - 126, ss - 126); memcpy_avx_64(dd - 64, ss - 64); break; - case 255: memcpy_avx_128(dd - 255, ss - 255); - case 127: memcpy_avx_64(dd - 127, ss - 127); memcpy_avx_64(dd - 64, ss - 64); break; - case 256: memcpy_avx_256(dd - 256, ss - 256); break; - } - - return dst; -} - - -//--------------------------------------------------------------------- -// main routine -//--------------------------------------------------------------------- -static void* memcpy_fast(void *destination, const void *source, size_t size) -{ - unsigned char *dst = (unsigned char*)destination; - const unsigned char *src = (const unsigned char*)source; - static size_t cachesize = 0x200000; // L3-cache size - size_t padding; - - // small memory copy - if (size <= 256) { - memcpy_tiny(dst, src, size); - _mm256_zeroupper(); - return destination; - } - - // align destination to 16 bytes boundary - padding = (32 - (((size_t)dst) & 31)) & 31; - -#if 0 - if (padding > 0) { - __m256i head = _mm256_loadu_si256((const __m256i*)src); - _mm256_storeu_si256((__m256i*)dst, head); - dst += padding; - src += padding; - size -= padding; - } -#else - __m256i head = _mm256_loadu_si256((const __m256i*)src); - _mm256_storeu_si256((__m256i*)dst, head); - dst += padding; - src += padding; - size -= padding; -#endif - - // medium size copy - if (size <= cachesize) { - __m256i c0, c1, c2, c3, c4, c5, c6, c7; - - for (; size >= 256; size -= 256) { - c0 = _mm256_loadu_si256(((const __m256i*)src) + 0); - c1 = _mm256_loadu_si256(((const __m256i*)src) + 1); - c2 = _mm256_loadu_si256(((const __m256i*)src) + 2); - c3 = _mm256_loadu_si256(((const __m256i*)src) + 3); - c4 = _mm256_loadu_si256(((const __m256i*)src) + 4); - c5 = _mm256_loadu_si256(((const __m256i*)src) + 5); - c6 = _mm256_loadu_si256(((const __m256i*)src) + 6); - c7 = _mm256_loadu_si256(((const __m256i*)src) + 7); - _mm_prefetch((const char*)(src + 512), _MM_HINT_NTA); - src += 256; - _mm256_storeu_si256((((__m256i*)dst) + 0), c0); - _mm256_storeu_si256((((__m256i*)dst) + 1), c1); - _mm256_storeu_si256((((__m256i*)dst) + 2), c2); - _mm256_storeu_si256((((__m256i*)dst) + 3), c3); - _mm256_storeu_si256((((__m256i*)dst) + 4), c4); - _mm256_storeu_si256((((__m256i*)dst) + 5), c5); - _mm256_storeu_si256((((__m256i*)dst) + 6), c6); - _mm256_storeu_si256((((__m256i*)dst) + 7), c7); - dst += 256; - } - } - else { // big memory copy - __m256i c0, c1, c2, c3, c4, c5, c6, c7; - /* __m256i c0, c1, c2, c3, c4, c5, c6, c7; */ - - _mm_prefetch((const char*)(src), _MM_HINT_NTA); - - if ((((size_t)src) & 31) == 0) { // source aligned - for (; size >= 256; size -= 256) { - c0 = _mm256_load_si256(((const __m256i*)src) + 0); - c1 = _mm256_load_si256(((const __m256i*)src) + 1); - c2 = _mm256_load_si256(((const __m256i*)src) + 2); - c3 = _mm256_load_si256(((const __m256i*)src) + 3); - c4 = _mm256_load_si256(((const __m256i*)src) + 4); - c5 = _mm256_load_si256(((const __m256i*)src) + 5); - c6 = _mm256_load_si256(((const __m256i*)src) + 6); - c7 = _mm256_load_si256(((const __m256i*)src) + 7); - _mm_prefetch((const char*)(src + 512), _MM_HINT_NTA); - src += 256; - _mm256_stream_si256((((__m256i*)dst) + 0), c0); - _mm256_stream_si256((((__m256i*)dst) + 1), c1); - _mm256_stream_si256((((__m256i*)dst) + 2), c2); - _mm256_stream_si256((((__m256i*)dst) + 3), c3); - _mm256_stream_si256((((__m256i*)dst) + 4), c4); - _mm256_stream_si256((((__m256i*)dst) + 5), c5); - _mm256_stream_si256((((__m256i*)dst) + 6), c6); - _mm256_stream_si256((((__m256i*)dst) + 7), c7); - dst += 256; - } - } - else { // source unaligned - for (; size >= 256; size -= 256) { - c0 = _mm256_loadu_si256(((const __m256i*)src) + 0); - c1 = _mm256_loadu_si256(((const __m256i*)src) + 1); - c2 = _mm256_loadu_si256(((const __m256i*)src) + 2); - c3 = _mm256_loadu_si256(((const __m256i*)src) + 3); - c4 = _mm256_loadu_si256(((const __m256i*)src) + 4); - c5 = _mm256_loadu_si256(((const __m256i*)src) + 5); - c6 = _mm256_loadu_si256(((const __m256i*)src) + 6); - c7 = _mm256_loadu_si256(((const __m256i*)src) + 7); - _mm_prefetch((const char*)(src + 512), _MM_HINT_NTA); - src += 256; - _mm256_stream_si256((((__m256i*)dst) + 0), c0); - _mm256_stream_si256((((__m256i*)dst) + 1), c1); - _mm256_stream_si256((((__m256i*)dst) + 2), c2); - _mm256_stream_si256((((__m256i*)dst) + 3), c3); - _mm256_stream_si256((((__m256i*)dst) + 4), c4); - _mm256_stream_si256((((__m256i*)dst) + 5), c5); - _mm256_stream_si256((((__m256i*)dst) + 6), c6); - _mm256_stream_si256((((__m256i*)dst) + 7), c7); - dst += 256; - } - } - _mm_sfence(); - } - - memcpy_tiny(dst, src, size); - _mm256_zeroupper(); - - return destination; -} - - -#endif - - - diff --git a/contrib/FastMemcpy/LICENSE b/contrib/FastMemcpy/LICENSE deleted file mode 100644 index c449da6aa8a..00000000000 --- a/contrib/FastMemcpy/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Linwei - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/contrib/FastMemcpy/README.md b/contrib/FastMemcpy/README.md deleted file mode 100644 index e253f6bf5dd..00000000000 --- a/contrib/FastMemcpy/README.md +++ /dev/null @@ -1,20 +0,0 @@ -Internal implementation of `memcpy` function. - -It has the following advantages over `libc`-supplied implementation: -- it is linked statically, so the function is called directly, not through a `PLT` (procedure lookup table of shared library); -- it is linked statically, so the function can have position-dependent code; -- your binaries will not depend on `glibc`'s memcpy, that forces dependency on specific symbol version like `memcpy@@GLIBC_2.14` and consequently on specific version of `glibc` library; -- you can include `memcpy.h` directly and the function has the chance to be inlined, which is beneficial for small but unknown at compile time sizes of memory regions; -- this version of `memcpy` pretend to be faster (in our benchmarks, the difference is within few percents). - -Currently it uses the implementation from **Linwei** (skywind3000@163.com). -Look at https://www.zhihu.com/question/35172305 for discussion. - -Drawbacks: -- only use SSE 2, doesn't use wider (AVX, AVX 512) vector registers when available; -- no CPU dispatching; doesn't take into account actual cache size. - -Also worth to look at: -- simple implementation from Facebook: https://github.com/facebook/folly/blob/master/folly/memcpy.S -- implementation from Agner Fog: http://www.agner.org/optimize/ -- glibc source code. diff --git a/contrib/FastMemcpy/memcpy_wrapper.c b/contrib/FastMemcpy/memcpy_wrapper.c deleted file mode 100644 index 1f57345980a..00000000000 --- a/contrib/FastMemcpy/memcpy_wrapper.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "FastMemcpy.h" - -void * memcpy(void * __restrict destination, const void * __restrict source, size_t size) -{ - return memcpy_fast(destination, source, size); -} diff --git a/contrib/NuRaft b/contrib/NuRaft index ff9049bcc8e..3d3683e7775 160000 --- a/contrib/NuRaft +++ b/contrib/NuRaft @@ -1 +1 @@ -Subproject commit ff9049bcc8ea6a02276ccdc8629d764e9e5de853 +Subproject commit 3d3683e77753cfe015a05fae95ddf418e19f59e1 diff --git a/contrib/boringssl b/contrib/boringssl index 8b2bf912ba0..fd9ce1a0406 160000 --- a/contrib/boringssl +++ b/contrib/boringssl @@ -1 +1 @@ -Subproject commit 8b2bf912ba04823cfe9e7e8f5bb60cb7f6252449 +Subproject commit fd9ce1a0406f571507068b9555d0b545b8a18332 diff --git a/contrib/cassandra b/contrib/cassandra index b446d7eb68e..c097fb5c7e6 160000 --- a/contrib/cassandra +++ b/contrib/cassandra @@ -1 +1 @@ -Subproject commit b446d7eb68e6962f431e2b3771313bfe9a2bbd93 +Subproject commit c097fb5c7e63cc430016d9a8b240d8e63fbefa52 diff --git a/contrib/googletest b/contrib/googletest index 356f2d264a4..e7e591764ba 160000 --- a/contrib/googletest +++ b/contrib/googletest @@ -1 +1 @@ -Subproject commit 356f2d264a485db2fcc50ec1c672e0d37b6cb39b +Subproject commit e7e591764baba0a0c3c9ad0014430e7a27331d16 diff --git a/contrib/krb5-cmake/CMakeLists.txt b/contrib/krb5-cmake/CMakeLists.txt index f88402df1fa..fce7fbc582a 100644 --- a/contrib/krb5-cmake/CMakeLists.txt +++ b/contrib/krb5-cmake/CMakeLists.txt @@ -474,13 +474,6 @@ add_custom_command( WORKING_DIRECTORY "${KRB5_SOURCE_DIR}/util/et" ) -add_custom_target( - CREATE_COMPILE_ET ALL - DEPENDS ${KRB5_SOURCE_DIR}/util/et/compile_et - COMMENT "creating compile_et" - VERBATIM -) - file(GLOB_RECURSE ET_FILES "${KRB5_SOURCE_DIR}/*.et" ) @@ -531,7 +524,7 @@ add_custom_command( add_custom_target( - ERROR_MAP_H ALL + ERROR_MAP_H DEPENDS ${KRB5_SOURCE_DIR}/lib/gssapi/krb5/error_map.h COMMENT "generating error_map.h" VERBATIM @@ -544,14 +537,14 @@ add_custom_command( ) add_custom_target( - ERRMAP_H ALL + ERRMAP_H DEPENDS ${KRB5_SOURCE_DIR}/lib/gssapi/generic/errmap.h COMMENT "generating errmap.h" VERBATIM ) add_custom_target( - KRB_5_H ALL + KRB_5_H DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/include/krb5/krb5.h COMMENT "generating krb5.h" VERBATIM @@ -564,15 +557,19 @@ add_dependencies( ERRMAP_H ERROR_MAP_H KRB_5_H - ) +) preprocess_et(processed_et_files ${ET_FILES}) -add_custom_command( - OUTPUT ${KRB5_SOURCE_DIR}/lib/gssapi/generic/errmap.h - COMMAND perl -w -I../../../util ../../../util/gen.pl bimap errmap.h NAME=mecherrmap LEFT=OM_uint32 RIGHT=struct\ mecherror LEFTPRINT=print_OM_uint32 RIGHTPRINT=mecherror_print LEFTCMP=cmp_OM_uint32 RIGHTCMP=mecherror_cmp - WORKING_DIRECTORY "${KRB5_SOURCE_DIR}/lib/gssapi/generic" -) +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/include_private/kcmrpc.h ${CMAKE_CURRENT_BINARY_DIR}/include_private/kcmrpc.c + COMMAND mig -header kcmrpc.h -user kcmrpc.c -sheader /dev/null -server /dev/null -I${KRB5_SOURCE_DIR}/lib/krb5/ccache ${KRB5_SOURCE_DIR}/lib/krb5/ccache/kcmrpc.defs + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include_private" + ) + + list(APPEND ALL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/include_private/kcmrpc.c) +endif() target_sources(${KRB5_LIBRARY} PRIVATE ${ALL_SRCS} @@ -604,6 +601,25 @@ file(COPY ${KRB5_SOURCE_DIR}/util/et/com_err.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/ ) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/osconf.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include_private/ +) + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/profile.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include_private/ +) + +string(TOLOWER "${CMAKE_SYSTEM_NAME}" _system_name) + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/autoconf_${_system_name}.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include_private/ +) + +file(RENAME + ${CMAKE_CURRENT_BINARY_DIR}/include_private/autoconf_${_system_name}.h + ${CMAKE_CURRENT_BINARY_DIR}/include_private/autoconf.h +) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/krb5 ) @@ -633,7 +649,7 @@ target_include_directories(${KRB5_LIBRARY} PUBLIC ) target_include_directories(${KRB5_LIBRARY} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} #for autoconf.h + ${CMAKE_CURRENT_BINARY_DIR}/include_private # For autoconf.h and other generated headers. ${KRB5_SOURCE_DIR} ${KRB5_SOURCE_DIR}/include ${KRB5_SOURCE_DIR}/lib/gssapi/mechglue diff --git a/contrib/krb5-cmake/autoconf_darwin.h b/contrib/krb5-cmake/autoconf_darwin.h new file mode 100644 index 00000000000..965e2f02997 --- /dev/null +++ b/contrib/krb5-cmake/autoconf_darwin.h @@ -0,0 +1,764 @@ +/* include/autoconf.h. Generated from autoconf.h.in by configure. */ +/* include/autoconf.h.in. Generated from configure.in by autoheader. */ + + +#ifndef KRB5_AUTOCONF_H +#define KRB5_AUTOCONF_H + + +/* Define if AES-NI support is enabled */ +/* #undef AESNI */ + +/* Define if socket can't be bound to 0.0.0.0 */ +/* #undef BROKEN_STREAMS_SOCKETS */ + +/* Define if va_list objects can be simply copied by assignment. */ +/* #undef CAN_COPY_VA_LIST */ + +/* Define to reduce code size even if it means more cpu usage */ +/* #undef CONFIG_SMALL */ + +/* Define if __attribute__((constructor)) works */ +#define CONSTRUCTOR_ATTR_WORKS 1 + +/* Define to default ccache name */ +#define DEFCCNAME "FILE:/tmp/krb5cc_%{uid}" + +/* Define to default client keytab name */ +#define DEFCKTNAME "FILE:/etc/krb5/user/%{euid}/client.keytab" + +/* Define to default keytab name */ +#define DEFKTNAME "FILE:/etc/krb5.keytab" + +/* Define if library initialization should be delayed until first use */ +#define DELAY_INITIALIZER 1 + +/* Define if __attribute__((destructor)) works */ +#define DESTRUCTOR_ATTR_WORKS 1 + +/* Define to disable PKINIT plugin support */ +#define DISABLE_PKINIT 1 + +/* Define if LDAP KDB support within the Kerberos library (mainly ASN.1 code) + should be enabled. */ +/* #undef ENABLE_LDAP */ + +/* Define if translation functions should be used. */ +/* #undef ENABLE_NLS */ + +/* Define if thread support enabled */ +#define ENABLE_THREADS 1 + +/* Define as return type of endrpcent */ +#define ENDRPCENT_TYPE void + +/* Define if Fortuna PRNG is selected */ +#define FORTUNA 1 + +/* Define to the type of elements in the array set by `getgroups'. Usually + this is either `int' or `gid_t'. */ +#define GETGROUPS_T gid_t + +/* Define if gethostbyname_r returns int rather than struct hostent * */ +/* #undef GETHOSTBYNAME_R_RETURNS_INT */ + +/* Type of getpeername second argument. */ +#define GETPEERNAME_ARG3_TYPE GETSOCKNAME_ARG3_TYPE + +/* Define if getpwnam_r exists but takes only 4 arguments (e.g., POSIX draft 6 + implementations like some Solaris releases). */ +/* #undef GETPWNAM_R_4_ARGS */ + +/* Define if getpwnam_r returns an int */ +#define GETPWNAM_R_RETURNS_INT 1 + +/* Define if getpwuid_r exists but takes only 4 arguments (e.g., POSIX draft 6 + implementations like some Solaris releases). */ +/* #undef GETPWUID_R_4_ARGS */ + +/* Define if getservbyname_r returns int rather than struct servent * */ +/* #undef GETSERVBYNAME_R_RETURNS_INT */ + +/* Type of pointer target for argument 3 to getsockname */ +#define GETSOCKNAME_ARG3_TYPE socklen_t + +/* Define if gmtime_r returns int instead of struct tm pointer, as on old + HP-UX systems. */ +/* #undef GMTIME_R_RETURNS_INT */ + +/* Define if va_copy macro or function is available. */ +#define HAS_VA_COPY 1 + +/* Define to 1 if you have the `access' function. */ +#define HAVE_ACCESS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the `bswap16' function. */ +/* #undef HAVE_BSWAP16 */ + +/* Define to 1 if you have the `bswap64' function. */ +/* #undef HAVE_BSWAP64 */ + +/* Define to 1 if bswap_16 is available via byteswap.h */ +/* #undef HAVE_BSWAP_16 */ + +/* Define to 1 if bswap_64 is available via byteswap.h */ +/* #undef HAVE_BSWAP_64 */ + +/* Define if bt_rseq is available, for recursive btree traversal. */ +#define HAVE_BT_RSEQ 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BYTESWAP_H */ + +/* Define to 1 if you have the `chmod' function. */ +#define HAVE_CHMOD 1 + +/* Define if cmocka library is available. */ +/* #undef HAVE_CMOCKA */ + +/* Define to 1 if you have the `compile' function. */ +/* #undef HAVE_COMPILE */ + +/* Define if com_err has compatible gettext support */ +#define HAVE_COM_ERR_INTL 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CPUID_H */ + +/* Define to 1 if you have the `daemon' function. */ +#define HAVE_DAEMON 1 + +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +#define HAVE_DECL_STRERROR_R 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the `dn_skipname' function. */ +#define HAVE_DN_SKIPNAME 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `fchmod' function. */ +#define HAVE_FCHMOD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `flock' function. */ +#define HAVE_FLOCK 1 + +/* Define to 1 if you have the `fnmatch' function. */ +#define HAVE_FNMATCH 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FNMATCH_H 1 + +/* Define if you have the getaddrinfo function */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getenv' function. */ +#define HAVE_GETENV 1 + +/* Define to 1 if you have the `geteuid' function. */ +#define HAVE_GETEUID 1 + +/* Define if gethostbyname_r exists and its return type is known */ +/* #undef HAVE_GETHOSTBYNAME_R */ + +/* Define to 1 if you have the `getnameinfo' function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define if system getopt should be used. */ +#define HAVE_GETOPT 1 + +/* Define if system getopt_long should be used. */ +#define HAVE_GETOPT_LONG 1 + +/* Define if getpwnam_r is available and useful. */ +#define HAVE_GETPWNAM_R 1 + +/* Define if getpwuid_r is available and useful. */ +#define HAVE_GETPWUID_R 1 + +/* Define if getservbyname_r exists and its return type is known */ +/* #undef HAVE_GETSERVBYNAME_R */ + +/* Have the gettimeofday function */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `getusershell' function. */ +#define HAVE_GETUSERSHELL 1 + +/* Define to 1 if you have the `gmtime_r' function. */ +#define HAVE_GMTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IFADDRS_H 1 + +/* Define to 1 if you have the `inet_ntop' function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have the `inet_pton' function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if the system has the type `int16_t'. */ +#define HAVE_INT16_T 1 + +/* Define to 1 if the system has the type `int32_t'. */ +#define HAVE_INT32_T 1 + +/* Define to 1 if the system has the type `int8_t'. */ +#define HAVE_INT8_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_KEYUTILS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LBER_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LDAP_H */ + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#define HAVE_LIBCRYPTO 1 + +/* Define if building with libedit. */ +/* #undef HAVE_LIBEDIT */ + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#define HAVE_LIBRESOLV 1 + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define if the util library is available */ +#define HAVE_LIBUTIL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MACHINE_BYTE_ORDER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MACHINE_ENDIAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if netdb.h declares h_errno */ +#define HAVE_NETDB_H_H_ERRNO 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the `ns_initparse' function. */ +#define HAVE_NS_INITPARSE 1 + +/* Define to 1 if you have the `ns_name_uncompress' function. */ +#define HAVE_NS_NAME_UNCOMPRESS 1 + +/* Define if OpenSSL supports cms. */ +#define HAVE_OPENSSL_CMS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PATHS_H 1 + +/* Define if persistent keyrings are supported */ +/* #undef HAVE_PERSISTENT_KEYRING */ + +/* Define to 1 if you have the header file. */ +#define HAVE_POLL_H 1 + +/* Define if #pragma weak references work */ +/* #undef HAVE_PRAGMA_WEAK_REF */ + +/* Define if you have POSIX threads libraries and header files. */ +#define HAVE_PTHREAD 1 + +/* Define to 1 if you have the `pthread_once' function. */ +#define HAVE_PTHREAD_ONCE 1 + +/* Have PTHREAD_PRIO_INHERIT. */ +#define HAVE_PTHREAD_PRIO_INHERIT 1 + +/* Define to 1 if you have the `pthread_rwlock_init' function. */ +#define HAVE_PTHREAD_RWLOCK_INIT 1 + +/* Define if pthread_rwlock_init is provided in the thread library. */ +#define HAVE_PTHREAD_RWLOCK_INIT_IN_THREAD_LIB 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if building with GNU Readline. */ +/* #undef HAVE_READLINE */ + +/* Define if regcomp exists and functions */ +#define HAVE_REGCOMP 1 + +/* Define to 1 if you have the `regexec' function. */ +#define HAVE_REGEXEC 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_REGEXPR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define to 1 if you have the `res_nclose' function. */ +#define HAVE_RES_NCLOSE 1 + +/* Define to 1 if you have the `res_ndestroy' function. */ +#define HAVE_RES_NDESTROY 1 + +/* Define to 1 if you have the `res_ninit' function. */ +#define HAVE_RES_NINIT 1 + +/* Define to 1 if you have the `res_nsearch' function. */ +#define HAVE_RES_NSEARCH 1 + +/* Define to 1 if you have the `res_search' function */ +#define HAVE_RES_SEARCH 1 + +/* Define to 1 if you have the `re_comp' function. */ +/* #undef HAVE_RE_COMP */ + +/* Define to 1 if you have the `re_exec' function. */ +/* #undef HAVE_RE_EXEC */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SASL_SASL_H */ + +/* Define if struct sockaddr contains sa_len */ +#define HAVE_SA_LEN 1 + +/* Define to 1 if you have the `setegid' function. */ +#define HAVE_SETEGID 1 + +/* Define to 1 if you have the `setenv' function. */ +#define HAVE_SETENV 1 + +/* Define to 1 if you have the `seteuid' function. */ +#define HAVE_SETEUID 1 + +/* Define if setluid provided in OSF/1 security library */ +/* #undef HAVE_SETLUID */ + +/* Define to 1 if you have the `setregid' function. */ +#define HAVE_SETREGID 1 + +/* Define to 1 if you have the `setresgid' function. */ +/* #undef HAVE_SETRESGID */ + +/* Define to 1 if you have the `setresuid' function. */ +/* #undef HAVE_SETRESUID */ + +/* Define to 1 if you have the `setreuid' function. */ +#define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setsid' function. */ +#define HAVE_SETSID 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define if there is a socklen_t type. If not, probably use size_t */ +#define HAVE_SOCKLEN_T 1 + +/* Define to 1 if you have the `srand' function. */ +#define HAVE_SRAND 1 + +/* Define to 1 if you have the `srand48' function. */ +#define HAVE_SRAND48 1 + +/* Define to 1 if you have the `srandom' function. */ +#define HAVE_SRANDOM 1 + +/* Define to 1 if the system has the type `ssize_t'. */ +#define HAVE_SSIZE_T 1 + +/* Define to 1 if you have the `stat' function. */ +#define HAVE_STAT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `step' function. */ +/* #undef HAVE_STEP */ + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#define HAVE_STRLCPY 1 + +/* Define to 1 if you have the `strptime' function. */ +#define HAVE_STRPTIME 1 + +/* Define to 1 if the system has the type `struct cmsghdr'. */ +#define HAVE_STRUCT_CMSGHDR 1 + +/* Define if there is a struct if_laddrconf. */ +/* #undef HAVE_STRUCT_IF_LADDRCONF */ + +/* Define to 1 if the system has the type `struct in6_pktinfo'. */ +#define HAVE_STRUCT_IN6_PKTINFO 1 + +/* Define to 1 if the system has the type `struct in_pktinfo'. */ +#define HAVE_STRUCT_IN_PKTINFO 1 + +/* Define if there is a struct lifconf. */ +/* #undef HAVE_STRUCT_LIFCONF */ + +/* Define to 1 if the system has the type `struct rt_msghdr'. */ +#define HAVE_STRUCT_RT_MSGHDR 1 + +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if `st_mtimensec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIMENSEC */ + +/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 + +/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BSWAP_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if sys_errlist in libc */ +#define HAVE_SYS_ERRLIST 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_FILE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_FILIO_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if tcl.h found */ +/* #undef HAVE_TCL_H */ + +/* Define if tcl/tcl.h found */ +/* #undef HAVE_TCL_TCL_H */ + +/* Define to 1 if you have the `timegm' function. */ +#define HAVE_TIMEGM 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `unsetenv' function. */ +#define HAVE_UNSETENV 1 + +/* Define to 1 if the system has the type `u_char'. */ +#define HAVE_U_CHAR 1 + +/* Define to 1 if the system has the type `u_int'. */ +#define HAVE_U_INT 1 + +/* Define to 1 if the system has the type `u_int16_t'. */ +#define HAVE_U_INT16_T 1 + +/* Define to 1 if the system has the type `u_int32_t'. */ +#define HAVE_U_INT32_T 1 + +/* Define to 1 if the system has the type `u_int8_t'. */ +#define HAVE_U_INT8_T 1 + +/* Define to 1 if the system has the type `u_long'. */ +#define HAVE_U_LONG 1 + +/* Define to 1 if you have the `vasprintf' function. */ +#define HAVE_VASPRINTF 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `vsprintf' function. */ +#define HAVE_VSPRINTF 1 + +/* Define to 1 if the system has the type `__int128_t'. */ +#define HAVE___INT128_T 1 + +/* Define to 1 if the system has the type `__uint128_t'. */ +#define HAVE___UINT128_T 1 + +/* Define if errno.h declares perror */ +/* #undef HDR_HAS_PERROR */ + +/* May need to be defined to enable IPv6 support, for example on IRIX */ +/* #undef INET6 */ + +/* Define if MIT Project Athena default configuration should be used */ +/* #undef KRB5_ATHENA_COMPAT */ + +/* Define for DNS support of locating realms and KDCs */ +#undef KRB5_DNS_LOOKUP + +/* Define to enable DNS lookups of Kerberos realm names */ +/* #undef KRB5_DNS_LOOKUP_REALM */ + +/* Define if the KDC should return only vague error codes to clients */ +/* #undef KRBCONF_VAGUE_ERRORS */ + +/* define if the system header files are missing prototype for daemon() */ +#define NEED_DAEMON_PROTO 1 + +/* Define if in6addr_any is not defined in libc */ +#define NEED_INSIXADDR_ANY 1 + +/* define if the system header files are missing prototype for + ss_execute_command() */ +/* #undef NEED_SS_EXECUTE_COMMAND_PROTO */ + +/* define if the system header files are missing prototype for strptime() */ +/* #undef NEED_STRPTIME_PROTO */ + +/* define if the system header files are missing prototype for swab() */ +/* #undef NEED_SWAB_PROTO */ + +/* Define if need to declare sys_errlist */ +/* #undef NEED_SYS_ERRLIST */ + +/* define if the system header files are missing prototype for vasprintf() */ +/* #undef NEED_VASPRINTF_PROTO */ + +/* Define if the KDC should use no lookaside cache */ +/* #undef NOCACHE */ + +/* Define if references to pthread routines should be non-weak. */ +/* #undef NO_WEAK_PTHREADS */ + +/* Define if lex produes code with yylineno */ +/* #undef NO_YYLINENO */ + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "krb5-bugs@mit.edu" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "Kerberos 5" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "Kerberos 5 1.17.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "krb5" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.17.1" + +/* Define if setjmp indicates POSIX interface */ +#define POSIX_SETJMP 1 + +/* Define if POSIX signal handling is used */ +#define POSIX_SIGNALS 1 + +/* Define if POSIX signal handlers are used */ +#define POSIX_SIGTYPE 1 + +/* Define if termios.h exists and tcsetattr exists */ +#define POSIX_TERMIOS 1 + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define as return type of setrpcent */ +#define SETRPCENT_TYPE void + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 8 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 8 + +/* Define to use OpenSSL for SPAKE preauth */ +#define SPAKE_OPENSSL 1 + +/* Define for static plugin linkage */ +/* #undef STATIC_PLUGINS */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if strerror_r returns char *. */ +/* #undef STRERROR_R_CHAR_P */ + +/* Define if sys_errlist is defined in errno.h */ +#define SYS_ERRLIST_DECLARED 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define if no TLS implementation is selected */ +/* #undef TLS_IMPL_NONE */ + +/* Define if TLS implementation is OpenSSL */ +#define TLS_IMPL_OPENSSL 1 + +/* Define if you have dirent.h functionality */ +#define USE_DIRENT_H 1 + +/* Define if dlopen should be used */ +#define USE_DLOPEN 1 + +/* Define if the keyring ccache should be enabled */ +/* #undef USE_KEYRING_CCACHE */ + +/* Define if link-time options for library finalization will be used */ +/* #undef USE_LINKER_FINI_OPTION */ + +/* Define if link-time options for library initialization will be used */ +/* #undef USE_LINKER_INIT_OPTION */ + +/* Define if sigprocmask should be used */ +#define USE_SIGPROCMASK 1 + +/* Define if wait takes int as a argument */ +#define WAIT_USES_INT 1 + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#define YYTEXT_POINTER 1 + +/* Define to enable extensions in glibc */ +#define _GNU_SOURCE 1 + +/* Define to enable C11 extensions */ +#define __STDC_WANT_LIB_EXT1__ 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define krb5_sigtype to type of signal handler */ +#define krb5_sigtype void + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `long' if does not define. */ +/* #undef time_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + + +#if defined(__GNUC__) && !defined(inline) +/* Silence gcc pedantic warnings about ANSI C. */ +# define inline __inline__ +#endif +#endif /* KRB5_AUTOCONF_H */ diff --git a/contrib/krb5-cmake/autoconf.h b/contrib/krb5-cmake/autoconf_linux.h similarity index 100% rename from contrib/krb5-cmake/autoconf.h rename to contrib/krb5-cmake/autoconf_linux.h diff --git a/contrib/mariadb-connector-c b/contrib/mariadb-connector-c index 21f451d4d31..f4476ee7311 160000 --- a/contrib/mariadb-connector-c +++ b/contrib/mariadb-connector-c @@ -1 +1 @@ -Subproject commit 21f451d4d3157ffed31ec60a8b76c407190e66bd +Subproject commit f4476ee7311b35b593750f6ae2cbdb62a4006374 diff --git a/contrib/poco b/contrib/poco index fbaaba4a02e..c55b91f394e 160000 --- a/contrib/poco +++ b/contrib/poco @@ -1 +1 @@ -Subproject commit fbaaba4a02e29987b8c584747a496c79528f125f +Subproject commit c55b91f394efa9c238c33957682501681ef9b716 diff --git a/docker/test/split_build_smoke_test/Dockerfile b/docker/test/split_build_smoke_test/Dockerfile index c77db1c6c88..54a9eb17868 100644 --- a/docker/test/split_build_smoke_test/Dockerfile +++ b/docker/test/split_build_smoke_test/Dockerfile @@ -2,5 +2,6 @@ FROM yandex/clickhouse-binary-builder COPY run.sh /run.sh +COPY process_split_build_smoke_test_result.py / CMD /run.sh diff --git a/docker/test/split_build_smoke_test/process_split_build_smoke_test_result.py b/docker/test/split_build_smoke_test/process_split_build_smoke_test_result.py new file mode 100755 index 00000000000..58d6ba8c62a --- /dev/null +++ b/docker/test/split_build_smoke_test/process_split_build_smoke_test_result.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +import os +import logging +import argparse +import csv + +RESULT_LOG_NAME = "run.log" + +def process_result(result_folder): + + status = "success" + description = 'Server started and responded' + summary = [("Smoke test", "OK")] + with open(os.path.join(result_folder, RESULT_LOG_NAME), 'r') as run_log: + lines = run_log.read().split('\n') + if not lines or lines[0].strip() != 'OK': + status = "failure" + logging.info("Lines is not ok: %s", str('\n'.join(lines))) + summary = [("Smoke test", "FAIL")] + description = 'Server failed to respond, see result in logs' + + result_logs = [] + server_log_path = os.path.join(result_folder, "clickhouse-server.log") + stderr_log_path = os.path.join(result_folder, "stderr.log") + client_stderr_log_path = os.path.join(result_folder, "clientstderr.log") + + if os.path.exists(server_log_path): + result_logs.append(server_log_path) + + if os.path.exists(stderr_log_path): + result_logs.append(stderr_log_path) + + if os.path.exists(client_stderr_log_path): + result_logs.append(client_stderr_log_path) + + return status, description, summary, result_logs + + +def write_results(results_file, status_file, results, status): + with open(results_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerows(results) + with open(status_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerow(status) + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') + parser = argparse.ArgumentParser(description="ClickHouse script for parsing results of split build smoke test") + parser.add_argument("--in-results-dir", default='/test_output/') + parser.add_argument("--out-results-file", default='/test_output/test_results.tsv') + parser.add_argument("--out-status-file", default='/test_output/check_status.tsv') + args = parser.parse_args() + + state, description, test_results, logs = process_result(args.in_results_dir) + logging.info("Result parsed") + status = (state, description) + write_results(args.out_results_file, args.out_status_file, test_results, status) + logging.info("Result written") diff --git a/docker/test/split_build_smoke_test/run.sh b/docker/test/split_build_smoke_test/run.sh index eac9848030e..b565d7a481e 100755 --- a/docker/test/split_build_smoke_test/run.sh +++ b/docker/test/split_build_smoke_test/run.sh @@ -5,16 +5,18 @@ set -x install_and_run_server() { mkdir /unpacked tar -xzf /package_folder/shared_build.tgz -C /unpacked --strip 1 - LD_LIBRARY_PATH=/unpacked /unpacked/clickhouse-server --config /unpacked/config/config.xml >/var/log/clickhouse-server/stderr.log 2>&1 & + LD_LIBRARY_PATH=/unpacked /unpacked/clickhouse-server --config /unpacked/config/config.xml >/test_output/stderr.log 2>&1 & } run_client() { for i in {1..100}; do sleep 1 - LD_LIBRARY_PATH=/unpacked /unpacked/clickhouse-client --query "select 'OK'" 2>/var/log/clickhouse-server/clientstderr.log && break + LD_LIBRARY_PATH=/unpacked /unpacked/clickhouse-client --query "select 'OK'" > /test_output/run.log 2> /test_output/clientstderr.log && break [[ $i == 100 ]] && echo 'FAIL' done } install_and_run_server run_client +mv /var/log/clickhouse-server/clickhouse-server.log /test_output/clickhouse-server.log +/process_split_build_smoke_test_result.py || echo -e "failure\tCannot parse results" > /test_output/check_status.tsv diff --git a/docker/test/sqlancer/Dockerfile b/docker/test/sqlancer/Dockerfile index 38a773e65ad..6bcdc3df5cd 100644 --- a/docker/test/sqlancer/Dockerfile +++ b/docker/test/sqlancer/Dockerfile @@ -1,7 +1,7 @@ # docker build -t yandex/clickhouse-sqlancer-test . FROM ubuntu:20.04 -RUN apt-get update --yes && env DEBIAN_FRONTEND=noninteractive apt-get install wget unzip git openjdk-14-jdk maven --yes --no-install-recommends +RUN apt-get update --yes && env DEBIAN_FRONTEND=noninteractive apt-get install wget unzip git openjdk-14-jdk maven python3 --yes --no-install-recommends RUN wget https://github.com/sqlancer/sqlancer/archive/master.zip -O /sqlancer.zip RUN mkdir /sqlancer && \ @@ -10,4 +10,5 @@ RUN mkdir /sqlancer && \ RUN cd /sqlancer/sqlancer-master && mvn package -DskipTests COPY run.sh / +COPY process_sqlancer_result.py / CMD ["/bin/bash", "/run.sh"] diff --git a/docker/test/sqlancer/process_sqlancer_result.py b/docker/test/sqlancer/process_sqlancer_result.py new file mode 100755 index 00000000000..411c1e18e19 --- /dev/null +++ b/docker/test/sqlancer/process_sqlancer_result.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + +import os +import logging +import argparse +import csv + + +def process_result(result_folder): + status = "success" + summary = [] + paths = [] + tests = ["TLPWhere", "TLPGroupBy", "TLPHaving", "TLPWhereGroupBy", "TLPDistinct", "TLPAggregate"] + + for test in tests: + err_path = '{}/{}.err'.format(result_folder, test) + out_path = '{}/{}.out'.format(result_folder, test) + if not os.path.exists(err_path): + logging.info("No output err on path %s", err_path) + summary.append((test, "SKIPPED")) + elif not os.path.exists(out_path): + logging.info("No output log on path %s", out_path) + else: + paths.append(err_path) + paths.append(out_path) + with open(err_path, 'r') as f: + if 'AssertionError' in f.read(): + summary.append((test, "FAIL")) + else: + summary.append((test, "OK")) + + logs_path = '{}/logs.tar.gz'.format(result_folder) + if not os.path.exists(logs_path): + logging.info("No logs tar on path %s", logs_path) + else: + paths.append(logs_path) + stdout_path = '{}/stdout.log'.format(result_folder) + if not os.path.exists(stdout_path): + logging.info("No stdout log on path %s", stdout_path) + else: + paths.append(stdout_path) + stderr_path = '{}/stderr.log'.format(result_folder) + if not os.path.exists(stderr_path): + logging.info("No stderr log on path %s", stderr_path) + else: + paths.append(stderr_path) + + description = "SQLancer test run. See report" + + return status, description, summary, paths + + +def write_results(results_file, status_file, results, status): + with open(results_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerows(results) + with open(status_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerow(status) + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') + parser = argparse.ArgumentParser(description="ClickHouse script for parsing results of sqlancer test") + parser.add_argument("--in-results-dir", default='/test_output/') + parser.add_argument("--out-results-file", default='/test_output/test_results.tsv') + parser.add_argument("--out-status-file", default='/test_output/check_status.tsv') + args = parser.parse_args() + + state, description, test_results, logs = process_result(args.in_results_dir) + logging.info("Result parsed") + status = (state, description) + write_results(args.out_results_file, args.out_status_file, test_results, status) + logging.info("Result written") diff --git a/docker/test/sqlancer/run.sh b/docker/test/sqlancer/run.sh index ffe0afd98a8..20e82603567 100755 --- a/docker/test/sqlancer/run.sh +++ b/docker/test/sqlancer/run.sh @@ -29,4 +29,5 @@ tail -n 1000 /var/log/clickhouse-server/stderr.log > /test_output/stderr.log tail -n 1000 /var/log/clickhouse-server/stdout.log > /test_output/stdout.log tail -n 1000 /var/log/clickhouse-server/clickhouse-server.log > /test_output/clickhouse-server.log +/process_sqlancer_result.py || echo -e "failure\tCannot parse results" > /test_output/check_status.tsv ls /test_output diff --git a/docker/test/stateful/run.sh b/docker/test/stateful/run.sh index 7779f0e9dc2..6b90a9e7e37 100755 --- a/docker/test/stateful/run.sh +++ b/docker/test/stateful/run.sh @@ -65,3 +65,11 @@ if [[ -n "$USE_DATABASE_REPLICATED" ]] && [[ "$USE_DATABASE_REPLICATED" -eq 1 ]] fi clickhouse-test --testname --shard --zookeeper --no-stateless --hung-check --print-time "$SKIP_LIST_OPT" "${ADDITIONAL_OPTIONS[@]}" "$SKIP_TESTS_OPTION" 2>&1 | ts '%Y-%m-%d %H:%M:%S' | tee test_output/test_result.txt + +./process_functional_tests_result.py || echo -e "failure\tCannot parse results" > /test_output/check_status.tsv + +pigz < /var/log/clickhouse-server/clickhouse-server.log > /test_output/clickhouse-server.log.gz ||: +mv /var/log/clickhouse-server/stderr.log /test_output/ ||: +if [[ -n "$WITH_COVERAGE" ]] && [[ "$WITH_COVERAGE" -eq 1 ]]; then + tar -chf /test_output/clickhouse_coverage.tar.gz /profraw ||: +fi diff --git a/docker/test/stateless/Dockerfile b/docker/test/stateless/Dockerfile index 2437415d17c..61d1b2f4849 100644 --- a/docker/test/stateless/Dockerfile +++ b/docker/test/stateless/Dockerfile @@ -46,4 +46,5 @@ ENV NUM_TRIES=1 ENV MAX_RUN_TIME=0 COPY run.sh / +COPY process_functional_tests_result.py / CMD ["/bin/bash", "/run.sh"] diff --git a/docker/test/stateless/process_functional_tests_result.py b/docker/test/stateless/process_functional_tests_result.py new file mode 100755 index 00000000000..27210ef9b80 --- /dev/null +++ b/docker/test/stateless/process_functional_tests_result.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 + +import os +import logging +import argparse +import csv + +OK_SIGN = "[ OK " +FAIL_SING = "[ FAIL " +TIMEOUT_SING = "[ Timeout! " +UNKNOWN_SIGN = "[ UNKNOWN " +SKIPPED_SIGN = "[ SKIPPED " +HUNG_SIGN = "Found hung queries in processlist" + +def process_test_log(log_path): + total = 0 + skipped = 0 + unknown = 0 + failed = 0 + success = 0 + hung = False + test_results = [] + with open(log_path, 'r') as test_file: + for line in test_file: + line = line.strip() + if HUNG_SIGN in line: + hung = True + if any(sign in line for sign in (OK_SIGN, FAIL_SING, UNKNOWN_SIGN, SKIPPED_SIGN)): + test_name = line.split(' ')[2].split(':')[0] + + test_time = '' + try: + time_token = line.split(']')[1].strip().split()[0] + float(time_token) + test_time = time_token + except: + pass + + total += 1 + if TIMEOUT_SING in line: + failed += 1 + test_results.append((test_name, "Timeout", test_time)) + elif FAIL_SING in line: + failed += 1 + test_results.append((test_name, "FAIL", test_time)) + elif UNKNOWN_SIGN in line: + unknown += 1 + test_results.append((test_name, "FAIL", test_time)) + elif SKIPPED_SIGN in line: + skipped += 1 + test_results.append((test_name, "SKIPPED", test_time)) + else: + success += int(OK_SIGN in line) + test_results.append((test_name, "OK", test_time)) + return total, skipped, unknown, failed, success, hung, test_results + +def process_result(result_path): + test_results = [] + state = "success" + description = "" + files = os.listdir(result_path) + if files: + logging.info("Find files in result folder %s", ','.join(files)) + result_path = os.path.join(result_path, 'test_result.txt') + else: + result_path = None + description = "No output log" + state = "error" + + if result_path and os.path.exists(result_path): + total, skipped, unknown, failed, success, hung, test_results = process_test_log(result_path) + is_flacky_check = 1 < int(os.environ.get('NUM_TRIES', 1)) + # If no tests were run (success == 0) it indicates an error (e.g. server did not start or crashed immediately) + # But it's Ok for "flaky checks" - they can contain just one test for check which is marked as skipped. + if failed != 0 or unknown != 0 or (success == 0 and (not is_flacky_check)): + state = "failure" + + if hung: + description = "Some queries hung, " + state = "failure" + else: + description = "" + + description += "fail: {}, passed: {}".format(failed, success) + if skipped != 0: + description += ", skipped: {}".format(skipped) + if unknown != 0: + description += ", unknown: {}".format(unknown) + else: + state = "failure" + description = "Output log doesn't exist" + test_results = [] + + return state, description, test_results + + +def write_results(results_file, status_file, results, status): + with open(results_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerows(results) + with open(status_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerow(status) + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') + parser = argparse.ArgumentParser(description="ClickHouse script for parsing results of functional tests") + parser.add_argument("--in-results-dir", default='/test_output/') + parser.add_argument("--out-results-file", default='/test_output/test_results.tsv') + parser.add_argument("--out-status-file", default='/test_output/check_status.tsv') + args = parser.parse_args() + + state, description, test_results = process_result(args.in_results_dir) + logging.info("Result parsed") + status = (state, description) + write_results(args.out_results_file, args.out_status_file, test_results, status) + logging.info("Result written") diff --git a/docker/test/stateless/run.sh b/docker/test/stateless/run.sh index d078f3739fd..3119ae27c59 100755 --- a/docker/test/stateless/run.sh +++ b/docker/test/stateless/run.sh @@ -72,5 +72,12 @@ export -f run_tests timeout "$MAX_RUN_TIME" bash -c run_tests ||: +./process_functional_tests_result.py || echo -e "failure\tCannot parse results" > /test_output/check_status.tsv + +pigz < /var/log/clickhouse-server/clickhouse-server.log > /test_output/clickhouse-server.log.gz ||: +mv /var/log/clickhouse-server/stderr.log /test_output/ ||: +if [[ -n "$WITH_COVERAGE" ]] && [[ "$WITH_COVERAGE" -eq 1 ]]; then + tar -chf /test_output/clickhouse_coverage.tar.gz /profraw ||: +fi tar -chf /test_output/text_log_dump.tar /var/lib/clickhouse/data/system/text_log ||: tar -chf /test_output/query_log_dump.tar /var/lib/clickhouse/data/system/query_log ||: diff --git a/docker/test/stress/run.sh b/docker/test/stress/run.sh index 817a5082bb9..9ddf7421934 100755 --- a/docker/test/stress/run.sh +++ b/docker/test/stress/run.sh @@ -53,10 +53,14 @@ handle SIGBUS stop print handle SIGABRT stop print continue thread apply all backtrace -continue +detach +quit " > script.gdb - gdb -batch -command script.gdb -p "$(cat /var/run/clickhouse-server/clickhouse-server.pid)" & + # FIXME Hung check may work incorrectly because of attached gdb + # 1. False positives are possible + # 2. We cannot attach another gdb to get stacktraces if some queries hung + gdb -batch -command script.gdb -p "$(cat /var/run/clickhouse-server/clickhouse-server.pid)" >> /test_output/gdb.log & } configure @@ -78,11 +82,55 @@ clickhouse-client --query "RENAME TABLE datasets.hits_v1 TO test.hits" clickhouse-client --query "RENAME TABLE datasets.visits_v1 TO test.visits" clickhouse-client --query "SHOW TABLES FROM test" -./stress --hung-check --output-folder test_output --skip-func-tests "$SKIP_TESTS_OPTION" && echo "OK" > /test_output/script_exit_code.txt || echo "FAIL" > /test_output/script_exit_code.txt +./stress --hung-check --output-folder test_output --skip-func-tests "$SKIP_TESTS_OPTION" \ + && echo -e 'Test script exit code\tOK' >> /test_output/test_results.tsv \ + || echo -e 'Test script failed\tFAIL' >> /test_output/test_results.tsv stop start -clickhouse-client --query "SELECT 'Server successfuly started'" > /test_output/alive_check.txt || echo 'Server failed to start' > /test_output/alive_check.txt +clickhouse-client --query "SELECT 'Server successfully started', 'OK'" >> /test_output/test_results.tsv \ + || echo -e 'Server failed to start\tFAIL' >> /test_output/test_results.tsv +[ -f /var/log/clickhouse-server/clickhouse-server.log ] || echo -e "Server log does not exist\tFAIL" +[ -f /var/log/clickhouse-server/stderr.log ] || echo -e "Stderr log does not exist\tFAIL" + +# Print Fatal log messages to stdout +zgrep -Fa " " /var/log/clickhouse-server/clickhouse-server.log + +# Grep logs for sanitizer asserts, crashes and other critical errors + +# Sanitizer asserts +zgrep -Fa "==================" /var/log/clickhouse-server/stderr.log >> /test_output/tmp +zgrep -Fa "WARNING" /var/log/clickhouse-server/stderr.log >> /test_output/tmp +zgrep -Fav "ASan doesn't fully support makecontext/swapcontext functions" > /dev/null \ + && echo -e 'Sanitizer assert (in stderr.log)\tFAIL' >> /test_output/test_results.tsv \ + || echo -e 'No sanitizer asserts\tOK' >> /test_output/test_results.tsv +rm -f /test_output/tmp + +# Logical errors +zgrep -Fa "Code: 49, e.displayText() = DB::Exception:" /var/log/clickhouse-server/clickhouse-server.log > /dev/null \ + && echo -e 'Logical error thrown (see clickhouse-server.log)\tFAIL' >> /test_output/test_results.tsv \ + || echo -e 'No logical errors\tOK' >> /test_output/test_results.tsv + +# Crash +zgrep -Fa "########################################" /var/log/clickhouse-server/clickhouse-server.log > /dev/null \ + && echo -e 'Killed by signal (in clickhouse-server.log)\tFAIL' >> /test_output/test_results.tsv \ + || echo -e 'Not crashed\tOK' >> /test_output/test_results.tsv + +# It also checks for OOM or crash without stacktrace (printed by watchdog) +zgrep -Fa " " /var/log/clickhouse-server/clickhouse-server.log > /dev/null \ + && echo -e 'Fatal message in clickhouse-server.log\tFAIL' >> /test_output/test_results.tsv \ + || echo -e 'No fatal messages in clickhouse-server.log\tOK' >> /test_output/test_results.tsv + +zgrep -Fa "########################################" /test_output/* > /dev/null \ + && echo -e 'Killed by signal (output files)\tFAIL' >> /test_output/test_results.tsv + +# Put logs into /test_output/ +pigz < /var/log/clickhouse-server/clickhouse-server.log > /test_output/clickhouse-server.log.gz tar -chf /test_output/coordination.tar /var/lib/clickhouse/coordination ||: +mv /var/log/clickhouse-server/stderr.log /test_output/ + +# Write check result into check_status.tsv +clickhouse-local --structure "test String, res String" -q "SELECT 'failure', test FROM table WHERE res != 'OK' order by (lower(test) like '%hung%') LIMIT 1" < /test_output/test_results.tsv > /test_output/check_status.tsv +[ -s /test_output/check_status.tsv ] || echo -e "success\tNo errors found" > /test_output/check_status.tsv diff --git a/docker/test/stress/stress b/docker/test/stress/stress index 841556cf090..a6f1ae19303 100755 --- a/docker/test/stress/stress +++ b/docker/test/stress/stress @@ -58,6 +58,27 @@ def run_func_test(cmd, output_prefix, num_processes, skip_tests_option, global_t time.sleep(0.5) return pipes +def prepare_for_hung_check(): + # FIXME this function should not exist, but... + + # We attach gdb to clickhouse-server before running tests + # to print stacktraces of all crashes even if clickhouse cannot print it for some reason. + # However, it obstruct checking for hung queries. + logging.info("Will terminate gdb (if any)") + call("kill -TERM $(pidof gdb)", shell=True, stderr=STDOUT) + + # Some tests execute SYSTEM STOP MERGES or similar queries. + # It may cause some ALTERs to hang. + # Possibly we should fix tests and forbid to use such queries without specifying table. + call("clickhouse client -q 'SYSTEM START MERGES'", shell=True, stderr=STDOUT) + call("clickhouse client -q 'SYSTEM START DISTRIBUTED SENDS'", shell=True, stderr=STDOUT) + call("clickhouse client -q 'SYSTEM START TTL MERGES'", shell=True, stderr=STDOUT) + call("clickhouse client -q 'SYSTEM START MOVES'", shell=True, stderr=STDOUT) + call("clickhouse client -q 'SYSTEM START FETCHES'", shell=True, stderr=STDOUT) + call("clickhouse client -q 'SYSTEM START REPLICATED SENDS'", shell=True, stderr=STDOUT) + call("clickhouse client -q 'SYSTEM START REPLICATION QUEUES'", shell=True, stderr=STDOUT) + + time.sleep(30) if __name__ == "__main__": logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') @@ -88,11 +109,14 @@ if __name__ == "__main__": logging.info("All processes finished") if args.hung_check: + prepare_for_hung_check() logging.info("Checking if some queries hung") cmd = "{} {} {}".format(args.test_cmd, "--hung-check", "00001_select_1") res = call(cmd, shell=True, stderr=STDOUT) + hung_check_status = "No queries hung\tOK\n" if res != 0: logging.info("Hung check failed with exit code {}".format(res)) - sys.exit(1) + hung_check_status = "Hung check failed\tFAIL\n" + open(os.path.join(args.output_folder, "test_results.tsv"), 'w+').write(hung_check_status) logging.info("Stress test finished") diff --git a/docker/test/style/Dockerfile b/docker/test/style/Dockerfile index e70f9e05679..86595a77a54 100644 --- a/docker/test/style/Dockerfile +++ b/docker/test/style/Dockerfile @@ -10,14 +10,6 @@ RUN apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install --yes \ yamllint \ && pip3 install codespell - -# For |& syntax -SHELL ["bash", "-c"] - -CMD cd /ClickHouse/utils/check-style && \ - ./check-style -n |& tee /test_output/style_output.txt && \ - ./check-typos |& tee /test_output/typos_output.txt && \ - ./check-whitespaces -n |& tee /test_output/whitespaces_output.txt && \ - ./check-duplicate-includes.sh |& tee /test_output/duplicate_output.txt && \ - ./shellcheck-run.sh |& tee /test_output/shellcheck_output.txt && \ - true +COPY run.sh / +COPY process_style_check_result.py / +CMD ["/bin/bash", "/run.sh"] diff --git a/docker/test/style/process_style_check_result.py b/docker/test/style/process_style_check_result.py new file mode 100755 index 00000000000..61b1e0f05c5 --- /dev/null +++ b/docker/test/style/process_style_check_result.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +import os +import logging +import argparse +import csv + + +def process_result(result_folder): + status = "success" + description = "" + test_results = [] + + style_log_path = '{}/style_output.txt'.format(result_folder) + if not os.path.exists(style_log_path): + logging.info("No style check log on path %s", style_log_path) + return "exception", "No style check log", [] + elif os.stat(style_log_path).st_size != 0: + description += "Style check failed. " + test_results.append(("Style check", "FAIL")) + status = "failure" # Disabled for now + else: + test_results.append(("Style check", "OK")) + + typos_log_path = '{}/typos_output.txt'.format(result_folder) + if not os.path.exists(style_log_path): + logging.info("No typos check log on path %s", style_log_path) + return "exception", "No typos check log", [] + elif os.stat(typos_log_path).st_size != 0: + description += "Typos check failed. " + test_results.append(("Typos check", "FAIL")) + status = "failure" + else: + test_results.append(("Typos check", "OK")) + + whitespaces_log_path = '{}/whitespaces_output.txt'.format(result_folder) + if not os.path.exists(style_log_path): + logging.info("No whitespaces check log on path %s", style_log_path) + return "exception", "No whitespaces check log", [] + elif os.stat(whitespaces_log_path).st_size != 0: + description += "Whitespaces check failed. " + test_results.append(("Whitespaces check", "FAIL")) + status = "failure" + else: + test_results.append(("Whitespaces check", "OK")) + + duplicate_log_path = '{}/duplicate_output.txt'.format(result_folder) + if not os.path.exists(duplicate_log_path): + logging.info("No header duplicates check log on path %s", duplicate_log_path) + return "exception", "No header duplicates check log", [] + elif os.stat(duplicate_log_path).st_size != 0: + description += " Header duplicates check failed. " + test_results.append(("Header duplicates check", "FAIL")) + status = "failure" + else: + test_results.append(("Header duplicates check", "OK")) + + shellcheck_log_path = '{}/shellcheck_output.txt'.format(result_folder) + if not os.path.exists(shellcheck_log_path): + logging.info("No shellcheck log on path %s", shellcheck_log_path) + return "exception", "No shellcheck log", [] + elif os.stat(shellcheck_log_path).st_size != 0: + description += " Shellcheck check failed. " + test_results.append(("Shellcheck ", "FAIL")) + status = "failure" + else: + test_results.append(("Shellcheck", "OK")) + + if not description: + description += "Style check success" + + return status, description, test_results + + +def write_results(results_file, status_file, results, status): + with open(results_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerows(results) + with open(status_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerow(status) + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') + parser = argparse.ArgumentParser(description="ClickHouse script for parsing results of style check") + parser.add_argument("--in-results-dir", default='/test_output/') + parser.add_argument("--out-results-file", default='/test_output/test_results.tsv') + parser.add_argument("--out-status-file", default='/test_output/check_status.tsv') + args = parser.parse_args() + + state, description, test_results = process_result(args.in_results_dir) + logging.info("Result parsed") + status = (state, description) + write_results(args.out_results_file, args.out_status_file, test_results, status) + logging.info("Result written") diff --git a/docker/test/style/run.sh b/docker/test/style/run.sh new file mode 100755 index 00000000000..424bfe71b15 --- /dev/null +++ b/docker/test/style/run.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +cd /ClickHouse/utils/check-style || echo -e "failure\tRepo not found" > /test_output/check_status.tsv +./check-style -n |& tee /test_output/style_output.txt +./check-typos |& tee /test_output/typos_output.txt +./check-whitespaces -n |& tee /test_output/whitespaces_output.txt +./check-duplicate-includes.sh |& tee /test_output/duplicate_output.txt +./shellcheck-run.sh |& tee /test_output/shellcheck_output.txt +/process_style_check_result.py || echo -e "failure\tCannot parse results" > /test_output/check_status.tsv diff --git a/docker/test/testflows/runner/Dockerfile b/docker/test/testflows/runner/Dockerfile index 4139fb9e044..10014851a82 100644 --- a/docker/test/testflows/runner/Dockerfile +++ b/docker/test/testflows/runner/Dockerfile @@ -61,6 +61,7 @@ RUN set -eux; \ COPY modprobe.sh /usr/local/bin/modprobe COPY dockerd-entrypoint.sh /usr/local/bin/ +COPY process_testflows_result.py /usr/local/bin/ RUN set -x \ && addgroup --system dockremap \ @@ -72,5 +73,5 @@ RUN set -x \ VOLUME /var/lib/docker EXPOSE 2375 ENTRYPOINT ["dockerd-entrypoint.sh"] -CMD ["sh", "-c", "python3 regression.py --no-color -o classic --local --clickhouse-binary-path ${CLICKHOUSE_TESTS_SERVER_BIN_PATH} --log test.log ${TESTFLOWS_OPTS}; cat test.log | tfs report results --format json > results.json"] +CMD ["sh", "-c", "python3 regression.py --no-color -o classic --local --clickhouse-binary-path ${CLICKHOUSE_TESTS_SERVER_BIN_PATH} --log test.log ${TESTFLOWS_OPTS}; cat test.log | tfs report results --format json > results.json; /usr/local/bin/process_testflows_result.py || echo -e 'failure\tCannot parse results' > check_status.tsv"] diff --git a/docker/test/testflows/runner/process_testflows_result.py b/docker/test/testflows/runner/process_testflows_result.py new file mode 100755 index 00000000000..37d0b6a69d1 --- /dev/null +++ b/docker/test/testflows/runner/process_testflows_result.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +import os +import logging +import argparse +import csv +import json + + +def process_result(result_folder): + json_path = os.path.join(result_folder, "results.json") + if not os.path.exists(json_path): + return "success", "No testflows in branch", None, [] + + test_binary_log = os.path.join(result_folder, "test.log") + with open(json_path) as source: + results = json.loads(source.read()) + + total_tests = 0 + total_ok = 0 + total_fail = 0 + total_other = 0 + test_results = [] + for test in results["tests"]: + test_name = test['test']['test_name'] + test_result = test['result']['result_type'].upper() + test_time = str(test['result']['message_rtime']) + total_tests += 1 + if test_result == "OK": + total_ok += 1 + elif test_result == "FAIL" or test_result == "ERROR": + total_fail += 1 + else: + total_other += 1 + + test_results.append((test_name, test_result, test_time)) + if total_fail != 0: + status = "failure" + else: + status = "success" + + description = "failed: {}, passed: {}, other: {}".format(total_fail, total_ok, total_other) + return status, description, test_results, [json_path, test_binary_log] + + +def write_results(results_file, status_file, results, status): + with open(results_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerows(results) + with open(status_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerow(status) + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') + parser = argparse.ArgumentParser(description="ClickHouse script for parsing results of Testflows tests") + parser.add_argument("--in-results-dir", default='./') + parser.add_argument("--out-results-file", default='./test_results.tsv') + parser.add_argument("--out-status-file", default='./check_status.tsv') + args = parser.parse_args() + + state, description, test_results, logs = process_result(args.in_results_dir) + logging.info("Result parsed") + status = (state, description) + write_results(args.out_results_file, args.out_status_file, test_results, status) + logging.info("Result written") + diff --git a/docker/test/unit/Dockerfile b/docker/test/unit/Dockerfile index f01ed613918..e2f4a691939 100644 --- a/docker/test/unit/Dockerfile +++ b/docker/test/unit/Dockerfile @@ -5,6 +5,6 @@ ENV TZ=Europe/Moscow RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN apt-get install gdb -CMD service zookeeper start && sleep 7 && /usr/share/zookeeper/bin/zkCli.sh -server localhost:2181 -create create /clickhouse_test ''; \ - gdb -q -ex 'set print inferior-events off' -ex 'set confirm off' -ex 'set print thread-events off' -ex run -ex bt -ex quit --args ./unit_tests_dbms | tee test_output/test_result.txt - +COPY run.sh / +COPY process_unit_tests_result.py / +CMD ["/bin/bash", "/run.sh"] diff --git a/docker/test/unit/process_unit_tests_result.py b/docker/test/unit/process_unit_tests_result.py new file mode 100755 index 00000000000..7219aa13b82 --- /dev/null +++ b/docker/test/unit/process_unit_tests_result.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +import os +import logging +import argparse +import csv + +OK_SIGN = 'OK ]' +FAILED_SIGN = 'FAILED ]' +SEGFAULT = 'Segmentation fault' +SIGNAL = 'received signal SIG' +PASSED = 'PASSED' + +def get_test_name(line): + elements = reversed(line.split(' ')) + for element in elements: + if '(' not in element and ')' not in element: + return element + raise Exception("No test name in line '{}'".format(line)) + +def process_result(result_folder): + summary = [] + total_counter = 0 + failed_counter = 0 + result_log_path = '{}/test_result.txt'.format(result_folder) + if not os.path.exists(result_log_path): + logging.info("No output log on path %s", result_log_path) + return "exception", "No output log", [] + + status = "success" + description = "" + passed = False + with open(result_log_path, 'r') as test_result: + for line in test_result: + if OK_SIGN in line: + logging.info("Found ok line: '%s'", line) + test_name = get_test_name(line.strip()) + logging.info("Test name: '%s'", test_name) + summary.append((test_name, "OK")) + total_counter += 1 + elif FAILED_SIGN in line and 'listed below' not in line and 'ms)' in line: + logging.info("Found fail line: '%s'", line) + test_name = get_test_name(line.strip()) + logging.info("Test name: '%s'", test_name) + summary.append((test_name, "FAIL")) + total_counter += 1 + failed_counter += 1 + elif SEGFAULT in line: + logging.info("Found segfault line: '%s'", line) + status = "failure" + description += "Segmentation fault. " + break + elif SIGNAL in line: + logging.info("Received signal line: '%s'", line) + status = "failure" + description += "Exit on signal. " + break + elif PASSED in line: + logging.info("PASSED record found: '%s'", line) + passed = True + + if not passed: + status = "failure" + description += "PASSED record not found. " + + if failed_counter != 0: + status = "failure" + + if not description: + description += "fail: {}, passed: {}".format(failed_counter, total_counter - failed_counter) + + return status, description, summary + + +def write_results(results_file, status_file, results, status): + with open(results_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerows(results) + with open(status_file, 'w') as f: + out = csv.writer(f, delimiter='\t') + out.writerow(status) + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') + parser = argparse.ArgumentParser(description="ClickHouse script for parsing results of unit tests") + parser.add_argument("--in-results-dir", default='/test_output/') + parser.add_argument("--out-results-file", default='/test_output/test_results.tsv') + parser.add_argument("--out-status-file", default='/test_output/check_status.tsv') + args = parser.parse_args() + + state, description, test_results = process_result(args.in_results_dir) + logging.info("Result parsed") + status = (state, description) + write_results(args.out_results_file, args.out_status_file, test_results, status) + logging.info("Result written") + diff --git a/docker/test/unit/run.sh b/docker/test/unit/run.sh new file mode 100644 index 00000000000..abc35fa40d2 --- /dev/null +++ b/docker/test/unit/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -x + +service zookeeper start && sleep 7 && /usr/share/zookeeper/bin/zkCli.sh -server localhost:2181 -create create /clickhouse_test ''; +gdb -q -ex 'set print inferior-events off' -ex 'set confirm off' -ex 'set print thread-events off' -ex run -ex bt -ex quit --args ./unit_tests_dbms | tee test_output/test_result.txt +./process_unit_tests_result.py || echo -e "failure\tCannot parse results" > /test_output/check_status.tsv diff --git a/docs/_description_templates/template-engine.md b/docs/_description_templates/template-engine.md index 35181881134..490f490fc4e 100644 --- a/docs/_description_templates/template-engine.md +++ b/docs/_description_templates/template-engine.md @@ -58,6 +58,6 @@ Result: Follow up with any text to clarify the example. -## See Also {#see-also} +**See Also** - [link](#) diff --git a/docs/_description_templates/template-function.md b/docs/_description_templates/template-function.md index a0074a76ef6..3d4d921898a 100644 --- a/docs/_description_templates/template-function.md +++ b/docs/_description_templates/template-function.md @@ -14,12 +14,12 @@ More text (Optional). **Arguments** (Optional) -- `x` — Description. [Type name](relative/path/to/type/dscr.md#type). -- `y` — Description. [Type name](relative/path/to/type/dscr.md#type). +- `x` — Description. Optional (only for optional arguments). Possible values: . Default value: . [Type name](relative/path/to/type/dscr.md#type). +- `y` — Description. Optional (only for optional arguments). Possible values: .Default value: . [Type name](relative/path/to/type/dscr.md#type). **Parameters** (Optional, only for parametric aggregate functions) -- `z` — Description. [Type name](relative/path/to/type/dscr.md#type). +- `z` — Description. Optional (only for optional parameters). Possible values: . Default value: . [Type name](relative/path/to/type/dscr.md#type). **Returned value(s)** diff --git a/docs/_description_templates/template-server-setting.md b/docs/_description_templates/template-server-setting.md index 36a2bcacfba..0b37d46cf41 100644 --- a/docs/_description_templates/template-server-setting.md +++ b/docs/_description_templates/template-server-setting.md @@ -8,14 +8,14 @@ Possible value: ... Default value: ... -Settings: (Optional) +**Settings** (Optional) If the section contains several settings, list them here. Specify possible values and default values: - setting_1 — Description. - setting_2 — Description. -**Example:** +**Example** ```xml diff --git a/docs/_description_templates/template-statement.md b/docs/_description_templates/template-statement.md index 62ea51edf83..bca015a2ac6 100644 --- a/docs/_description_templates/template-statement.md +++ b/docs/_description_templates/template-statement.md @@ -1,14 +1,14 @@ -# Statement name (for example, SHOW USER) +# Statement name (for example, SHOW USER) {#statement-name-in-lower-case} Brief description of what the statement does. -Syntax: +**Syntax** ```sql Syntax of the statement. ``` -## Other necessary sections of the description (Optional) +## Other necessary sections of the description (Optional) {#anchor} Examples of descriptions with a complicated structure: @@ -17,7 +17,7 @@ Examples of descriptions with a complicated structure: - https://clickhouse.tech/docs/en/sql-reference/statements/select/join/ -## See Also (Optional) +**See Also** (Optional) Links to related topics as a list. diff --git a/docs/en/commercial/cloud.md b/docs/en/commercial/cloud.md index 0490881c622..91d2061c0af 100644 --- a/docs/en/commercial/cloud.md +++ b/docs/en/commercial/cloud.md @@ -29,6 +29,17 @@ toc_title: Cloud - Cross-AZ scaling for performance and high availability - Built-in monitoring and SQL query editor +## Alibaba Cloud {#alibaba-cloud} + +Alibaba Cloud Managed Service for ClickHouse [China Site](https://www.aliyun.com/product/clickhouse) (Will be available at international site at May, 2021) provides the following key features: +- Highly reliable cloud disk storage engine based on Alibaba Cloud Apsara distributed system +- Expand capacity on demand without manual data migration +- Support single-node, single-replica, multi-node, and multi-replica architectures, and support hot and cold data tiering +- Support access allow-list, one-key recovery, multi-layer network security protection, cloud disk encryption +- Seamless integration with cloud log systems, databases, and data application tools +- Built-in monitoring and database management platform +- Professional database expert technical support and service + ## Tencent Cloud {#tencent-cloud} [Tencent Managed Service for ClickHouse](https://cloud.tencent.com/product/cdwch) provides the following key features: diff --git a/docs/en/development/build.md b/docs/en/development/build.md index f98329e748f..3181f26800d 100644 --- a/docs/en/development/build.md +++ b/docs/en/development/build.md @@ -170,7 +170,7 @@ $ ./release Normally all tools of the ClickHouse bundle, such as `clickhouse-server`, `clickhouse-client` etc., are linked into a single static executable, `clickhouse`. This executable must be re-linked on every change, which might be slow. Two common ways to improve linking time are to use `lld` linker, and use the 'split' build configuration, which builds a separate binary for every tool, and further splits the code into serveral shared libraries. To enable these tweaks, pass the following flags to `cmake`: ``` --DCMAKE_C_FLAGS="-fuse-ld=lld" -DCMAKE_CXX_FLAGS="-fuse-ld=lld" -DUSE_STATIC_LIBRARIES=0 -DSPLIT_SHARED_LIBRARIES=1 -DCLICKHOUSE_SPLIT_BINARY=1 +-DCMAKE_C_FLAGS="--ld-path=lld" -DCMAKE_CXX_FLAGS="--ld-path=lld" -DUSE_STATIC_LIBRARIES=0 -DSPLIT_SHARED_LIBRARIES=1 -DCLICKHOUSE_SPLIT_BINARY=1 ``` ## You Don’t Have to Build ClickHouse {#you-dont-have-to-build-clickhouse} diff --git a/docs/en/engines/table-engines/mergetree-family/mergetree.md b/docs/en/engines/table-engines/mergetree-family/mergetree.md index 753859b46d2..52d9111dc90 100644 --- a/docs/en/engines/table-engines/mergetree-family/mergetree.md +++ b/docs/en/engines/table-engines/mergetree-family/mergetree.md @@ -701,6 +701,32 @@ The `default` storage policy implies using only one volume, which consists of on The number of threads performing background moves of data parts can be changed by [background_move_pool_size](../../../operations/settings/settings.md#background_move_pool_size) setting. +### Details {#details} + +In the case of `MergeTree` tables, data is getting to disk in different ways: + +- As a result of an insert (`INSERT` query). +- During background merges and [mutations](../../../sql-reference/statements/alter/index.md#alter-mutations). +- When downloading from another replica. +- As a result of partition freezing [ALTER TABLE … FREEZE PARTITION](../../../sql-reference/statements/alter/partition.md#alter_freeze-partition). + +In all these cases except for mutations and partition freezing, a part is stored on a volume and a disk according to the given storage policy: + +1. The first volume (in the order of definition) that has enough disk space for storing a part (`unreserved_space > current_part_size`) and allows for storing parts of a given size (`max_data_part_size_bytes > current_part_size`) is chosen. +2. Within this volume, that disk is chosen that follows the one, which was used for storing the previous chunk of data, and that has free space more than the part size (`unreserved_space - keep_free_space_bytes > current_part_size`). + +Under the hood, mutations and partition freezing make use of [hard links](https://en.wikipedia.org/wiki/Hard_link). Hard links between different disks are not supported, therefore in such cases the resulting parts are stored on the same disks as the initial ones. + +In the background, parts are moved between volumes on the basis of the amount of free space (`move_factor` parameter) according to the order the volumes are declared in the configuration file. +Data is never transferred from the last one and into the first one. One may use system tables [system.part_log](../../../operations/system-tables/part_log.md#system_tables-part-log) (field `type = MOVE_PART`) and [system.parts](../../../operations/system-tables/parts.md#system_tables-parts) (fields `path` and `disk`) to monitor background moves. Also, the detailed information can be found in server logs. + +User can force moving a part or a partition from one volume to another using the query [ALTER TABLE … MOVE PART\|PARTITION … TO VOLUME\|DISK …](../../../sql-reference/statements/alter/partition.md#alter_move-partition), all the restrictions for background operations are taken into account. The query initiates a move on its own and does not wait for background operations to be completed. User will get an error message if not enough free space is available or if any of the required conditions are not met. + +Moving data does not interfere with data replication. Therefore, different storage policies can be specified for the same table on different replicas. + +After the completion of background merges and mutations, old parts are removed only after a certain amount of time (`old_parts_lifetime`). +During this time, they are not moved to other volumes or disks. Therefore, until the parts are finally removed, they are still taken into account for evaluation of the occupied disk space. + ## Using S3 for Data Storage {#table_engine-mergetree-s3} `MergeTree` family table engines is able to store data to [S3](https://aws.amazon.com/s3/) using a disk with type `s3`. @@ -793,30 +819,4 @@ S3 disk can be configured as `main` or `cold` storage: In case of `cold` option a data can be moved to S3 if local disk free size will be smaller than `move_factor * disk_size` or by TTL move rule. -### Details {#details} - -In the case of `MergeTree` tables, data is getting to disk in different ways: - -- As a result of an insert (`INSERT` query). -- During background merges and [mutations](../../../sql-reference/statements/alter/index.md#alter-mutations). -- When downloading from another replica. -- As a result of partition freezing [ALTER TABLE … FREEZE PARTITION](../../../sql-reference/statements/alter/partition.md#alter_freeze-partition). - -In all these cases except for mutations and partition freezing, a part is stored on a volume and a disk according to the given storage policy: - -1. The first volume (in the order of definition) that has enough disk space for storing a part (`unreserved_space > current_part_size`) and allows for storing parts of a given size (`max_data_part_size_bytes > current_part_size`) is chosen. -2. Within this volume, that disk is chosen that follows the one, which was used for storing the previous chunk of data, and that has free space more than the part size (`unreserved_space - keep_free_space_bytes > current_part_size`). - -Under the hood, mutations and partition freezing make use of [hard links](https://en.wikipedia.org/wiki/Hard_link). Hard links between different disks are not supported, therefore in such cases the resulting parts are stored on the same disks as the initial ones. - -In the background, parts are moved between volumes on the basis of the amount of free space (`move_factor` parameter) according to the order the volumes are declared in the configuration file. -Data is never transferred from the last one and into the first one. One may use system tables [system.part_log](../../../operations/system-tables/part_log.md#system_tables-part-log) (field `type = MOVE_PART`) and [system.parts](../../../operations/system-tables/parts.md#system_tables-parts) (fields `path` and `disk`) to monitor background moves. Also, the detailed information can be found in server logs. - -User can force moving a part or a partition from one volume to another using the query [ALTER TABLE … MOVE PART\|PARTITION … TO VOLUME\|DISK …](../../../sql-reference/statements/alter/partition.md#alter_move-partition), all the restrictions for background operations are taken into account. The query initiates a move on its own and does not wait for background operations to be completed. User will get an error message if not enough free space is available or if any of the required conditions are not met. - -Moving data does not interfere with data replication. Therefore, different storage policies can be specified for the same table on different replicas. - -After the completion of background merges and mutations, old parts are removed only after a certain amount of time (`old_parts_lifetime`). -During this time, they are not moved to other volumes or disks. Therefore, until the parts are finally removed, they are still taken into account for evaluation of the occupied disk space. - [Original article](https://clickhouse.tech/docs/ru/operations/table_engines/mergetree/) diff --git a/docs/en/operations/external-authenticators/ldap.md b/docs/en/operations/external-authenticators/ldap.md index 4c2748d6141..ebad4f2dbe8 100644 --- a/docs/en/operations/external-authenticators/ldap.md +++ b/docs/en/operations/external-authenticators/ldap.md @@ -1,4 +1,4 @@ -# LDAP {#external-authenticators-ldap} +# LDAP {#external-authenticators-ldap} LDAP server can be used to authenticate ClickHouse users. There are two different approaches for doing this: @@ -84,11 +84,12 @@ Note, that user `my_user` refers to `my_ldap_server`. This LDAP server must be c When SQL-driven [Access Control and Account Management](../access-rights.md#access-control) is enabled, users that are authenticated by LDAP servers can also be created using the [CREATE USER](../../sql-reference/statements/create/user.md#create-user-statement) statement. + Query: -```sql + CREATE USER my_user IDENTIFIED WITH ldap SERVER 'my_ldap_server'; -``` + ## LDAP Exernal User Directory {#ldap-external-user-directory} diff --git a/docs/en/operations/system-tables/settings.md b/docs/en/operations/system-tables/settings.md index a1db0a3d558..7034fe1204f 100644 --- a/docs/en/operations/system-tables/settings.md +++ b/docs/en/operations/system-tables/settings.md @@ -48,5 +48,6 @@ SELECT * FROM system.settings WHERE changed AND name='load_balancing' - [Settings](../../operations/settings/index.md#session-settings-intro) - [Permissions for Queries](../../operations/settings/permissions-for-queries.md#settings_readonly) - [Constraints on Settings](../../operations/settings/constraints-on-settings.md) +- [SHOW SETTINGS](../../sql-reference/statements/show.md#show-settings) statement [Original article](https://clickhouse.tech/docs/en/operations/system_tables/settings) diff --git a/docs/en/operations/system-tables/trace_log.md b/docs/en/operations/system-tables/trace_log.md index 2903e0d3bd7..b3b04795a60 100644 --- a/docs/en/operations/system-tables/trace_log.md +++ b/docs/en/operations/system-tables/trace_log.md @@ -52,4 +52,5 @@ trace: [371912858,371912789,371798468,371799717,371801313,3717 size: 5244400 ``` - [Original article](https://clickhouse.tech/docs/en/operations/system_tables/trace_log) \ No newline at end of file + [Original article](https://clickhouse.tech/docs/en/operations/system-tables/trace_log) + diff --git a/docs/en/sql-reference/aggregate-functions/reference/avg.md b/docs/en/sql-reference/aggregate-functions/reference/avg.md index d53a47a36a3..cbd409ccab6 100644 --- a/docs/en/sql-reference/aggregate-functions/reference/avg.md +++ b/docs/en/sql-reference/aggregate-functions/reference/avg.md @@ -14,26 +14,19 @@ avg(x) **Arguments** -- `x` — Values. - -`x` must be -[Integer](../../../sql-reference/data-types/int-uint.md), -[floating-point](../../../sql-reference/data-types/float.md), or -[Decimal](../../../sql-reference/data-types/decimal.md). +- `x` — input values, must be [Integer](../../../sql-reference/data-types/int-uint.md), [Float](../../../sql-reference/data-types/float.md), or [Decimal](../../../sql-reference/data-types/decimal.md). **Returned value** -- `NaN` if the supplied parameter is empty. -- Mean otherwise. - -**Return type** is always [Float64](../../../sql-reference/data-types/float.md). +- The arithmetic mean, always as [Float64](../../../sql-reference/data-types/float.md). +- `NaN` if the input parameter `x` is empty. **Example** Query: ``` sql -SELECT avg(x) FROM values('x Int8', 0, 1, 2, 3, 4, 5) +SELECT avg(x) FROM values('x Int8', 0, 1, 2, 3, 4, 5); ``` Result: @@ -46,11 +39,20 @@ Result: **Example** +Create a temp table: + Query: ``` sql CREATE table test (t UInt8) ENGINE = Memory; -SELECT avg(t) FROM test +``` + +Get the arithmetic mean: + +Query: + +``` +SELECT avg(t) FROM test; ``` Result: @@ -60,3 +62,5 @@ Result: │ nan │ └────────┘ ``` + +[Original article](https://clickhouse.tech/docs/en/sql-reference/aggregate-functions/reference/avg/) diff --git a/docs/en/sql-reference/functions/date-time-functions.md b/docs/en/sql-reference/functions/date-time-functions.md index 01c8ae59e02..304371f44eb 100644 --- a/docs/en/sql-reference/functions/date-time-functions.md +++ b/docs/en/sql-reference/functions/date-time-functions.md @@ -449,13 +449,13 @@ Result: └─────────────────────┴────────────────────────────────────────────┘ ``` -**See also** +**See Also** - [toStartOfInterval](#tostartofintervaltime-or-data-interval-x-unit-time-zone) ## date\_add {#date_add} -Adds specified date/time interval to the provided date. +Adds the time interval or date interval to the provided date or date with time. **Syntax** @@ -468,22 +468,36 @@ Aliases: `dateAdd`, `DATE_ADD`. **Arguments** - `unit` — The type of interval to add. [String](../../sql-reference/data-types/string.md). + Possible values: - Supported values: second, minute, hour, day, week, month, quarter, year. -- `value` - Value in specified unit - [Int](../../sql-reference/data-types/int-uint.md) -- `date` — [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). - + - `second` + - `minute` + - `hour` + - `day` + - `week` + - `month` + - `quarter` + - `year` + +- `value` — Value of interval to add. [Int](../../sql-reference/data-types/int-uint.md). +- `date` — The date or date with time to which `value` is added. [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). **Returned value** -Returns Date or DateTime with `value` expressed in `unit` added to `date`. +Date or date with time obtained by adding `value`, expressed in `unit`, to `date`. + +Type: [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). **Example** +Query: + ```sql -select date_add(YEAR, 3, toDate('2018-01-01')); +SELECT date_add(YEAR, 3, toDate('2018-01-01')); ``` +Result: + ```text ┌─plus(toDate('2018-01-01'), toIntervalYear(3))─┐ │ 2021-01-01 │ @@ -492,7 +506,7 @@ select date_add(YEAR, 3, toDate('2018-01-01')); ## date\_diff {#date_diff} -Returns the difference between two Date or DateTime values. +Returns the difference between two dates or dates with time values. **Syntax** @@ -500,25 +514,33 @@ Returns the difference between two Date or DateTime values. date_diff('unit', startdate, enddate, [timezone]) ``` -Aliases: `dateDiff`, `DATE_DIFF`. +Aliases: `dateDiff`, `DATE_DIFF`. **Arguments** -- `unit` — The type of interval for result [String](../../sql-reference/data-types/string.md). +- `unit` — The type of interval for result. [String](../../sql-reference/data-types/string.md). + Possible values: - Supported values: second, minute, hour, day, week, month, quarter, year. + - `second` + - `minute` + - `hour` + - `day` + - `week` + - `month` + - `quarter` + - `year` - `startdate` — The first time value to subtract (the subtrahend). [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). - `enddate` — The second time value to subtract from (the minuend). [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). -- `timezone` — Optional parameter. If specified, it is applied to both `startdate` and `enddate`. If not specified, timezones of `startdate` and `enddate` are used. If they are not the same, the result is unspecified. +- `timezone` — [Timezone name](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) (optional). If specified, it is applied to both `startdate` and `enddate`. If not specified, timezones of `startdate` and `enddate` are used. If they are not the same, the result is unspecified. [String](../../sql-reference/data-types/string.md). **Returned value** Difference between `enddate` and `startdate` expressed in `unit`. -Type: `int`. +Type: [Int](../../sql-reference/data-types/int-uint.md). **Example** @@ -561,13 +583,13 @@ Aliases: `dateSub`, `DATE_SUB`. - `month` - `quarter` - `year` - + - `value` — Value of interval to subtract. [Int](../../sql-reference/data-types/int-uint.md). - `date` — The date or date with time from which `value` is subtracted. [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). **Returned value** -Returns the date or date with time obtained by subtracting `value`, expressed in `unit`, from `date`. +Date or date with time obtained by subtracting `value`, expressed in `unit`, from `date`. Type: [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). @@ -601,22 +623,36 @@ Aliases: `timeStampAdd`, `TIMESTAMP_ADD`. **Arguments** -- `date` — Date or Date with time - [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). -- `value` - Value in specified unit - [Int](../../sql-reference/data-types/int-uint.md) +- `date` — Date or date with time. [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). +- `value` — Value of interval to add. [Int](../../sql-reference/data-types/int-uint.md). - `unit` — The type of interval to add. [String](../../sql-reference/data-types/string.md). + Possible values: - Supported values: second, minute, hour, day, week, month, quarter, year. + - `second` + - `minute` + - `hour` + - `day` + - `week` + - `month` + - `quarter` + - `year` **Returned value** -Returns Date or DateTime with the specified `value` expressed in `unit` added to `date`. +Date or date with time with the specified `value` expressed in `unit` added to `date`. + +Type: [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). **Example** +Query: + ```sql select timestamp_add(toDate('2018-01-01'), INTERVAL 3 MONTH); ``` +Result: + ```text ┌─plus(toDate('2018-01-01'), toIntervalMonth(3))─┐ │ 2018-04-01 │ @@ -625,7 +661,7 @@ select timestamp_add(toDate('2018-01-01'), INTERVAL 3 MONTH); ## timestamp\_sub {#timestamp_sub} -Returns the difference between two dates in the specified unit. +Subtracts the time interval from the provided date or date with time. **Syntax** @@ -637,22 +673,37 @@ Aliases: `timeStampSub`, `TIMESTAMP_SUB`. **Arguments** -- `unit` — The type of interval to add. [String](../../sql-reference/data-types/string.md). +- `unit` — The type of interval to subtract. [String](../../sql-reference/data-types/string.md). + Possible values: - Supported values: second, minute, hour, day, week, month, quarter, year. -- `value` - Value in specified unit - [Int](../../sql-reference/data-types/int-uint.md). -- `date`- [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). + - `second` + - `minute` + - `hour` + - `day` + - `week` + - `month` + - `quarter` + - `year` + +- `value` — Value of interval to subtract. [Int](../../sql-reference/data-types/int-uint.md). +- `date` — Date or date with time. [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). **Returned value** -Difference between `date` and the specified `value` expressed in `unit`. +Date or date with time obtained by subtracting `value`, expressed in `unit`, from `date`. + +Type: [Date](../../sql-reference/data-types/date.md) or [DateTime](../../sql-reference/data-types/datetime.md). **Example** +Query: + ```sql select timestamp_sub(MONTH, 5, toDateTime('2018-12-18 01:02:03')); ``` +Result: + ```text ┌─minus(toDateTime('2018-12-18 01:02:03'), toIntervalMonth(5))─┐ │ 2018-07-18 01:02:03 │ diff --git a/docs/en/sql-reference/functions/math-functions.md b/docs/en/sql-reference/functions/math-functions.md index f56a721c0c0..bfe973e3d96 100644 --- a/docs/en/sql-reference/functions/math-functions.md +++ b/docs/en/sql-reference/functions/math-functions.md @@ -415,7 +415,7 @@ Result: ## sign(x) {#signx} -The `sign` function can extract the sign of a real number. +Returns the sign of a real number. **Syntax** @@ -433,9 +433,9 @@ sign(x) - 0 for `x = 0` - 1 for `x > 0` -**Example** +**Examples** -Query: +Sign for the zero value: ``` sql SELECT sign(0); @@ -449,7 +449,7 @@ Result: └─────────┘ ``` -Query: +Sign for the positive value: ``` sql SELECT sign(1); @@ -463,7 +463,7 @@ Result: └─────────┘ ``` -Query: +Sign for the negative value: ``` sql SELECT sign(-1); diff --git a/docs/en/sql-reference/statements/alter/user.md b/docs/en/sql-reference/statements/alter/user.md index efad6561439..b590bf4887d 100644 --- a/docs/en/sql-reference/statements/alter/user.md +++ b/docs/en/sql-reference/statements/alter/user.md @@ -12,10 +12,10 @@ Syntax: ``` sql ALTER USER [IF EXISTS] name1 [ON CLUSTER cluster_name1] [RENAME TO new_name1] [, name2 [ON CLUSTER cluster_name2] [RENAME TO new_name2] ...] - [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}] - [[ADD|DROP] HOST {LOCAL | NAME 'name' | REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE] + [NOT IDENTIFIED | IDENTIFIED {[WITH {no_password | plaintext_password | sha256_password | sha256_hash | double_sha1_password | double_sha1_hash}] BY {'password' | 'hash'}} | {WITH ldap SERVER 'server_name'} | {WITH kerberos [REALM 'realm']}] + [[ADD | DROP] HOST {LOCAL | NAME 'name' | REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE] [DEFAULT ROLE role [,...] | ALL | ALL EXCEPT role [,...] ] - [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] + [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY | WRITABLE] | PROFILE 'profile_name'] [,...] ``` To use `ALTER USER` you must have the [ALTER USER](../../../sql-reference/statements/grant.md#grant-access-management) privilege. diff --git a/docs/en/sql-reference/statements/create/user.md b/docs/en/sql-reference/statements/create/user.md index c1a52e3b864..49a4e3813a1 100644 --- a/docs/en/sql-reference/statements/create/user.md +++ b/docs/en/sql-reference/statements/create/user.md @@ -12,10 +12,10 @@ Syntax: ``` sql CREATE USER [IF NOT EXISTS | OR REPLACE] name1 [ON CLUSTER cluster_name1] [, name2 [ON CLUSTER cluster_name2] ...] - [IDENTIFIED [WITH {NO_PASSWORD|PLAINTEXT_PASSWORD|SHA256_PASSWORD|SHA256_HASH|DOUBLE_SHA1_PASSWORD|DOUBLE_SHA1_HASH|LDAP_SERVER}] BY {'password'|'hash'}] + [NOT IDENTIFIED | IDENTIFIED {[WITH {no_password | plaintext_password | sha256_password | sha256_hash | double_sha1_password | double_sha1_hash}] BY {'password' | 'hash'}} | {WITH ldap SERVER 'server_name'} | {WITH kerberos [REALM 'realm']}] [HOST {LOCAL | NAME 'name' | REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE] [DEFAULT ROLE role [,...]] - [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] + [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY | WRITABLE] | PROFILE 'profile_name'] [,...] ``` `ON CLUSTER` clause allows creating users on a cluster, see [Distributed DDL](../../../sql-reference/distributed-ddl.md). @@ -30,7 +30,8 @@ There are multiple ways of user identification: - `IDENTIFIED WITH sha256_hash BY 'hash'` - `IDENTIFIED WITH double_sha1_password BY 'qwerty'` - `IDENTIFIED WITH double_sha1_hash BY 'hash'` -- `IDENTIFIED WITH ldap_server BY 'server'` +- `IDENTIFIED WITH ldap SERVER 'server_name'` +- `IDENTIFIED WITH kerberos` or `IDENTIFIED WITH kerberos REALM 'realm'` ## User Host {#user-host} diff --git a/docs/en/sql-reference/statements/show.md b/docs/en/sql-reference/statements/show.md index 35631f8c8d6..7b3f709b876 100644 --- a/docs/en/sql-reference/statements/show.md +++ b/docs/en/sql-reference/statements/show.md @@ -428,4 +428,69 @@ errors_count: 0 estimated_recovery_time: 0 ``` -[Original article](https://clickhouse.tech/docs/en/query_language/show/) +## SHOW SETTINGS {#show-settings} + +Returns a list of system settings and their values. Selects data from the [system.settings](../../operations/system-tables/settings.md) table. + +**Syntax** + +```sql +SHOW [CHANGED] SETTINGS LIKE|ILIKE +``` + +**Clauses** + +`LIKE|ILIKE` allow to specify a matching pattern for the setting name. It can contain globs such as `%` or `_`. `LIKE` clause is case-sensitive, `ILIKE` — case insensitive. + +When the `CHANGED` clause is used, the query returns only settings changed from their default values. + +**Examples** + +Query with the `LIKE` clause: + +```sql +SHOW SETTINGS LIKE 'send_timeout'; +``` +Result: + +```text +┌─name─────────┬─type────┬─value─┐ +│ send_timeout │ Seconds │ 300 │ +└──────────────┴─────────┴───────┘ +``` + +Query with the `ILIKE` clause: + +```sql +SHOW SETTINGS ILIKE '%CONNECT_timeout%' +``` + +Result: + +```text +┌─name────────────────────────────────────┬─type─────────┬─value─┐ +│ connect_timeout │ Seconds │ 10 │ +│ connect_timeout_with_failover_ms │ Milliseconds │ 50 │ +│ connect_timeout_with_failover_secure_ms │ Milliseconds │ 100 │ +└─────────────────────────────────────────┴──────────────┴───────┘ +``` + +Query with the `CHANGED` clause: + +```sql +SHOW CHANGED SETTINGS ILIKE '%MEMORY%' +``` + +Result: + +```text +┌─name─────────────┬─type───┬─value───────┐ +│ max_memory_usage │ UInt64 │ 10000000000 │ +└──────────────────┴────────┴─────────────┘ +``` + +**See Also** + +- [system.settings](../../operations/system-tables/settings.md) table + +[Original article](https://clickhouse.tech/docs/en/sql-reference/statements/show/) diff --git a/docs/ja/commercial/cloud.md b/docs/ja/commercial/cloud.md index 403b34d198c..84f58e46cdb 100644 --- a/docs/ja/commercial/cloud.md +++ b/docs/ja/commercial/cloud.md @@ -20,4 +20,16 @@ toc_title: "\u30AF\u30E9\u30A6\u30C9" - 暗号化と分離 - 自動メンテナンス +## Alibaba Cloud {#alibaba-cloud} + +ClickHouseのためのAlibaba Cloudの管理サービス [中国サイト](https://www.aliyun.com/product/clickhouse) (2021年5月に国際サイトで利用可能になります) 次の主な機能を提供します: + +- Alibaba Cloud Apsara分散システムをベースにした信頼性の高いクラウドディスクストレージエンジン +- 手動でのデータ移行を必要とせずに、オン・デマンドで容量を拡張 +- シングル・ノード、シングル・レプリカ、マルチ・ノード、マルチ・レプリカ・アーキテクチャをサポートし、ホット・データとコールド・データの階層化をサポート +- アクセスホワイトリスト、OneKey Recovery、マルチレイヤーネットワークセキュリティ保護、クラウドディスク暗号化をサポート +- クラウドログシステム、データベース、およびデータアプリケーションツールとのシームレスな統合 +- 組み込み型の監視およびデータベース管理プラットフォーム +- プロフェッショナルデータベースエキスパートによるテクニカル・サポートとサービス + {## [元の記事](https://clickhouse.tech/docs/en/commercial/cloud/) ##} diff --git a/docs/ru/commercial/cloud.md b/docs/ru/commercial/cloud.md index 4f57592b4c7..8023f738c70 100644 --- a/docs/ru/commercial/cloud.md +++ b/docs/ru/commercial/cloud.md @@ -1,6 +1,6 @@ --- toc_priority: 1 -toc_title: "\u041f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0438\u0020\u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0445\u0020\u0443\u0441\u043b\u0443\u0433\u0020\u0043\u006c\u0069\u0063\u006b\u0048\u006f\u0075\u0073\u0065" +toc_title: "Поставщики облачных услуг ClickHouse" --- # Поставщики облачных услуг ClickHouse {#clickhouse-cloud-service-providers} diff --git a/docs/ru/commercial/index.md b/docs/ru/commercial/index.md index c6c440c17e8..66b1b125823 100644 --- a/docs/ru/commercial/index.md +++ b/docs/ru/commercial/index.md @@ -1,9 +1,7 @@ --- -toc_folder_title: "\u041A\u043E\u043C\u043C\u0435\u0440\u0447\u0435\u0441\u043A\u0438\ - \u0435 \u0443\u0441\u043B\u0443\u0433\u0438" +toc_folder_title: "Коммерческие услуги" toc_priority: 70 -toc_title: "\u041A\u043E\u043C\u043C\u0435\u0440\u0447\u0435\u0441\u043A\u0438\u0435\ - \ \u0443\u0441\u043B\u0443\u0433\u0438" +toc_title: "Коммерческие услуги" --- # Коммерческие услуги {#clickhouse-commercial-services} diff --git a/docs/ru/development/architecture.md b/docs/ru/development/architecture.md index de8fba1bc4b..9f43fabba4f 100644 --- a/docs/ru/development/architecture.md +++ b/docs/ru/development/architecture.md @@ -1,6 +1,6 @@ --- toc_priority: 62 -toc_title: "\u041e\u0431\u0437\u043e\u0440\u0020\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b\u0020\u0043\u006c\u0069\u0063\u006b\u0048\u006f\u0075\u0073\u0065" +toc_title: "Обзор архитектуры ClickHouse" --- # Обзор архитектуры ClickHouse {#overview-of-clickhouse-architecture} diff --git a/docs/ru/development/browse-code.md b/docs/ru/development/browse-code.md index ac17cf0e6f5..3f6de574abe 100644 --- a/docs/ru/development/browse-code.md +++ b/docs/ru/development/browse-code.md @@ -1,6 +1,6 @@ --- toc_priority: 71 -toc_title: "\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f\u0020\u043f\u043e\u0020\u043a\u043e\u0434\u0443\u0020\u0043\u006c\u0069\u0063\u006b\u0048\u006f\u0075\u0073\u0065" +toc_title: "Навигация по коду ClickHouse" --- diff --git a/docs/ru/development/contrib.md b/docs/ru/development/contrib.md index 05367267e41..f3310836ba9 100644 --- a/docs/ru/development/contrib.md +++ b/docs/ru/development/contrib.md @@ -1,6 +1,6 @@ --- toc_priority: 70 -toc_title: "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435\u0020\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435\u0020\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438" +toc_title: "Используемые сторонние библиотеки" --- diff --git a/docs/ru/development/developer-instruction.md b/docs/ru/development/developer-instruction.md index 7d88c97fe46..9ddb17b7212 100644 --- a/docs/ru/development/developer-instruction.md +++ b/docs/ru/development/developer-instruction.md @@ -1,6 +1,6 @@ --- toc_priority: 61 -toc_title: "\u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432" +toc_title: "Инструкция для разработчиков" --- # Инструкция для разработчиков diff --git a/docs/ru/development/style.md b/docs/ru/development/style.md index 1b211259bbb..72607ca6bad 100644 --- a/docs/ru/development/style.md +++ b/docs/ru/development/style.md @@ -1,6 +1,6 @@ --- toc_priority: 68 -toc_title: "\u041a\u0430\u043a\u0020\u043f\u0438\u0441\u0430\u0442\u044c\u0020\u043a\u043e\u0434\u0020\u043d\u0430\u0020\u0043\u002b\u002b" +toc_title: "Как писать код на C++" --- diff --git a/docs/ru/engines/database-engines/index.md b/docs/ru/engines/database-engines/index.md index 4dfe766f066..e06c032a636 100644 --- a/docs/ru/engines/database-engines/index.md +++ b/docs/ru/engines/database-engines/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u0414\u0432\u0438\u0436\u043a\u0438\u0020\u0431\u0430\u0437\u0020\u0434\u0430\u043d\u043d\u044b\u0445" +toc_folder_title: "Движки баз данных" toc_priority: 27 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435" +toc_title: "Введение" --- # Движки баз данных {#dvizhki-baz-dannykh} diff --git a/docs/ru/engines/index.md b/docs/ru/engines/index.md index 28ccc8bcfe6..fe41ada8fb6 100644 --- a/docs/ru/engines/index.md +++ b/docs/ru/engines/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0045\u006e\u0067\u0069\u006e\u0065\u0073" +toc_folder_title: "Engines" toc_hidden: true toc_priority: 25 toc_title: hidden diff --git a/docs/ru/engines/table-engines/index.md b/docs/ru/engines/table-engines/index.md index 740588c50a4..05236eb5b33 100644 --- a/docs/ru/engines/table-engines/index.md +++ b/docs/ru/engines/table-engines/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u0414\u0432\u0438\u0436\u043a\u0438\u0020\u0442\u0430\u0431\u043b\u0438\u0446" +toc_folder_title: "Движки таблиц" toc_priority: 26 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435" +toc_title: "Введение" --- diff --git a/docs/ru/engines/table-engines/integrations/index.md b/docs/ru/engines/table-engines/integrations/index.md index db7e527442e..e01d9d0cee2 100644 --- a/docs/ru/engines/table-engines/integrations/index.md +++ b/docs/ru/engines/table-engines/integrations/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0414\u0432\u0438\u0436\u043a\u0438\u0020\u0442\u0430\u0431\u043b\u0438\u0446\u0020\u0434\u043b\u044f\u0020\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438" +toc_folder_title: "Движки таблиц для интеграции" toc_priority: 30 --- diff --git a/docs/ru/engines/table-engines/log-family/index.md b/docs/ru/engines/table-engines/log-family/index.md index 7c6d2f81d7c..b2a56f650f4 100644 --- a/docs/ru/engines/table-engines/log-family/index.md +++ b/docs/ru/engines/table-engines/log-family/index.md @@ -1,6 +1,6 @@ --- -toc_folder_title: "\u0421\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u043e\u0020\u004c\u006f\u0067" -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435" +toc_folder_title: "Семейство Log" +toc_title: "Введение" toc_priority: 29 --- diff --git a/docs/ru/engines/table-engines/mergetree-family/custom-partitioning-key.md b/docs/ru/engines/table-engines/mergetree-family/custom-partitioning-key.md index 2d26528d964..00d850b01c3 100644 --- a/docs/ru/engines/table-engines/mergetree-family/custom-partitioning-key.md +++ b/docs/ru/engines/table-engines/mergetree-family/custom-partitioning-key.md @@ -1,6 +1,6 @@ --- toc_priority: 32 -toc_title: "\u041f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439\u0020\u043a\u043b\u044e\u0447\u0020\u043f\u0430\u0440\u0442\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f" +toc_title: "Произвольный ключ партиционирования" --- diff --git a/docs/ru/engines/table-engines/mergetree-family/index.md b/docs/ru/engines/table-engines/mergetree-family/index.md index abdfdd77d7f..e184e51c406 100644 --- a/docs/ru/engines/table-engines/mergetree-family/index.md +++ b/docs/ru/engines/table-engines/mergetree-family/index.md @@ -1,5 +1,5 @@ --- toc_folder_title: MergeTree Family toc_priority: 28 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435" +toc_title: "Введение" --- diff --git a/docs/ru/engines/table-engines/mergetree-family/mergetree.md b/docs/ru/engines/table-engines/mergetree-family/mergetree.md index 6fc566b7c31..bc74b2592b9 100644 --- a/docs/ru/engines/table-engines/mergetree-family/mergetree.md +++ b/docs/ru/engines/table-engines/mergetree-family/mergetree.md @@ -56,13 +56,13 @@ ORDER BY expr ClickHouse использует ключ сортировки в качестве первичного ключа, если первичный ключ не задан в секции `PRIMARY KEY`. - Чтобы отключить сортировку, используйте синтаксис `ORDER BY tuple()`. Смотрите [выбор первичного ключа](#vybor-pervichnogo-kliucha). + Чтобы отключить сортировку, используйте синтаксис `ORDER BY tuple()`. Смотрите [выбор первичного ключа](#primary-keys-and-indexes-in-queries). - `PARTITION BY` — [ключ партиционирования](custom-partitioning-key.md). Необязательный параметр. Для партиционирования по месяцам используйте выражение `toYYYYMM(date_column)`, где `date_column` — столбец с датой типа [Date](../../../engines/table-engines/mergetree-family/mergetree.md). В этом случае имена партиций имеют формат `"YYYYMM"`. -- `PRIMARY KEY` — первичный ключ, если он [отличается от ключа сортировки](#pervichnyi-kliuch-otlichnyi-ot-kliucha-sortirovki). Необязательный параметр. +- `PRIMARY KEY` — первичный ключ, если он [отличается от ключа сортировки](#choosing-a-primary-key-that-differs-from-the-sorting-key). Необязательный параметр. По умолчанию первичный ключ совпадает с ключом сортировки (который задаётся секцией `ORDER BY`.) Поэтому в большинстве случаев секцию `PRIMARY KEY` отдельно указывать не нужно. @@ -188,7 +188,7 @@ ClickHouse не требует уникального первичного кл При сортировке с использованием выражения `ORDER BY` для значений `NULL` всегда работает принцип [NULLS_LAST](../../../sql-reference/statements/select/order-by.md#sorting-of-special-values). -### Выбор первичного ключа {#vybor-pervichnogo-kliucha} +### Выбор первичного ключа {#selecting-the-primary-key} Количество столбцов в первичном ключе не ограничено явным образом. В зависимости от структуры данных в первичный ключ можно включать больше или меньше столбцов. Это может: @@ -217,7 +217,7 @@ ClickHouse не требует уникального первичного кл -### Первичный ключ, отличный от ключа сортировки {#pervichnyi-kliuch-otlichnyi-ot-kliucha-sortirovki} +### Первичный ключ, отличный от ключа сортировки {#choosing-a-primary-key-that-differs-from-the-sorting-key} Существует возможность задать первичный ключ (выражение, значения которого будут записаны в индексный файл для каждой засечки), отличный от ключа сортировки (выражение, по которому будут упорядочены строки в кусках @@ -236,7 +236,7 @@ ClickHouse не требует уникального первичного кл [ALTER ключа сортировки](../../../engines/table-engines/mergetree-family/mergetree.md) — лёгкая операция, так как при одновременном добавлении нового столбца в таблицу и ключ сортировки не нужно изменять данные кусков (они остаются упорядоченными и по новому выражению ключа). -### Использование индексов и партиций в запросах {#ispolzovanie-indeksov-i-partitsii-v-zaprosakh} +### Использование индексов и партиций в запросах {#use-of-indexes-and-partitions-in-queries} Для запросов `SELECT` ClickHouse анализирует возможность использования индекса. Индекс может использоваться, если в секции `WHERE/PREWHERE`, в качестве одного из элементов конъюнкции, или целиком, есть выражение, представляющее операции сравнения на равенства, неравенства, а также `IN` или `LIKE` с фиксированным префиксом, над столбцами или выражениями, входящими в первичный ключ или ключ партиционирования, либо над некоторыми частично монотонными функциями от этих столбцов, а также логические связки над такими выражениями. @@ -270,7 +270,7 @@ SELECT count() FROM table WHERE CounterID = 34 OR URL LIKE '%upyachka%' Ключ партиционирования по месяцам обеспечивает чтение только тех блоков данных, которые содержат даты из нужного диапазона. При этом блок данных может содержать данные за многие даты (до целого месяца). В пределах одного блока данные упорядочены по первичному ключу, который может не содержать дату в качестве первого столбца. В связи с этим, при использовании запроса с указанием условия только на дату, но не на префикс первичного ключа, будет читаться данных больше, чем за одну дату. -### Использование индекса для частично-монотонных первичных ключей {#ispolzovanie-indeksa-dlia-chastichno-monotonnykh-pervichnykh-kliuchei} +### Использование индекса для частично-монотонных первичных ключей {#use-of-index-for-partially-monotonic-primary-keys} Рассмотрим, например, дни месяца. Они образуют последовательность [монотонную](https://ru.wikipedia.org/wiki/Монотонная_последовательность) в течение одного месяца, но не монотонную на более длительных периодах. Это частично-монотонная последовательность. Если пользователь создаёт таблицу с частично-монотонным первичным ключом, ClickHouse как обычно создаёт разреженный индекс. Когда пользователь выбирает данные из такого рода таблиц, ClickHouse анализирует условия запроса. Если пользователь хочет получить данные между двумя метками индекса, и обе эти метки находятся внутри одного месяца, ClickHouse может использовать индекс в данном конкретном случае, поскольку он может рассчитать расстояние между параметрами запроса и индексными метками. @@ -312,7 +312,7 @@ SELECT count() FROM table WHERE s < 'z' SELECT count() FROM table WHERE u64 * i32 == 10 AND u64 * length(s) >= 1234 ``` -#### Доступные индексы {#dostupnye-indeksy} +#### Доступные индексы {#available-types-of-indices} - `minmax` — Хранит минимум и максимум выражения (если выражение - `tuple`, то для каждого элемента `tuple`), используя их для пропуска блоков аналогично первичному ключу. @@ -375,7 +375,7 @@ INDEX b (u64 * length(str), i32 + f64 * 100, date, str) TYPE set(100) GRANULARIT - `s != 1` - `NOT startsWith(s, 'test')` -## Конкурентный доступ к данным {#konkurentnyi-dostup-k-dannym} +## Конкурентный доступ к данным {#concurrent-data-access} Для конкурентного доступа к таблице используется мультиверсионность. То есть, при одновременном чтении и обновлении таблицы, данные будут читаться из набора кусочков, актуального на момент запроса. Длинных блокировок нет. Вставки никак не мешают чтениям. @@ -531,13 +531,13 @@ TTL d + INTERVAL 1 MONTH GROUP BY k1, k2 SET x = max(x), y = min(y); ## Хранение данных таблицы на нескольких блочных устройствах {#table_engine-mergetree-multiple-volumes} -### Введение {#vvedenie} +### Введение {#introduction} Движки таблиц семейства `MergeTree` могут хранить данные на нескольких блочных устройствах. Это может оказаться полезным, например, при неявном разделении данных одной таблицы на «горячие» и «холодные». Наиболее свежая часть занимает малый объём и запрашивается регулярно, а большой хвост исторических данных запрашивается редко. При наличии в системе нескольких дисков, «горячая» часть данных может быть размещена на быстрых дисках (например, на NVMe SSD или в памяти), а холодная на более медленных (например, HDD). Минимальной перемещаемой единицей для `MergeTree` является кусок данных (data part). Данные одного куска могут находится только на одном диске. Куски могут перемещаться между дисками в фоне, согласно пользовательским настройкам, а также с помощью запросов [ALTER](../../../engines/table-engines/mergetree-family/mergetree.md#alter_move-partition). -### Термины {#terminy} +### Термины {#terms} - Диск — примонтированное в файловой системе блочное устройство. - Диск по умолчанию — диск, на котором находится путь, указанный в конфигурационной настройке сервера [path](../../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-path). @@ -689,7 +689,7 @@ SETTINGS storage_policy = 'moving_from_ssd_to_hdd' Количество потоков для фоновых перемещений кусков между дисками можно изменить с помощью настройки [background_move_pool_size](../../../operations/settings/settings.md#background_move_pool_size) -### Особенности работы {#osobennosti-raboty} +### Особенности работы {#details} В таблицах `MergeTree` данные попадают на диск несколькими способами: @@ -712,4 +712,99 @@ SETTINGS storage_policy = 'moving_from_ssd_to_hdd' После выполнения фоновых слияний или мутаций старые куски не удаляются сразу, а через некоторое время (табличная настройка `old_parts_lifetime`). Также они не перемещаются на другие тома или диски, поэтому до момента удаления они продолжают учитываться при подсчёте занятого дискового пространства. +## Использование сервиса S3 для хранения данных {#table_engine-mergetree-s3} + +Таблицы семейства `MergeTree` могут хранить данные в сервисе [S3](https://aws.amazon.com/s3/) при использовании диска типа `s3`. + +Конфигурация: + +``` xml + + ... + + + s3 + https://storage.yandexcloud.net/my-bucket/root-path/ + your_access_key_id + your_secret_access_key + + http://proxy1 + http://proxy2 + + 10000 + 5000 + 100 + 10 + 1000 + /var/lib/clickhouse/disks/s3/ + true + /var/lib/clickhouse/disks/s3/cache/ + false + + + ... + +``` + +Обязательные параметры: + +- `endpoint` — URL точки приема запроса на стороне S3 в [форматах](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html) `path` или `virtual hosted`. URL точки должен содержать бакет и путь к корневой директории на сервере, где хранятся данные. +- `access_key_id` — id ключа доступа к S3. +- `secret_access_key` — секретный ключ доступа к S3. + +Необязательные параметры: + +- `use_environment_credentials` — признак, нужно ли считывать учетные данные AWS из переменных окружения `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` и `AWS_SESSION_TOKEN`, если они есть. Значение по умолчанию: `false`. +- `proxy` — конфигурация прокси-сервера для конечной точки S3. Каждый элемент `uri` внутри блока `proxy` должен содержать URL прокси-сервера. +- `connect_timeout_ms` — таймаут подключения к сокету в миллисекундах. Значение по умолчанию: 10 секунд. +- `request_timeout_ms` — таймаут выполнения запроса в миллисекундах. Значение по умолчанию: 5 секунд. +- `max_connections` — размер пула соединений S3. Значение по умолчанию: `100`. +- `retry_attempts` — число попыток выполнения запроса в случае возникновения ошибки. Значение по умолчанию: `10`. +- `min_bytes_for_seek` — минимальное количество байтов, которые используются для операций поиска вместо последовательного чтения. Значение по умолчанию: 1 МБайт. +- `metadata_path` — путь к локальному файловому хранилищу для хранения файлов с метаданными для S3. Значение по умолчанию: `/var/lib/clickhouse/disks//`. +- `cache_enabled` — признак, разрешено ли хранение кэша засечек и файлов индекса в локальной файловой системе. Значение по умолчанию: `true`. +- `cache_path` — путь в локальной файловой системе, где будут храниться кэш засечек и файлы индекса. Значение по умолчанию: `/var/lib/clickhouse/disks//cache/`. +- `skip_access_check` — признак, выполнять ли проверку доступов при запуске диска. Если установлено значение `true`, то проверка не выполняется. Значение по умолчанию: `false`. + + +Диск S3 может быть сконфигурирован как `main` или `cold`: + +``` xml + + ... + + + s3 + https://storage.yandexcloud.net/my-bucket/root-path/ + your_access_key_id + your_secret_access_key + + + + + +
+ s3 +
+
+
+ + +
+ default +
+ + s3 + +
+ 0.2 +
+
+ ... +
+``` + +Если диск сконфигурирован как `cold`, данные будут переноситься в S3 при срабатывании правил TTL или когда свободное место на локальном диске станет меньше порогового значения, которое определяется как `move_factor * disk_size`. + + [Оригинальная статья](https://clickhouse.tech/docs/ru/engines/table-engines/mergetree-family/mergetree/) diff --git a/docs/ru/engines/table-engines/mergetree-family/replication.md b/docs/ru/engines/table-engines/mergetree-family/replication.md index a8a308b104f..1735a02cf4c 100644 --- a/docs/ru/engines/table-engines/mergetree-family/replication.md +++ b/docs/ru/engines/table-engines/mergetree-family/replication.md @@ -1,6 +1,6 @@ --- toc_priority: 31 -toc_title: "\u0420\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044f\u0020\u0434\u0430\u043d\u043d\u044b\u0445" +toc_title: "Репликация данных" --- # Репликация данных {#table_engines-replication} diff --git a/docs/ru/engines/table-engines/special/external-data.md b/docs/ru/engines/table-engines/special/external-data.md index 7e383c0c12d..da9e132dd4f 100644 --- a/docs/ru/engines/table-engines/special/external-data.md +++ b/docs/ru/engines/table-engines/special/external-data.md @@ -1,6 +1,6 @@ --- toc_priority: 45 -toc_title: "\u0412\u043d\u0435\u0448\u043d\u0438\u0435\u0020\u0434\u0430\u043d\u043d\u044b\u0435\u0020\u0434\u043b\u044f\u0020\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438\u0020\u0437\u0430\u043f\u0440\u043e\u0441\u0430" +toc_title: "Внешние данные для обработки запроса" --- # Внешние данные для обработки запроса {#vneshnie-dannye-dlia-obrabotki-zaprosa} diff --git a/docs/ru/engines/table-engines/special/index.md b/docs/ru/engines/table-engines/special/index.md index 0d86461dd2d..0300d3ad641 100644 --- a/docs/ru/engines/table-engines/special/index.md +++ b/docs/ru/engines/table-engines/special/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435\u0020\u0434\u0432\u0438\u0436\u043a\u0438\u0020\u0442\u0430\u0431\u043b\u0438\u0446" +toc_folder_title: "Специальные движки таблиц" toc_priority: 31 --- diff --git a/docs/ru/faq/general/ne-tormozit.md b/docs/ru/faq/general/ne-tormozit.md index 59c8023da37..1230e34c475 100644 --- a/docs/ru/faq/general/ne-tormozit.md +++ b/docs/ru/faq/general/ne-tormozit.md @@ -1,6 +1,5 @@ --- -title: "What does \u201C\u043D\u0435 \u0442\u043E\u0440\u043C\u043E\u0437\u0438\u0442\ - \u201D mean?" +title: "What does “не тормозит” mean?" toc_hidden: true toc_priority: 11 --- diff --git a/docs/ru/getting-started/example-datasets/criteo.md b/docs/ru/getting-started/example-datasets/criteo.md index 7a58da5b695..ecdc5f5fa41 100644 --- a/docs/ru/getting-started/example-datasets/criteo.md +++ b/docs/ru/getting-started/example-datasets/criteo.md @@ -1,6 +1,6 @@ --- toc_priority: 18 -toc_title: "\u0422\u0435\u0440\u0430\u0431\u0430\u0439\u0442\u0020\u043b\u043e\u0433\u043e\u0432\u0020\u043a\u043b\u0438\u043a\u043e\u0432\u0020\u043e\u0442\u0020\u0043\u0072\u0069\u0074\u0065\u006f" +toc_title: "Терабайт логов кликов от Criteo" --- # Терабайт логов кликов от Criteo {#terabait-logov-klikov-ot-criteo} diff --git a/docs/ru/getting-started/example-datasets/index.md b/docs/ru/getting-started/example-datasets/index.md index eff944a7980..fd89bb122e3 100644 --- a/docs/ru/getting-started/example-datasets/index.md +++ b/docs/ru/getting-started/example-datasets/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0435\u0020\u043c\u0430\u0441\u0441\u0438\u0432\u044b\u0020\u0434\u0430\u043d\u043d\u044b\u0445" +toc_folder_title: "Тестовые массивы данных" toc_priority: 14 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435" +toc_title: "Введение" --- # Тестовые массивы данных {#testovye-massivy-dannykh} diff --git a/docs/ru/getting-started/example-datasets/metrica.md b/docs/ru/getting-started/example-datasets/metrica.md index 3246eb5178c..7deacdb836c 100644 --- a/docs/ru/getting-started/example-datasets/metrica.md +++ b/docs/ru/getting-started/example-datasets/metrica.md @@ -1,6 +1,6 @@ --- toc_priority: 15 -toc_title: "\u0410\u043d\u043e\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435\u0020\u0434\u0430\u043d\u043d\u044b\u0435\u0020\u042f\u043d\u0434\u0435\u043a\u0441\u002e\u041c\u0435\u0442\u0440\u0438\u043a\u0438" +toc_title: "Анонимизированные данные Яндекс.Метрики" --- # Анонимизированные данные Яндекс.Метрики {#anonimizirovannye-dannye-iandeks-metriki} diff --git a/docs/ru/getting-started/example-datasets/nyc-taxi.md b/docs/ru/getting-started/example-datasets/nyc-taxi.md index a4472751a99..891a92e2fa7 100644 --- a/docs/ru/getting-started/example-datasets/nyc-taxi.md +++ b/docs/ru/getting-started/example-datasets/nyc-taxi.md @@ -1,6 +1,6 @@ --- toc_priority: 20 -toc_title: "\u0414\u0430\u043d\u043d\u044b\u0435\u0020\u043e\u0020\u0442\u0430\u043a\u0441\u0438\u0020\u0432\u0020\u041d\u044c\u044e\u002d\u0419\u043e\u0440\u043a\u0435" +toc_title: "Данные о такси в Нью-Йорке" --- # Данные о такси в Нью-Йорке {#dannye-o-taksi-v-niu-iorke} diff --git a/docs/ru/getting-started/index.md b/docs/ru/getting-started/index.md index ab72ce4a1d2..78b56092740 100644 --- a/docs/ru/getting-started/index.md +++ b/docs/ru/getting-started/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u041d\u0430\u0447\u0430\u043b\u043e\u0020\u0440\u0430\u0431\u043e\u0442\u044b" +toc_folder_title: "Начало работы" toc_hidden: true toc_priority: 8 toc_title: hidden diff --git a/docs/ru/getting-started/install.md b/docs/ru/getting-started/install.md index 04efe77712b..aa5e8d77512 100644 --- a/docs/ru/getting-started/install.md +++ b/docs/ru/getting-started/install.md @@ -1,6 +1,6 @@ --- toc_priority: 11 -toc_title: "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430" +toc_title: "Установка" --- # Установка {#ustanovka} diff --git a/docs/ru/guides/apply-catboost-model.md b/docs/ru/guides/apply-catboost-model.md index 026b4d9d75e..11964c57fc7 100644 --- a/docs/ru/guides/apply-catboost-model.md +++ b/docs/ru/guides/apply-catboost-model.md @@ -1,6 +1,6 @@ --- toc_priority: 41 -toc_title: "\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u0020\u043c\u043e\u0434\u0435\u043b\u0438\u0020\u0043\u0061\u0074\u0042\u006f\u006f\u0073\u0074\u0020\u0432\u0020\u0043\u006c\u0069\u0063\u006b\u0048\u006f\u0075\u0073\u0065" +toc_title: "Применение модели CatBoost в ClickHouse" --- # Применение модели CatBoost в ClickHouse {#applying-catboost-model-in-clickhouse} diff --git a/docs/ru/guides/index.md b/docs/ru/guides/index.md index 2c38de275a7..5b305a6a135 100644 --- a/docs/ru/guides/index.md +++ b/docs/ru/guides/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u0420\u0443\u043A\u043E\u0432\u043E\u0434\u0441\u0442\u0432\u0430" +toc_folder_title: "Руководства" toc_priority: 38 -toc_title: "\u041E\u0431\u0437\u043E\u0440" +toc_title: "Обзор" --- # Руководства {#rukovodstva} diff --git a/docs/ru/index.md b/docs/ru/index.md index 617fae7ac6c..26d7dc3bf21 100644 --- a/docs/ru/index.md +++ b/docs/ru/index.md @@ -1,6 +1,6 @@ --- toc_priority: 0 -toc_title: "\u041E\u0431\u0437\u043E\u0440" +toc_title: "Обзор" --- # Что такое ClickHouse {#what-is-clickhouse} diff --git a/docs/ru/interfaces/cli.md b/docs/ru/interfaces/cli.md index b1d8c4f0732..3f6b288fc2b 100644 --- a/docs/ru/interfaces/cli.md +++ b/docs/ru/interfaces/cli.md @@ -1,6 +1,6 @@ --- toc_priority: 17 -toc_title: "\u041a\u043b\u0438\u0435\u043d\u0442\u0020\u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439\u0020\u0441\u0442\u0440\u043e\u043a\u0438" +toc_title: "Клиент командной строки" --- # Клиент командной строки {#klient-komandnoi-stroki} diff --git a/docs/ru/interfaces/cpp.md b/docs/ru/interfaces/cpp.md index 264b4f82500..018f4e22e34 100644 --- a/docs/ru/interfaces/cpp.md +++ b/docs/ru/interfaces/cpp.md @@ -1,6 +1,6 @@ --- toc_priority: 24 -toc_title: "\u0043\u002b\u002b\u0020\u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0430\u044f\u0020\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430" +toc_title: "C++ клиентская библиотека" --- # C++ клиентская библиотека {#c-klientskaia-biblioteka} diff --git a/docs/ru/interfaces/formats.md b/docs/ru/interfaces/formats.md index 98426b489e8..edea533b642 100644 --- a/docs/ru/interfaces/formats.md +++ b/docs/ru/interfaces/formats.md @@ -1,6 +1,6 @@ --- toc_priority: 21 -toc_title: "\u0424\u043e\u0440\u043c\u0430\u0442\u044b\u0020\u0432\u0445\u043e\u0434\u043d\u044b\u0445\u0020\u0438\u0020\u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0445\u0020\u0434\u0430\u043d\u043d\u044b\u0445" +toc_title: "Форматы входных и выходных данных" --- # Форматы входных и выходных данных {#formats} diff --git a/docs/ru/interfaces/http.md b/docs/ru/interfaces/http.md index d6f930f3f63..5cb50d8f168 100644 --- a/docs/ru/interfaces/http.md +++ b/docs/ru/interfaces/http.md @@ -1,6 +1,6 @@ --- toc_priority: 19 -toc_title: "\u0048\u0054\u0054\u0050\u002d\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441" +toc_title: "HTTP-интерфейс" --- # HTTP-интерфейс {#http-interface} diff --git a/docs/ru/interfaces/index.md b/docs/ru/interfaces/index.md index ea381c46206..fc8743b3c1e 100644 --- a/docs/ru/interfaces/index.md +++ b/docs/ru/interfaces/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u0418\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044B" +toc_folder_title: "Интерфейсы" toc_priority: 14 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043D\u0438\u0435" +toc_title: "Введение" --- # Интерфейсы {#interfaces} diff --git a/docs/ru/interfaces/jdbc.md b/docs/ru/interfaces/jdbc.md index 196dba64933..ac86375c74f 100644 --- a/docs/ru/interfaces/jdbc.md +++ b/docs/ru/interfaces/jdbc.md @@ -1,6 +1,6 @@ --- toc_priority: 22 -toc_title: "\u004a\u0044\u0042\u0043\u002d\u0434\u0440\u0430\u0439\u0432\u0435\u0440" +toc_title: "JDBC-драйвер" --- # JDBC-драйвер {#jdbc-draiver} diff --git a/docs/ru/interfaces/mysql.md b/docs/ru/interfaces/mysql.md index fa0003e0bea..925b1113109 100644 --- a/docs/ru/interfaces/mysql.md +++ b/docs/ru/interfaces/mysql.md @@ -1,6 +1,6 @@ --- toc_priority: 20 -toc_title: "\u004d\u0079\u0053\u0051\u004c\u002d\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441" +toc_title: "MySQL-интерфейс" --- # MySQL-интерфейс {#mysql-interface} diff --git a/docs/ru/interfaces/odbc.md b/docs/ru/interfaces/odbc.md index 728c4bd6979..7843d3cb943 100644 --- a/docs/ru/interfaces/odbc.md +++ b/docs/ru/interfaces/odbc.md @@ -1,6 +1,6 @@ --- toc_priority: 23 -toc_title: "\u004f\u0044\u0042\u0043\u002d\u0434\u0440\u0430\u0439\u0432\u0435\u0440" +toc_title: "ODBC-драйвер" --- diff --git a/docs/ru/interfaces/tcp.md b/docs/ru/interfaces/tcp.md index d89646f15b7..ea8c170009d 100644 --- a/docs/ru/interfaces/tcp.md +++ b/docs/ru/interfaces/tcp.md @@ -1,6 +1,6 @@ --- toc_priority: 18 -toc_title: "\u0420\u043e\u0434\u043d\u043e\u0439\u0020\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0020\u0028\u0054\u0043\u0050\u0029" +toc_title: "Родной интерфейс (TCP)" --- # Родной интерфейс (TCP) {#rodnoi-interfeis-tcp} diff --git a/docs/ru/interfaces/third-party/client-libraries.md b/docs/ru/interfaces/third-party/client-libraries.md index 97fa382fdd9..65e93731300 100644 --- a/docs/ru/interfaces/third-party/client-libraries.md +++ b/docs/ru/interfaces/third-party/client-libraries.md @@ -1,6 +1,6 @@ --- toc_priority: 26 -toc_title: "\u041a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0435\u0020\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438\u0020\u043e\u0442\u0020\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445\u0020\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432" +toc_title: "Клиентские библиотеки от сторонних разработчиков" --- # Клиентские библиотеки от сторонних разработчиков {#klientskie-biblioteki-ot-storonnikh-razrabotchikov} diff --git a/docs/ru/interfaces/third-party/gui.md b/docs/ru/interfaces/third-party/gui.md index 1fabdb8a31c..c02c32e08f4 100644 --- a/docs/ru/interfaces/third-party/gui.md +++ b/docs/ru/interfaces/third-party/gui.md @@ -1,6 +1,6 @@ --- toc_priority: 28 -toc_title: "\u0412\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0435\u0020\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b\u0020\u043e\u0442\u0020\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445\u0020\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432" +toc_title: "Визуальные интерфейсы от сторонних разработчиков" --- diff --git a/docs/ru/interfaces/third-party/index.md b/docs/ru/interfaces/third-party/index.md index a57169df73b..8b59bb5fd28 100644 --- a/docs/ru/interfaces/third-party/index.md +++ b/docs/ru/interfaces/third-party/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0421\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435\u0020\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b" +toc_folder_title: "Сторонние интерфейсы" toc_priority: 24 --- diff --git a/docs/ru/interfaces/third-party/integrations.md b/docs/ru/interfaces/third-party/integrations.md index 60d6181ab3f..84d5b93f92f 100644 --- a/docs/ru/interfaces/third-party/integrations.md +++ b/docs/ru/interfaces/third-party/integrations.md @@ -1,6 +1,6 @@ --- toc_priority: 27 -toc_title: "\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438\u0020\u0434\u043b\u044f\u0020\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438\u0020\u043e\u0442\u0020\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445\u0020\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432" +toc_title: "Библиотеки для интеграции от сторонних разработчиков" --- # Библиотеки для интеграции от сторонних разработчиков {#biblioteki-dlia-integratsii-ot-storonnikh-razrabotchikov} diff --git a/docs/ru/interfaces/third-party/proxy.md b/docs/ru/interfaces/third-party/proxy.md index fc66ecde293..48853cb352e 100644 --- a/docs/ru/interfaces/third-party/proxy.md +++ b/docs/ru/interfaces/third-party/proxy.md @@ -1,6 +1,6 @@ --- toc_priority: 29 -toc_title: "\u041f\u0440\u043e\u043a\u0441\u0438\u002d\u0441\u0435\u0440\u0432\u0435\u0440\u044b\u0020\u043e\u0442\u0020\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445\u0020\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432" +toc_title: "Прокси-серверы от сторонних разработчиков" --- # Прокси-серверы от сторонних разработчиков {#proksi-servery-ot-storonnikh-razrabotchikov} diff --git a/docs/ru/introduction/distinctive-features.md b/docs/ru/introduction/distinctive-features.md index 4eeeef4a443..852f5cecd5b 100644 --- a/docs/ru/introduction/distinctive-features.md +++ b/docs/ru/introduction/distinctive-features.md @@ -1,6 +1,6 @@ --- toc_priority: 4 -toc_title: "\u041e\u0442\u043b\u0438\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435\u0020\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\u0020\u0043\u006c\u0069\u0063\u006b\u0048\u006f\u0075\u0073\u0065" +toc_title: "Отличительные возможности ClickHouse" --- # Отличительные возможности ClickHouse {#otlichitelnye-vozmozhnosti-clickhouse} diff --git a/docs/ru/introduction/history.md b/docs/ru/introduction/history.md index ab740954bbe..ad17b2be27d 100644 --- a/docs/ru/introduction/history.md +++ b/docs/ru/introduction/history.md @@ -1,6 +1,6 @@ --- toc_priority: 7 -toc_title: "\u0418\u0441\u0442\u043e\u0440\u0438\u044f\u0020\u0043\u006c\u0069\u0063\u006b\u0048\u006f\u0075\u0073\u0065" +toc_title: "История ClickHouse" --- diff --git a/docs/ru/introduction/index.md b/docs/ru/introduction/index.md index 28a8e10e15b..c37cde09060 100644 --- a/docs/ru/introduction/index.md +++ b/docs/ru/introduction/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0412\u0432\u0435\u0434\u0435\u043D\u0438\u0435" +toc_folder_title: "Введение" toc_priority: 1 --- diff --git a/docs/ru/introduction/performance.md b/docs/ru/introduction/performance.md index c449e76a6ea..dd92d3df9f5 100644 --- a/docs/ru/introduction/performance.md +++ b/docs/ru/introduction/performance.md @@ -1,6 +1,6 @@ --- toc_priority: 6 -toc_title: "\u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c" +toc_title: "Производительность" --- # Производительность {#proizvoditelnost} diff --git a/docs/ru/operations/access-rights.md b/docs/ru/operations/access-rights.md index 00e55da7a82..9aa4e5f2561 100644 --- a/docs/ru/operations/access-rights.md +++ b/docs/ru/operations/access-rights.md @@ -1,6 +1,6 @@ --- toc_priority: 48 -toc_title: "\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u0020\u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c" +toc_title: "Управление доступом" --- # Управление доступом {#access-control} diff --git a/docs/ru/operations/backup.md b/docs/ru/operations/backup.md index 165b54d9b62..703217e8547 100644 --- a/docs/ru/operations/backup.md +++ b/docs/ru/operations/backup.md @@ -1,6 +1,6 @@ --- toc_priority: 49 -toc_title: "\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435\u0020\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u0020\u0434\u0430\u043d\u043d\u044b\u0445" +toc_title: "Резервное копирование данных" --- # Резервное копирование данных {#rezervnoe-kopirovanie-dannykh} diff --git a/docs/ru/operations/configuration-files.md b/docs/ru/operations/configuration-files.md index a4cc9182427..84b26d0ba2a 100644 --- a/docs/ru/operations/configuration-files.md +++ b/docs/ru/operations/configuration-files.md @@ -1,6 +1,6 @@ --- toc_priority: 50 -toc_title: "\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435\u0020\u0444\u0430\u0439\u043b\u044b" +toc_title: "Конфигурационные файлы" --- diff --git a/docs/ru/operations/index.md b/docs/ru/operations/index.md index 74a1d135967..99dcf652891 100644 --- a/docs/ru/operations/index.md +++ b/docs/ru/operations/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u042d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u044f" +toc_folder_title: "Эксплуатация" toc_priority: 41 -toc_title: "\u042d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u044f" +toc_title: "Эксплуатация" --- # Эксплуатация {#operations} diff --git a/docs/ru/operations/monitoring.md b/docs/ru/operations/monitoring.md index 52d0b5ecc8a..7656b04d011 100644 --- a/docs/ru/operations/monitoring.md +++ b/docs/ru/operations/monitoring.md @@ -1,6 +1,6 @@ --- toc_priority: 45 -toc_title: "\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433" +toc_title: "Мониторинг" --- # Мониторинг {#monitoring} diff --git a/docs/ru/operations/quotas.md b/docs/ru/operations/quotas.md index 92533eef0c1..31f3a66a1c3 100644 --- a/docs/ru/operations/quotas.md +++ b/docs/ru/operations/quotas.md @@ -1,6 +1,6 @@ --- toc_priority: 51 -toc_title: "\u041a\u0432\u043e\u0442\u044b" +toc_title: "Квоты" --- # Квоты {#quotas} diff --git a/docs/ru/operations/requirements.md b/docs/ru/operations/requirements.md index 36a7dd30b34..6567dcc9695 100644 --- a/docs/ru/operations/requirements.md +++ b/docs/ru/operations/requirements.md @@ -1,6 +1,6 @@ --- toc_priority: 44 -toc_title: "\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f" +toc_title: "Требования" --- # Требования {#trebovaniia} diff --git a/docs/ru/operations/server-configuration-parameters/index.md b/docs/ru/operations/server-configuration-parameters/index.md index a691fe69fef..f511955ebc4 100644 --- a/docs/ru/operations/server-configuration-parameters/index.md +++ b/docs/ru/operations/server-configuration-parameters/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435\u0020\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b\u0020\u0441\u0435\u0440\u0432\u0435\u0440\u0430" +toc_folder_title: "Конфигурационные параметры сервера" toc_priority: 54 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435" +toc_title: "Введение" --- # Конфигурационные параметры сервера {#server-settings} diff --git a/docs/ru/operations/server-configuration-parameters/settings.md b/docs/ru/operations/server-configuration-parameters/settings.md index 15ab13836e3..f46d899a3b7 100644 --- a/docs/ru/operations/server-configuration-parameters/settings.md +++ b/docs/ru/operations/server-configuration-parameters/settings.md @@ -1,6 +1,6 @@ --- toc_priority: 57 -toc_title: "\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435\u0020\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b\u0020\u0441\u0435\u0440\u0432\u0435\u0440\u0430" +toc_title: "Конфигурационные параметры сервера" --- # Конфигурационные параметры сервера {#server-configuration-parameters-reference} diff --git a/docs/ru/operations/settings/constraints-on-settings.md b/docs/ru/operations/settings/constraints-on-settings.md index b23be22958c..a4c1876574d 100644 --- a/docs/ru/operations/settings/constraints-on-settings.md +++ b/docs/ru/operations/settings/constraints-on-settings.md @@ -1,6 +1,6 @@ --- toc_priority: 62 -toc_title: "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u0020\u043d\u0430\u0020\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u0020\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a" +toc_title: "Ограничения на изменение настроек" --- # Ограничения на изменение настроек {#constraints-on-settings} diff --git a/docs/ru/operations/settings/permissions-for-queries.md b/docs/ru/operations/settings/permissions-for-queries.md index ae896dac77c..571f56fc3bd 100644 --- a/docs/ru/operations/settings/permissions-for-queries.md +++ b/docs/ru/operations/settings/permissions-for-queries.md @@ -1,6 +1,6 @@ --- toc_priority: 58 -toc_title: "\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f\u0020\u0434\u043b\u044f\u0020\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432" +toc_title: "Разрешения для запросов" --- # Разрешения для запросов {#permissions_for_queries} diff --git a/docs/ru/operations/settings/query-complexity.md b/docs/ru/operations/settings/query-complexity.md index b0eac5d96e7..c6e580a2209 100644 --- a/docs/ru/operations/settings/query-complexity.md +++ b/docs/ru/operations/settings/query-complexity.md @@ -1,6 +1,6 @@ --- toc_priority: 59 -toc_title: "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u0020\u043d\u0430\u0020\u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u0020\u0437\u0430\u043f\u0440\u043e\u0441\u0430" +toc_title: "Ограничения на сложность запроса" --- # Ограничения на сложность запроса {#restrictions-on-query-complexity} diff --git a/docs/ru/operations/settings/settings-profiles.md b/docs/ru/operations/settings/settings-profiles.md index 10feda01850..e8082919d89 100644 --- a/docs/ru/operations/settings/settings-profiles.md +++ b/docs/ru/operations/settings/settings-profiles.md @@ -1,6 +1,6 @@ --- toc_priority: 61 -toc_title: "\u041f\u0440\u043e\u0444\u0438\u043b\u0438\u0020\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a" +toc_title: "Профили настроек" --- # Профили настроек {#settings-profiles} diff --git a/docs/ru/operations/settings/settings-users.md b/docs/ru/operations/settings/settings-users.md index 2069922d0ea..21cd78569df 100644 --- a/docs/ru/operations/settings/settings-users.md +++ b/docs/ru/operations/settings/settings-users.md @@ -1,6 +1,6 @@ --- toc_priority: 63 -toc_title: "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0020\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439" +toc_title: "Настройки пользователей" --- # Настройки пользователей {#nastroiki-polzovatelei} diff --git a/docs/ru/operations/settings/settings.md b/docs/ru/operations/settings/settings.md index f8f587c8a36..663821158bd 100644 --- a/docs/ru/operations/settings/settings.md +++ b/docs/ru/operations/settings/settings.md @@ -1,6 +1,6 @@ --- toc_priority: 60 -toc_title: "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438" +toc_title: "Настройки" --- # Настройки {#settings} diff --git a/docs/ru/operations/system-tables/index.md b/docs/ru/operations/system-tables/index.md index cdea6102a81..e4b6f5beb9d 100644 --- a/docs/ru/operations/system-tables/index.md +++ b/docs/ru/operations/system-tables/index.md @@ -1,6 +1,6 @@ --- toc_priority: 52 -toc_title: "\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435\u0020\u0442\u0430\u0431\u043b\u0438\u0446\u044b" +toc_title: "Системные таблицы" --- # Системные таблицы {#system-tables} diff --git a/docs/ru/operations/system-tables/settings.md b/docs/ru/operations/system-tables/settings.md index c1ada37131c..50ccac684c4 100644 --- a/docs/ru/operations/system-tables/settings.md +++ b/docs/ru/operations/system-tables/settings.md @@ -48,5 +48,6 @@ SELECT * FROM system.settings WHERE changed AND name='load_balancing' - [Настройки](../settings/index.md#settings) - [Разрешения для запросов](../settings/permissions-for-queries.md#settings_readonly) - [Ограничения для значений настроек](../settings/constraints-on-settings.md) +- Выражение [SHOW SETTINGS](../../sql-reference/statements/show.md#show-settings) [Оригинальная статья](https://clickhouse.tech/docs/ru/operations/system_tables/settings) diff --git a/docs/ru/operations/system-tables/trace_log.md b/docs/ru/operations/system-tables/trace_log.md index 3f0a16199d5..88f4b29651b 100644 --- a/docs/ru/operations/system-tables/trace_log.md +++ b/docs/ru/operations/system-tables/trace_log.md @@ -12,7 +12,7 @@ ClickHouse создает эту таблицу когда утсановлен - `event_time`([DateTime](../../sql-reference/data-types/datetime.md)) — дата и время в момент снятия экземпляра стэка адресов вызова. -- `event_time_microseconds` ([DateTime](../../sql-reference/data-types/datetime.md)) — дата и время в момент снятия экземпляра стэка адресов вызова с точностью до микросекунд. +- `event_time_microseconds` ([DateTime64](../../sql-reference/data-types/datetime64.md)) — дата и время в момент снятия экземпляра стэка адресов вызова с точностью до микросекунд. - `revision`([UInt32](../../sql-reference/data-types/int-uint.md)) — ревизия сборки сервера ClickHouse. @@ -50,4 +50,4 @@ trace: [371912858,371912789,371798468,371799717,371801313,3717 size: 5244400 ``` -[Оригинальная статья](https://clickhouse.tech/docs/ru/operations/system_tables/trace_log) +[Оригинальная статья](https://clickhouse.tech/docs/ru/operations/system-tables/trace_log) diff --git a/docs/ru/operations/tips.md b/docs/ru/operations/tips.md index 40035309c03..0a2ca5ecac1 100644 --- a/docs/ru/operations/tips.md +++ b/docs/ru/operations/tips.md @@ -1,6 +1,6 @@ --- toc_priority: 58 -toc_title: "\u0421\u043e\u0432\u0435\u0442\u044b\u0020\u043f\u043e\u0020\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438" +toc_title: "Советы по эксплуатации" --- # Советы по эксплуатации {#sovety-po-ekspluatatsii} diff --git a/docs/ru/operations/troubleshooting.md b/docs/ru/operations/troubleshooting.md index 3df2a1dd46c..5882bc36f9e 100644 --- a/docs/ru/operations/troubleshooting.md +++ b/docs/ru/operations/troubleshooting.md @@ -1,6 +1,6 @@ --- toc_priority: 46 -toc_title: "\u0423\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u0020\u043d\u0435\u0438\u0441\u043f\u0440\u0430\u0432\u043d\u043e\u0441\u0442\u0435\u0439" +toc_title: "Устранение неисправностей" --- # Устранение неисправностей {#ustranenie-neispravnostei} diff --git a/docs/ru/operations/update.md b/docs/ru/operations/update.md index c74b28b3fd7..5c187ed1604 100644 --- a/docs/ru/operations/update.md +++ b/docs/ru/operations/update.md @@ -1,6 +1,6 @@ --- toc_priority: 47 -toc_title: "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u0020\u0043\u006c\u0069\u0063\u006b\u0048\u006f\u0075\u0073\u0065" +toc_title: "Обновление ClickHouse" --- # Обновление ClickHouse {#obnovlenie-clickhouse} diff --git a/docs/ru/operations/utilities/clickhouse-local.md b/docs/ru/operations/utilities/clickhouse-local.md index 15d069c9acf..137472fa993 100644 --- a/docs/ru/operations/utilities/clickhouse-local.md +++ b/docs/ru/operations/utilities/clickhouse-local.md @@ -14,9 +14,9 @@ toc_title: clickhouse-local !!! warning "Warning" Мы не рекомендуем подключать серверную конфигурацию к `clickhouse-local`, поскольку данные можно легко повредить неосторожными действиями. -Для временных данных по умолчанию создается специальный каталог. Если вы хотите обойти это действие, каталог данных можно указать с помощью опции `-- --path`. +Для временных данных по умолчанию создается специальный каталог. -## Вызов программы {#vyzov-programmy} +## Вызов программы {#usage} Основной формат вызова: @@ -31,15 +31,23 @@ $ clickhouse-local --structure "table_structure" --input-format "format_of_incom - `-if`, `--input-format` — формат входящих данных. По умолчанию — `TSV`. - `-f`, `--file` — путь к файлу с данными. По умолчанию — `stdin`. - `-q`, `--query` — запросы на выполнение. Разделитель запросов — `;`. +- `-qf`, `--queries-file` - путь к файлу с запросами для выполнения. Необходимо задать либо параметр `query`, либо `queries-file`. - `-N`, `--table` — имя таблицы, в которую будут помещены входящие данные. По умолчанию - `table`. - `-of`, `--format`, `--output-format` — формат выходных данных. По умолчанию — `TSV`. +- `-d`, `--database` — база данных по умолчанию. Если не указано, используется значение `_local`. - `--stacktrace` — вывод отладочной информации при исключениях. +- `--echo` — перед выполнением запрос выводится в консоль. - `--verbose` — подробный вывод при выполнении запроса. -- `-s` — отключает вывод системных логов в `stderr`. -- `--config-file` — путь к файлу конфигурации. По умолчанию `clickhouse-local` запускается с пустой конфигурацией. Конфигурационный файл имеет тот же формат, что и для сервера ClickHouse и в нём можно использовать все конфигурационные параметры сервера. Обычно подключение конфигурации не требуется, если требуется установить отдельный параметр, то это можно сделать ключом с именем параметра. +- `--logger.console` — логирование действий в консоль. +- `--logger.log` — логирование действий в файл с указанным именем. +- `--logger.level` — уровень логирования. +- `--ignore-error` — не прекращать обработку если запрос выдал ошибку. +- `-c`, `--config-file` — путь к файлу конфигурации. По умолчанию `clickhouse-local` запускается с пустой конфигурацией. Конфигурационный файл имеет тот же формат, что и для сервера ClickHouse, и в нём можно использовать все конфигурационные параметры сервера. Обычно подключение конфигурации не требуется; если требуется установить отдельный параметр, то это можно сделать ключом с именем параметра. +- `--no-system-tables` — запуск без использования системных таблиц. - `--help` — вывод справочной информации о `clickhouse-local`. +- `-V`, `--version` — вывод текущей версии и выход. -## Примеры вызова {#primery-vyzova} +## Примеры вызова {#examples} ``` bash $ echo -e "1,2\n3,4" | clickhouse-local --structure "a Int64, b Int64" \ diff --git a/docs/ru/operations/utilities/index.md b/docs/ru/operations/utilities/index.md index 5b55ebd798d..8b533c29ff5 100644 --- a/docs/ru/operations/utilities/index.md +++ b/docs/ru/operations/utilities/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u0423\u0442\u0438\u043b\u0438\u0442\u044b" +toc_folder_title: "Утилиты" toc_priority: 56 -toc_title: "\u041e\u0431\u0437\u043e\u0440" +toc_title: "Обзор" --- # Утилиты ClickHouse {#utility-clickhouse} diff --git a/docs/ru/sql-reference/aggregate-functions/combinators.md b/docs/ru/sql-reference/aggregate-functions/combinators.md index 592c61f87ff..3b35716ec27 100644 --- a/docs/ru/sql-reference/aggregate-functions/combinators.md +++ b/docs/ru/sql-reference/aggregate-functions/combinators.md @@ -1,6 +1,6 @@ --- toc_priority: 37 -toc_title: "\u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0442\u043e\u0440\u044b\u0020\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043d\u044b\u0445\u0020\u0444\u0443\u043d\u043a\u0446\u0438\u0439" +toc_title: "Комбинаторы агрегатных функций" --- diff --git a/docs/ru/sql-reference/aggregate-functions/index.md b/docs/ru/sql-reference/aggregate-functions/index.md index 4a7768f587f..3c931222f58 100644 --- a/docs/ru/sql-reference/aggregate-functions/index.md +++ b/docs/ru/sql-reference/aggregate-functions/index.md @@ -1,8 +1,7 @@ --- -toc_folder_title: "\u0410\u0433\u0440\u0435\u0433\u0430\u0442\u043D\u044B\u0435 \u0444\ - \u0443\u043D\u043A\u0446\u0438\u0438" +toc_folder_title: "Агрегатные функции" toc_priority: 33 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043D\u0438\u0435" +toc_title: "Введение" --- # Агрегатные функции {#aggregate-functions} diff --git a/docs/ru/sql-reference/aggregate-functions/parametric-functions.md b/docs/ru/sql-reference/aggregate-functions/parametric-functions.md index d96f7a13bcc..61518cb6f02 100644 --- a/docs/ru/sql-reference/aggregate-functions/parametric-functions.md +++ b/docs/ru/sql-reference/aggregate-functions/parametric-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 38 -toc_title: "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435\u0020\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043d\u044b\u0435\u0020\u0444\u0443\u043d\u043a\u0446\u0438\u0438" +toc_title: "Параметрические агрегатные функции" --- # Параметрические агрегатные функции {#aggregate_functions_parametric} diff --git a/docs/ru/sql-reference/aggregate-functions/reference/argmax.md b/docs/ru/sql-reference/aggregate-functions/reference/argmax.md index f44e65831a9..dd2df23e1cd 100644 --- a/docs/ru/sql-reference/aggregate-functions/reference/argmax.md +++ b/docs/ru/sql-reference/aggregate-functions/reference/argmax.md @@ -27,13 +27,13 @@ argMax(tuple(arg, val)) **Возвращаемое значение** -- Значение `arg`, соответствующее максимальному значению `val`. +- значение `arg`, соответствующее максимальному значению `val`. Тип: соответствует типу `arg`. Если передан кортеж: -- Кортеж `(arg, val)` c максимальным значением `val` и соответствующим ему `arg`. +- кортеж `(arg, val)` c максимальным значением `val` и соответствующим ему `arg`. Тип: [Tuple](../../../sql-reference/data-types/tuple.md). @@ -52,15 +52,15 @@ argMax(tuple(arg, val)) Запрос: ``` sql -SELECT argMax(user, salary), argMax(tuple(user, salary)) FROM salary; +SELECT argMax(user, salary), argMax(tuple(user, salary), salary), argMax(tuple(user, salary)) FROM salary; ``` Результат: ``` text -┌─argMax(user, salary)─┬─argMax(tuple(user, salary))─┐ -│ director │ ('director',5000) │ -└──────────────────────┴─────────────────────────────┘ +┌─argMax(user, salary)─┬─argMax(tuple(user, salary), salary)─┬─argMax(tuple(user, salary))─┐ +│ director │ ('director',5000) │ ('director',5000) │ +└──────────────────────┴─────────────────────────────────────┴─────────────────────────────┘ ``` [Оригинальная статья](https://clickhouse.tech/docs/ru/sql-reference/aggregate-functions/reference/argmax/) diff --git a/docs/ru/sql-reference/aggregate-functions/reference/avg.md b/docs/ru/sql-reference/aggregate-functions/reference/avg.md index b0bee64ec66..c032199aa32 100644 --- a/docs/ru/sql-reference/aggregate-functions/reference/avg.md +++ b/docs/ru/sql-reference/aggregate-functions/reference/avg.md @@ -4,8 +4,61 @@ toc_priority: 5 # avg {#agg_function-avg} -Вычисляет среднее. -Работает только для чисел. -Результат всегда Float64. +Вычисляет среднее арифметическое. -[Оригинальная статья](https://clickhouse.tech/docs/en/sql-reference/aggregate-functions/reference/avg/) +**Синтаксис** + +``` sql +avg(x) +``` + +**Аргументы** + +- `x` — входное значение типа [Integer](../../../sql-reference/data-types/int-uint.md), [Float](../../../sql-reference/data-types/float.md) или [Decimal](../../../sql-reference/data-types/decimal.md). + +**Возвращаемое значение** + +- среднее арифметическое, всегда типа [Float64](../../../sql-reference/data-types/float.md). +- `NaN`, если входное значение `x` — пустое. + +**Пример** + +Запрос: + +``` sql +SELECT avg(x) FROM values('x Int8', 0, 1, 2, 3, 4, 5); +``` + +Результат: + +``` text +┌─avg(x)─┐ +│ 2.5 │ +└────────┘ +``` + +**Пример** + +Создайте временную таблицу: + +Запрос: + +``` sql +CREATE table test (t UInt8) ENGINE = Memory; +``` + +Выполните запрос: + +``` sql +SELECT avg(t) FROM test; +``` + +Результат: + +``` text +┌─avg(x)─┐ +│ nan │ +└────────┘ +``` + +[Оригинальная статья](https://clickhouse.tech/docs/ru/sql-reference/aggregate-functions/reference/avg/) diff --git a/docs/ru/sql-reference/aggregate-functions/reference/index.md b/docs/ru/sql-reference/aggregate-functions/reference/index.md index 4c0060581fd..e496893a771 100644 --- a/docs/ru/sql-reference/aggregate-functions/reference/index.md +++ b/docs/ru/sql-reference/aggregate-functions/reference/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0421\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a" +toc_folder_title: "Справочник" toc_priority: 36 toc_hidden: true --- diff --git a/docs/ru/sql-reference/data-types/boolean.md b/docs/ru/sql-reference/data-types/boolean.md index bb0cd50c739..b0fad6d7446 100644 --- a/docs/ru/sql-reference/data-types/boolean.md +++ b/docs/ru/sql-reference/data-types/boolean.md @@ -1,6 +1,6 @@ --- toc_priority: 43 -toc_title: "\u0411\u0443\u043b\u0435\u0432\u044b\u0020\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f" +toc_title: "Булевы значения" --- # Булевы значения {#bulevy-znacheniia} diff --git a/docs/ru/sql-reference/data-types/domains/index.md b/docs/ru/sql-reference/data-types/domains/index.md index 4449469b1bc..6a968a76ff6 100644 --- a/docs/ru/sql-reference/data-types/domains/index.md +++ b/docs/ru/sql-reference/data-types/domains/index.md @@ -1,6 +1,6 @@ --- -toc_folder_title: "\u0414\u043e\u043c\u0435\u043d\u044b" -toc_title_title: "\u041e\u0431\u0437\u043e\u0440" +toc_folder_title: "Домены" +toc_title_title: "Обзор" toc_priority: 56 --- diff --git a/docs/ru/sql-reference/data-types/index.md b/docs/ru/sql-reference/data-types/index.md index 7a5618f4c5d..53c983a147a 100644 --- a/docs/ru/sql-reference/data-types/index.md +++ b/docs/ru/sql-reference/data-types/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u0422\u0438\u043F\u044B \u0434\u0430\u043D\u043D\u044B\u0445" +toc_folder_title: "Типы данных" toc_priority: 37 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043D\u0438\u0435" +toc_title: "Введение" --- # Типы данных {#data_types} diff --git a/docs/ru/sql-reference/data-types/nested-data-structures/index.md b/docs/ru/sql-reference/data-types/nested-data-structures/index.md index d53cabc6652..db214b90c03 100644 --- a/docs/ru/sql-reference/data-types/nested-data-structures/index.md +++ b/docs/ru/sql-reference/data-types/nested-data-structures/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0412\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435\u0020\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b\u0020\u0434\u0430\u043d\u043d\u044b\u0445" +toc_folder_title: "Вложенные структуры данных" toc_hidden: true toc_priority: 54 toc_title: hidden diff --git a/docs/ru/sql-reference/data-types/special-data-types/index.md b/docs/ru/sql-reference/data-types/special-data-types/index.md index 29c057472ea..e6d9fa8b011 100644 --- a/docs/ru/sql-reference/data-types/special-data-types/index.md +++ b/docs/ru/sql-reference/data-types/special-data-types/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0421\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0435\u0020\u0442\u0438\u043f\u044b\u0020\u0434\u0430\u043d\u043d\u044b\u0445" +toc_folder_title: "Служебные типы данных" toc_hidden: true toc_priority: 55 toc_title: hidden diff --git a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-hierarchical.md b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-hierarchical.md index 350e391dbed..9c0b731bc7d 100644 --- a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-hierarchical.md +++ b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-hierarchical.md @@ -1,6 +1,6 @@ --- toc_priority: 45 -toc_title: "\u0418\u0435\u0440\u0430\u0440\u0445\u0438\u0447\u0435\u0441\u043a\u0438\u0435\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u0438" +toc_title: "Иерархические словари" --- # Иерархические словари {#ierarkhicheskie-slovari} diff --git a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-layout.md b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-layout.md index f6b8b670563..0fd4a85c46f 100644 --- a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-layout.md +++ b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-layout.md @@ -1,6 +1,6 @@ --- toc_priority: 41 -toc_title: "\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u0435\u0439\u0020\u0432\u0020\u043f\u0430\u043c\u044f\u0442\u0438" +toc_title: "Хранение словарей в памяти" --- # Хранение словарей в памяти {#dicts-external-dicts-dict-layout} diff --git a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-lifetime.md b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-lifetime.md index ec0fb8e0ee5..cdf1b05fb37 100644 --- a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-lifetime.md +++ b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-lifetime.md @@ -1,6 +1,6 @@ --- toc_priority: 42 -toc_title: "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u0435\u0439" +toc_title: "Обновление словарей" --- # Обновление словарей {#obnovlenie-slovarei} diff --git a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-sources.md b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-sources.md index 77275b65a05..13b6a93b6ae 100644 --- a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-sources.md +++ b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-sources.md @@ -1,6 +1,6 @@ --- toc_priority: 43 -toc_title: "\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438\u0020\u0432\u043d\u0435\u0448\u043d\u0438\u0445\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u0435\u0439" +toc_title: "Источники внешних словарей" --- # Источники внешних словарей {#dicts-external-dicts-dict-sources} diff --git a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-structure.md b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-structure.md index bf87ce61b9e..6efbe706110 100644 --- a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-structure.md +++ b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict-structure.md @@ -1,6 +1,6 @@ --- toc_priority: 44 -toc_title: "\u041a\u043b\u044e\u0447\u0020\u0438\u0020\u043f\u043e\u043b\u044f\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u044f" +toc_title: "Ключ и поля словаря" --- # Ключ и поля словаря {#kliuch-i-polia-slovaria} diff --git a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict.md b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict.md index ff18f906926..7e35f59609d 100644 --- a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict.md +++ b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts-dict.md @@ -1,6 +1,6 @@ --- toc_priority: 40 -toc_title: "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0020\u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u044f" +toc_title: "Настройка внешнего словаря" --- # Настройка внешнего словаря {#dicts-external-dicts-dict} diff --git a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts.md b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts.md index c18af68c15e..6467b5f82e4 100644 --- a/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts.md +++ b/docs/ru/sql-reference/dictionaries/external-dictionaries/external-dicts.md @@ -1,6 +1,6 @@ --- toc_priority: 39 -toc_title: "\u0412\u043d\u0435\u0448\u043d\u0438\u0435\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u0438" +toc_title: "Внешние словари" --- diff --git a/docs/ru/sql-reference/dictionaries/external-dictionaries/index.md b/docs/ru/sql-reference/dictionaries/external-dictionaries/index.md index b448858b1fa..c0d954d6976 100644 --- a/docs/ru/sql-reference/dictionaries/external-dictionaries/index.md +++ b/docs/ru/sql-reference/dictionaries/external-dictionaries/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0412\u043d\u0435\u0448\u043d\u0438\u0435\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u0438" +toc_folder_title: "Внешние словари" toc_priority: 37 --- diff --git a/docs/ru/sql-reference/dictionaries/index.md b/docs/ru/sql-reference/dictionaries/index.md index 5a4119b4dd5..238aa244967 100644 --- a/docs/ru/sql-reference/dictionaries/index.md +++ b/docs/ru/sql-reference/dictionaries/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u0421\u043b\u043e\u0432\u0430\u0440\u0438" +toc_folder_title: "Словари" toc_priority: 35 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435" +toc_title: "Введение" --- # Словари {#slovari} diff --git a/docs/ru/sql-reference/dictionaries/internal-dicts.md b/docs/ru/sql-reference/dictionaries/internal-dicts.md index d8103efa6ae..af7f13f7133 100644 --- a/docs/ru/sql-reference/dictionaries/internal-dicts.md +++ b/docs/ru/sql-reference/dictionaries/internal-dicts.md @@ -1,6 +1,6 @@ --- toc_priority: 39 -toc_title: "\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u0438" +toc_title: "Встроенные словари" --- # Встроенные словари {#internal_dicts} diff --git a/docs/ru/sql-reference/distributed-ddl.md b/docs/ru/sql-reference/distributed-ddl.md index 275709320f6..17c38cfe820 100644 --- a/docs/ru/sql-reference/distributed-ddl.md +++ b/docs/ru/sql-reference/distributed-ddl.md @@ -1,6 +1,6 @@ --- toc_priority: 32 -toc_title: "\u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435\u0020\u0044\u0044\u004c\u0020\u0437\u0430\u043f\u0440\u043e\u0441\u044b\u000a" +toc_title: "Распределенные DDL запросы" --- # Распределенные DDL запросы (секция ON CLUSTER) {#raspredelennye-ddl-zaprosy-sektsiia-on-cluster} diff --git a/docs/ru/sql-reference/functions/arithmetic-functions.md b/docs/ru/sql-reference/functions/arithmetic-functions.md index 16c3e8fd8f0..779e0a9fe4a 100644 --- a/docs/ru/sql-reference/functions/arithmetic-functions.md +++ b/docs/ru/sql-reference/functions/arithmetic-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 34 -toc_title: "\u0410\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435\u0020\u0444\u0443\u043d\u043a\u0446\u0438\u0438" +toc_title: "Арифметические функции" --- # Арифметические функции {#arifmeticheskie-funktsii} diff --git a/docs/ru/sql-reference/functions/array-functions.md b/docs/ru/sql-reference/functions/array-functions.md index fe216b1aed1..dca645888a9 100644 --- a/docs/ru/sql-reference/functions/array-functions.md +++ b/docs/ru/sql-reference/functions/array-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 35 -toc_title: "\u041c\u0430\u0441\u0441\u0438\u0432\u044b" +toc_title: "Массивы" --- # Массивы {#functions-for-working-with-arrays} diff --git a/docs/ru/sql-reference/functions/array-join.md b/docs/ru/sql-reference/functions/array-join.md index 2ed3d25fa92..ed67d30062b 100644 --- a/docs/ru/sql-reference/functions/array-join.md +++ b/docs/ru/sql-reference/functions/array-join.md @@ -1,6 +1,6 @@ --- toc_priority: 61 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u044f\u0020\u0041\u0072\u0072\u0061\u0079\u004a\u006f\u0069\u006e" +toc_title: "Функция ArrayJoin" --- # Функция ArrayJoin {#functions_arrayjoin} diff --git a/docs/ru/sql-reference/functions/bit-functions.md b/docs/ru/sql-reference/functions/bit-functions.md index 8c7808437a5..79ea05f4bd7 100644 --- a/docs/ru/sql-reference/functions/bit-functions.md +++ b/docs/ru/sql-reference/functions/bit-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 48 -toc_title: "\u0411\u0438\u0442\u043e\u0432\u044b\u0435\u0020\u0444\u0443\u043d\u043a\u0446\u0438\u0438" +toc_title: "Битовые функции" --- # Битовые функции {#bitovye-funktsii} diff --git a/docs/ru/sql-reference/functions/bitmap-functions.md b/docs/ru/sql-reference/functions/bitmap-functions.md index b21ddea94e4..cd0ddee01a6 100644 --- a/docs/ru/sql-reference/functions/bitmap-functions.md +++ b/docs/ru/sql-reference/functions/bitmap-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 49 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0431\u0438\u0442\u043c\u0430\u043f\u043e\u0432" +toc_title: "Функции для битмапов" --- # Функции для битовых масок {#bitmap-functions} diff --git a/docs/ru/sql-reference/functions/comparison-functions.md b/docs/ru/sql-reference/functions/comparison-functions.md index a98c97ec96c..179df5c2ed5 100644 --- a/docs/ru/sql-reference/functions/comparison-functions.md +++ b/docs/ru/sql-reference/functions/comparison-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 36 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f" +toc_title: "Функции сравнения" --- # Функции сравнения {#funktsii-sravneniia} diff --git a/docs/ru/sql-reference/functions/conditional-functions.md b/docs/ru/sql-reference/functions/conditional-functions.md index 83268b68959..888e9427a79 100644 --- a/docs/ru/sql-reference/functions/conditional-functions.md +++ b/docs/ru/sql-reference/functions/conditional-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 43 -toc_title: "\u0423\u0441\u043b\u043e\u0432\u043d\u044b\u0435\u0020\u0444\u0443\u043d\u043a\u0446\u0438\u0438" +toc_title: "Условные функции" --- # Условные функции {#uslovnye-funktsii} diff --git a/docs/ru/sql-reference/functions/date-time-functions.md b/docs/ru/sql-reference/functions/date-time-functions.md index 1cd5ec74540..9f3df92922f 100644 --- a/docs/ru/sql-reference/functions/date-time-functions.md +++ b/docs/ru/sql-reference/functions/date-time-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 39 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u0434\u0430\u0442\u0430\u043c\u0438\u0020\u0438\u0020\u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c" +toc_title: "Функции для работы с датами и временем" --- # Функции для работы с датами и временем {#funktsii-dlia-raboty-s-datami-i-vremenem} @@ -446,7 +446,7 @@ date_trunc(unit, value[, timezone]) **Аргументы** -- `unit` — название части даты или времени. [String Literal](../syntax.md#syntax-string-literal). +- `unit` — единица измерения времени, в которой задана отсекаемая часть. [String Literal](../syntax.md#syntax-string-literal). Возможные значения: - `second` @@ -497,108 +497,98 @@ SELECT now(), date_trunc('hour', now(), 'Europe/Moscow'); └─────────────────────┴────────────────────────────────────────────┘ ``` -**См. также** +**Смотрите также** - [toStartOfInterval](#tostartofintervaltime-or-data-interval-x-unit-time-zone) -## now {#now} +## date\_add {#date_add} -Возвращает текущую дату и время. +Добавляет интервал времени или даты к указанной дате или дате со временем. **Синтаксис** ``` sql -now([timezone]) +date_add(unit, value, date) ``` -**Параметры** +Синонимы: `dateAdd`, `DATE_ADD`. -- `timezone` — [часовой пояс](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) для возвращаемого значения (необязательно). [String](../../sql-reference/data-types/string.md) +**Аргументы** + +- `unit` — единица измерения времени, в которой задан интервал для добавления. [String](../../sql-reference/data-types/string.md). + Возможные значения: + + - `second` + - `minute` + - `hour` + - `day` + - `week` + - `month` + - `quarter` + - `year` + +- `value` — значение интервала для добавления. [Int](../../sql-reference/data-types/int-uint.md). +- `date` — дата или дата со временем, к которой добавляется `value`. [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). **Возвращаемое значение** -- Текущие дата и время. +Дата или дата со временем, полученная в результате добавления `value`, выраженного в `unit`, к `date`. -Тип: [Datetime](../../sql-reference/data-types/datetime.md). +Тип: [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). **Пример** -Запрос без указания часового пояса: +Запрос: -``` sql -SELECT now(); +```sql +SELECT date_add(YEAR, 3, toDate('2018-01-01')); ``` Результат: -``` text -┌───────────────now()─┐ -│ 2020-10-17 07:42:09 │ -└─────────────────────┘ +```text +┌─plus(toDate('2018-01-01'), toIntervalYear(3))─┐ +│ 2021-01-01 │ +└───────────────────────────────────────────────┘ ``` -Запрос с указанием часового пояса: +## date\_diff {#date_diff} -``` sql -SELECT now('Europe/Moscow'); -``` - -Результат: - -``` text -┌─now('Europe/Moscow')─┐ -│ 2020-10-17 10:42:23 │ -└──────────────────────┘ -``` - -## today {#today} - -Принимает ноль аргументов и возвращает текущую дату на один из моментов выполнения запроса. -То же самое, что toDate(now()) - -## yesterday {#yesterday} - -Принимает ноль аргументов и возвращает вчерашнюю дату на один из моментов выполнения запроса. -Делает то же самое, что today() - 1. - -## dateDiff {#datediff} - -Вычисляет разницу между двумя значениями дат с временем. +Вычисляет разницу между двумя значениями дат или дат со временем. **Синтаксис** ``` sql -dateDiff('unit', startdate, enddate, [timezone]) +date_diff('unit', startdate, enddate, [timezone]) ``` -**Параметры** +Синонимы: `dateDiff`, `DATE_DIFF`. -- `unit` — Единица измерения времени, в которой будет вычислена разница между `startdate` и `enddate`. [String](../syntax.md#syntax-string-literal). +**Аргументы** - Поддерживаемые значения: +- `unit` — единица измерения времени, в которой будет выражено возвращаемое значение функции. [String](../../sql-reference/data-types/string.md). + Возможные значения: - | unit | - | ------ | - |second | - |minute | - |hour | - |day | - |week | - |month | - |quarter | - |year | + - `second` + - `minute` + - `hour` + - `day` + - `week` + - `month` + - `quarter` + - `year` -- `startdate` — Первая дата. [Date](../../sql-reference/functions/date-time-functions.md) или [DateTime](../../sql-reference/functions/date-time-functions.md). +- `startdate` — первая дата или дата со временем, которая вычитается из `enddate`. [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). -- `enddate` — Вторая дата. [Date](../../sql-reference/functions/date-time-functions.md) или [DateTime](../../sql-reference/functions/date-time-functions.md). +- `enddate` — вторая дата или дата со временем, из которой вычитается `startdate`. [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). -- `timezone` — Опциональный параметр. Если определен, применяется к обоим значениям: `startdate` и `enddate`. Если не определен, используются часовые пояса `startdate` и `enddate`. Если часовые пояса не совпадают, вернется неожидаемый результат. +- `timezone` — [часовой пояс](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) (необязательно). Если этот аргумент указан, то он применяется как для `startdate`, так и для `enddate`. Если этот аргумент не указан, то используются часовые пояса аргументов `startdate` и `enddate`. Если часовые пояса аргументов `startdate` и `enddate` не совпадают, то результат не определен. [String](../../sql-reference/data-types/string.md). **Возвращаемое значение** -Разница между `startdate` и `enddate`, выраженная в `unit`. +Разница между `enddate` и `startdate`, выраженная в `unit`. -Тип: `int`. +Тип: [Int](../../sql-reference/data-types/int-uint.md). **Пример** @@ -641,13 +631,13 @@ date_sub(unit, value, date) - `month` - `quarter` - `year` - -- `value` — значение интервала для вычитания. [Int](../../sql-reference/data-types/int-uint.md). + +- `value` — значение интервала для вычитания. [Int](../../sql-reference/data-types/int-uint.md). - `date` — дата или дата со временем, из которой вычитается `value`. [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). **Возвращаемое значение** -Возвращает дату или дату со временем, полученную в результате вычитания `value`, выраженного в `unit`, из `date`. +Дата или дата со временем, полученная в результате вычитания `value`, выраженного в `unit`, из `date`. Тип: [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). @@ -667,6 +657,167 @@ SELECT date_sub(YEAR, 3, toDate('2018-01-01')); └────────────────────────────────────────────────┘ ``` +## timestamp\_add {#timestamp_add} + +Добавляет интервал времени к указанной дате или дате со временем. + +**Синтаксис** + +``` sql +timestamp_add(date, INTERVAL value unit) +``` + +Синонимы: `timeStampAdd`, `TIMESTAMP_ADD`. + +**Аргументы** + +- `date` — дата или дата со временем. [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). +- `value` — значение интервала для добавления. [Int](../../sql-reference/data-types/int-uint.md). +- `unit` — единица измерения времени, в которой задан интервал для добавления. [String](../../sql-reference/data-types/string.md). + Возможные значения: + + - `second` + - `minute` + - `hour` + - `day` + - `week` + - `month` + - `quarter` + - `year` + +**Возвращаемое значение** + +Дата или дата со временем, полученная в результате добавления `value`, выраженного в `unit`, к `date`. + +Тип: [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). + +**Пример** + +Запрос: + +```sql +select timestamp_add(toDate('2018-01-01'), INTERVAL 3 MONTH); +``` + +Результат: + +```text +┌─plus(toDate('2018-01-01'), toIntervalMonth(3))─┐ +│ 2018-04-01 │ +└────────────────────────────────────────────────┘ +``` + +## timestamp\_sub {#timestamp_sub} + +Вычитает интервал времени из указанной даты или даты со временем. + +**Синтакис** + +``` sql +timestamp_sub(unit, value, date) +``` + +Синонимы: `timeStampSub`, `TIMESTAMP_SUB`. + +**Аргументы** + +- `unit` — единица измерения времени, в которой задан интервал для вычитания. [String](../../sql-reference/data-types/string.md). + Возможные значения: + + - `second` + - `minute` + - `hour` + - `day` + - `week` + - `month` + - `quarter` + - `year` + +- `value` — значение интервала для вычитания. [Int](../../sql-reference/data-types/int-uint.md). +- `date` — дата или дата со временем. [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). + +**Возвращаемое значение** + +Дата или дата со временем, полученная в результате вычитания `value`, выраженного в `unit`, из `date`. + +Тип: [Date](../../sql-reference/data-types/date.md) или [DateTime](../../sql-reference/data-types/datetime.md). + +**Пример** + +Запрос: + +```sql +select timestamp_sub(MONTH, 5, toDateTime('2018-12-18 01:02:03')); +``` + +Результат: + +```text +┌─minus(toDateTime('2018-12-18 01:02:03'), toIntervalMonth(5))─┐ +│ 2018-07-18 01:02:03 │ +└──────────────────────────────────────────────────────────────┘ +``` + +## now {#now} + +Возвращает текущую дату и время. + +**Синтаксис** + +``` sql +now([timezone]) +``` + +**Параметры** + +- `timezone` — [часовой пояс](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) для возвращаемого значения (необязательно). [String](../../sql-reference/data-types/string.md). + +**Возвращаемое значение** + +- Текущие дата и время. + +Тип: [Datetime](../../sql-reference/data-types/datetime.md). + +**Пример** + +Запрос без указания часового пояса: + +``` sql +SELECT now(); +``` + +Результат: + +``` text +┌───────────────now()─┐ +│ 2020-10-17 07:42:09 │ +└─────────────────────┘ +``` + +Запрос с указанием часового пояса: + +``` sql +SELECT now('Europe/Moscow'); +``` + +Результат: + +``` text +┌─now('Europe/Moscow')─┐ +│ 2020-10-17 10:42:23 │ +└──────────────────────┘ +``` + +## today {#today} + +Возвращает текущую дату на момент выполнения запроса. Функция не требует аргументов. +То же самое, что toDate(now()) + +## yesterday {#yesterday} + +Возвращает вчерашнюю дату на момент выполнения запроса. +Делает то же самое, что today() - 1. Функция не требует аргументов. + ## timeSlot {#timeslot} Округляет время до получаса. diff --git a/docs/ru/sql-reference/functions/encoding-functions.md b/docs/ru/sql-reference/functions/encoding-functions.md index 8c3065e5a77..951c6c60e38 100644 --- a/docs/ru/sql-reference/functions/encoding-functions.md +++ b/docs/ru/sql-reference/functions/encoding-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 52 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f" +toc_title: "Функции кодирования" --- # Функции кодирования {#funktsii-kodirovaniia} diff --git a/docs/ru/sql-reference/functions/encryption-functions.md b/docs/ru/sql-reference/functions/encryption-functions.md index 0216a6b2356..a7adb40e631 100644 --- a/docs/ru/sql-reference/functions/encryption-functions.md +++ b/docs/ru/sql-reference/functions/encryption-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 67 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f" +toc_title: "Функции для шифрования" --- # Функции шифрования {#encryption-functions} diff --git a/docs/ru/sql-reference/functions/ext-dict-functions.md b/docs/ru/sql-reference/functions/ext-dict-functions.md index 6054ed141d4..8d018e8e9ac 100644 --- a/docs/ru/sql-reference/functions/ext-dict-functions.md +++ b/docs/ru/sql-reference/functions/ext-dict-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 58 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u0432\u043d\u0435\u0448\u043d\u0438\u043c\u0438\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u044f\u043c\u0438" +toc_title: "Функции для работы с внешними словарями" --- # Функции для работы с внешними словарями {#ext_dict_functions} diff --git a/docs/ru/sql-reference/functions/functions-for-nulls.md b/docs/ru/sql-reference/functions/functions-for-nulls.md index 0db55847631..f0277a59699 100644 --- a/docs/ru/sql-reference/functions/functions-for-nulls.md +++ b/docs/ru/sql-reference/functions/functions-for-nulls.md @@ -1,6 +1,6 @@ --- toc_priority: 63 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u004e\u0075\u006c\u006c\u0061\u0062\u006c\u0065\u002d\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438" +toc_title: "Функции для работы с Nullable-аргументами" --- # Функции для работы с Nullable-аргументами {#funktsii-dlia-raboty-s-nullable-argumentami} diff --git a/docs/ru/sql-reference/functions/geo/coordinates.md b/docs/ru/sql-reference/functions/geo/coordinates.md index 1931a9b932f..09e2d7d01bf 100644 --- a/docs/ru/sql-reference/functions/geo/coordinates.md +++ b/docs/ru/sql-reference/functions/geo/coordinates.md @@ -1,5 +1,5 @@ --- -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u0433\u0435\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u043c\u0438\u0020\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c\u0438" +toc_title: "Функции для работы с географическими координатами" toc_priority: 62 --- diff --git a/docs/ru/sql-reference/functions/geo/geohash.md b/docs/ru/sql-reference/functions/geo/geohash.md index 38c64f11b10..2dd3f83ddf1 100644 --- a/docs/ru/sql-reference/functions/geo/geohash.md +++ b/docs/ru/sql-reference/functions/geo/geohash.md @@ -1,5 +1,5 @@ --- -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439\u0020\u0047\u0065\u006f\u0068\u0061\u0073\u0068" +toc_title: "Функции для работы с системой Geohash" --- # Функции для работы с системой Geohash {#geohash} diff --git a/docs/ru/sql-reference/functions/geo/h3.md b/docs/ru/sql-reference/functions/geo/h3.md index 69d06b5dfa6..7046833f7ec 100644 --- a/docs/ru/sql-reference/functions/geo/h3.md +++ b/docs/ru/sql-reference/functions/geo/h3.md @@ -1,5 +1,5 @@ --- -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u0438\u043d\u0434\u0435\u043a\u0441\u0430\u043c\u0438\u0020\u0048\u0033" +toc_title: "Функции для работы с индексами H3" --- # Функции для работы с индексами H3 {#h3index} diff --git a/docs/ru/sql-reference/functions/geo/index.md b/docs/ru/sql-reference/functions/geo/index.md index cedaafaa31d..6b9a14e4d02 100644 --- a/docs/ru/sql-reference/functions/geo/index.md +++ b/docs/ru/sql-reference/functions/geo/index.md @@ -1,6 +1,6 @@ --- toc_priority: 62 -toc_folder_title: "\u0413\u0435\u043e\u002d\u0434\u0430\u043d\u043d\u044b\u0435" +toc_folder_title: "Гео-данные" toc_title: hidden --- diff --git a/docs/ru/sql-reference/functions/hash-functions.md b/docs/ru/sql-reference/functions/hash-functions.md index f7820889ea9..1742abe5b56 100644 --- a/docs/ru/sql-reference/functions/hash-functions.md +++ b/docs/ru/sql-reference/functions/hash-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 50 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f" +toc_title: "Функции хэширования" --- # Функции хэширования {#funktsii-kheshirovaniia} diff --git a/docs/ru/sql-reference/functions/in-functions.md b/docs/ru/sql-reference/functions/in-functions.md index b732f67303b..7326d087610 100644 --- a/docs/ru/sql-reference/functions/in-functions.md +++ b/docs/ru/sql-reference/functions/in-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 60 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438\u0020\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u0020\u0049\u004e" +toc_title: "Функции для реализации оператора IN" --- # Функции для реализации оператора IN {#funktsii-dlia-realizatsii-operatora-in} diff --git a/docs/ru/sql-reference/functions/index.md b/docs/ru/sql-reference/functions/index.md index 25d3b6de067..ae3879b6c96 100644 --- a/docs/ru/sql-reference/functions/index.md +++ b/docs/ru/sql-reference/functions/index.md @@ -1,7 +1,7 @@ --- -toc_folder_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438" +toc_folder_title: "Функции" toc_priority: 32 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435" +toc_title: "Введение" --- # Функции {#funktsii} diff --git a/docs/ru/sql-reference/functions/introspection.md b/docs/ru/sql-reference/functions/introspection.md index 00dd660bc16..4cd7e5d273b 100644 --- a/docs/ru/sql-reference/functions/introspection.md +++ b/docs/ru/sql-reference/functions/introspection.md @@ -1,6 +1,6 @@ --- toc_priority: 65 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0438\u043d\u0442\u0440\u043e\u0441\u043f\u0435\u043a\u0446\u0438\u0438" +toc_title: "Функции интроспекции" --- # Функции интроспекции {#introspection-functions} diff --git a/docs/ru/sql-reference/functions/ip-address-functions.md b/docs/ru/sql-reference/functions/ip-address-functions.md index bc48419473d..a2a08b1938e 100644 --- a/docs/ru/sql-reference/functions/ip-address-functions.md +++ b/docs/ru/sql-reference/functions/ip-address-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 55 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u0049\u0050\u002d\u0430\u0434\u0440\u0435\u0441\u0430\u043c\u0438" +toc_title: "Функции для работы с IP-адресами" --- # Функции для работы с IP-адресами {#funktsii-dlia-raboty-s-ip-adresami} diff --git a/docs/ru/sql-reference/functions/logical-functions.md b/docs/ru/sql-reference/functions/logical-functions.md index 9b1ee6a66a7..2d71c60a509 100644 --- a/docs/ru/sql-reference/functions/logical-functions.md +++ b/docs/ru/sql-reference/functions/logical-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 37 -toc_title: "\u041b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435\u0020\u0444\u0443\u043d\u043a\u0446\u0438\u0438" +toc_title: "Логические функции" --- # Логические функции {#logicheskie-funktsii} diff --git a/docs/ru/sql-reference/functions/machine-learning-functions.md b/docs/ru/sql-reference/functions/machine-learning-functions.md index 2ffdfd05613..decbff56646 100644 --- a/docs/ru/sql-reference/functions/machine-learning-functions.md +++ b/docs/ru/sql-reference/functions/machine-learning-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 64 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e\u0020\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f" +toc_title: "Функции машинного обучения" --- # Функции машинного обучения {#funktsii-mashinnogo-obucheniia} diff --git a/docs/ru/sql-reference/functions/math-functions.md b/docs/ru/sql-reference/functions/math-functions.md index 2e57aca6a0a..a5ba01f6282 100644 --- a/docs/ru/sql-reference/functions/math-functions.md +++ b/docs/ru/sql-reference/functions/math-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 44 -toc_title: "\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435\u0020\u0444\u0443\u043d\u043a\u0446\u0438\u0438" +toc_title: "Математические функции" --- # Математические функции {#matematicheskie-funktsii} @@ -405,4 +405,67 @@ SELECT log1p(0); - [log(x)](../../sql-reference/functions/math-functions.md#logx) +## sign(x) {#signx} + +Возвращает знак действительного числа. + +**Синтаксис** + +``` sql +sign(x) +``` + +**Аргумент** + +- `x` — Значения от `-∞` до `+∞`. Любой числовой тип, поддерживаемый ClickHouse. + +**Возвращаемое значение** + +- -1 если `x < 0` +- 0 если `x = 0` +- 1 если `x > 0` + +**Примеры** + +Результат sign() для нуля: + +``` sql +SELECT sign(0); +``` +Результат: + +``` text +┌─sign(0)─┐ +│ 0 │ +└─────────┘ +``` + +Результат sign() для положительного аргумента: + +``` sql +SELECT sign(1); +``` + +Результат: + +``` text +┌─sign(1)─┐ +│ 1 │ +└─────────┘ +``` + +Результат sign() для отрицательного аргумента: + +``` sql +SELECT sign(-1); +``` + +Результат: + +``` text +┌─sign(-1)─┐ +│ -1 │ +└──────────┘ +``` + [Оригинальная статья](https://clickhouse.tech/docs/ru/query_language/functions/math_functions/) diff --git a/docs/ru/sql-reference/functions/other-functions.md b/docs/ru/sql-reference/functions/other-functions.md index 19494c0aa10..595d2458ca9 100644 --- a/docs/ru/sql-reference/functions/other-functions.md +++ b/docs/ru/sql-reference/functions/other-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 66 -toc_title: "\u041f\u0440\u043e\u0447\u0438\u0435\u0020\u0444\u0443\u043d\u043a\u0446\u0438\u0438" +toc_title: "Прочие функции" --- # Прочие функции {#other-functions} diff --git a/docs/ru/sql-reference/functions/random-functions.md b/docs/ru/sql-reference/functions/random-functions.md index f3889504fa6..a09f5159309 100644 --- a/docs/ru/sql-reference/functions/random-functions.md +++ b/docs/ru/sql-reference/functions/random-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 51 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438\u0020\u043f\u0441\u0435\u0432\u0434\u043e\u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445\u0020\u0447\u0438\u0441\u0435\u043b" +toc_title: "Функции генерации псевдослучайных чисел" --- # Функции генерации псевдослучайных чисел {#functions-for-generating-pseudo-random-numbers} diff --git a/docs/ru/sql-reference/functions/rounding-functions.md b/docs/ru/sql-reference/functions/rounding-functions.md index 78033160396..704e7f5dd52 100644 --- a/docs/ru/sql-reference/functions/rounding-functions.md +++ b/docs/ru/sql-reference/functions/rounding-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 45 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u044f" +toc_title: "Функции округления" --- # Функции округления {#funktsii-okrugleniia} diff --git a/docs/ru/sql-reference/functions/splitting-merging-functions.md b/docs/ru/sql-reference/functions/splitting-merging-functions.md index d451eabc407..cacce5f4ba2 100644 --- a/docs/ru/sql-reference/functions/splitting-merging-functions.md +++ b/docs/ru/sql-reference/functions/splitting-merging-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 47 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u044f\u0020\u0438\u0020\u0441\u043b\u0438\u044f\u043d\u0438\u044f\u0020\u0441\u0442\u0440\u043e\u043a\u0020\u0438\u0020\u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432" +toc_title: "Функции разбиения и слияния строк и массивов" --- # Функции разбиения и слияния строк и массивов {#funktsii-razbieniia-i-sliianiia-strok-i-massivov} diff --git a/docs/ru/sql-reference/functions/string-functions.md b/docs/ru/sql-reference/functions/string-functions.md index 1159a1f5823..65a1cd63563 100644 --- a/docs/ru/sql-reference/functions/string-functions.md +++ b/docs/ru/sql-reference/functions/string-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 40 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u043e\u0020\u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438" +toc_title: "Функции для работы со строками" --- # Функции для работы со строками {#funktsii-dlia-raboty-so-strokami} diff --git a/docs/ru/sql-reference/functions/string-replace-functions.md b/docs/ru/sql-reference/functions/string-replace-functions.md index f334d6804f9..f00a06d1560 100644 --- a/docs/ru/sql-reference/functions/string-replace-functions.md +++ b/docs/ru/sql-reference/functions/string-replace-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 42 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u043f\u043e\u0438\u0441\u043a\u0430\u0020\u0438\u0020\u0437\u0430\u043c\u0435\u043d\u044b\u0020\u0432\u0020\u0441\u0442\u0440\u043e\u043a\u0430\u0445" +toc_title: "Функции поиска и замены в строках" --- # Функции поиска и замены в строках {#funktsii-poiska-i-zameny-v-strokakh} diff --git a/docs/ru/sql-reference/functions/string-search-functions.md b/docs/ru/sql-reference/functions/string-search-functions.md index b7193da6f33..95ac922a4a8 100644 --- a/docs/ru/sql-reference/functions/string-search-functions.md +++ b/docs/ru/sql-reference/functions/string-search-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 41 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u043f\u043e\u0438\u0441\u043a\u0430\u0020\u0432\u0020\u0441\u0442\u0440\u043e\u043a\u0430\u0445" +toc_title: "Функции поиска в строках" --- # Функции поиска в строках {#funktsii-poiska-v-strokakh} diff --git a/docs/ru/sql-reference/functions/type-conversion-functions.md b/docs/ru/sql-reference/functions/type-conversion-functions.md index 53e7bc1300e..f312f9f5847 100644 --- a/docs/ru/sql-reference/functions/type-conversion-functions.md +++ b/docs/ru/sql-reference/functions/type-conversion-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 38 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f\u0020\u0442\u0438\u043f\u043e\u0432" +toc_title: "Функции преобразования типов" --- # Функции преобразования типов {#funktsii-preobrazovaniia-tipov} diff --git a/docs/ru/sql-reference/functions/url-functions.md b/docs/ru/sql-reference/functions/url-functions.md index 7541e16bed4..83f7fd32f6c 100644 --- a/docs/ru/sql-reference/functions/url-functions.md +++ b/docs/ru/sql-reference/functions/url-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 54 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u0055\u0052\u004c" +toc_title: "Функции для работы с URL" --- # Функции для работы с URL {#funktsii-dlia-raboty-s-url} diff --git a/docs/ru/sql-reference/functions/uuid-functions.md b/docs/ru/sql-reference/functions/uuid-functions.md index 6082fcaa712..f0017adbc8b 100644 --- a/docs/ru/sql-reference/functions/uuid-functions.md +++ b/docs/ru/sql-reference/functions/uuid-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 53 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u0055\u0055\u0049\u0044" +toc_title: "Функции для работы с UUID" --- # Функции для работы с UUID {#funktsii-dlia-raboty-s-uuid} diff --git a/docs/ru/sql-reference/functions/ym-dict-functions.md b/docs/ru/sql-reference/functions/ym-dict-functions.md index c3b04e4ab66..f6d02e553a0 100644 --- a/docs/ru/sql-reference/functions/ym-dict-functions.md +++ b/docs/ru/sql-reference/functions/ym-dict-functions.md @@ -1,6 +1,6 @@ --- toc_priority: 59 -toc_title: "\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u0020\u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u043e\u0020\u0441\u043b\u043e\u0432\u0430\u0440\u044f\u043c\u0438\u0020\u042f\u043d\u0434\u0435\u043a\u0441\u002e\u041c\u0435\u0442\u0440\u0438\u043a\u0438" +toc_title: "Функции для работы со словарями Яндекс.Метрики" --- # Функции для работы со словарями Яндекс.Метрики {#ym-dict-functions} diff --git a/docs/ru/sql-reference/index.md b/docs/ru/sql-reference/index.md index f59232ee047..7aea530c7ee 100644 --- a/docs/ru/sql-reference/index.md +++ b/docs/ru/sql-reference/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0421\u043F\u0440\u0430\u0432\u043A\u0430 \u043F\u043E SQL" +toc_folder_title: "Справка по SQL" toc_hidden: true toc_priority: 28 toc_title: hidden diff --git a/docs/ru/sql-reference/operators/index.md b/docs/ru/sql-reference/operators/index.md index 1eddfc4dcaf..691c398ce4c 100644 --- a/docs/ru/sql-reference/operators/index.md +++ b/docs/ru/sql-reference/operators/index.md @@ -1,6 +1,6 @@ --- toc_priority: 38 -toc_title: "\u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b" +toc_title: "Операторы" --- # Операторы {#operatory} diff --git a/docs/ru/sql-reference/statements/alter/column.md b/docs/ru/sql-reference/statements/alter/column.md index 850b415e268..63a756d2625 100644 --- a/docs/ru/sql-reference/statements/alter/column.md +++ b/docs/ru/sql-reference/statements/alter/column.md @@ -1,6 +1,6 @@ --- toc_priority: 37 -toc_title: "\u041c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438\u0020\u0441\u043e\u0020\u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c\u0438" +toc_title: "Манипуляции со столбцами" --- # Манипуляции со столбцами {#manipuliatsii-so-stolbtsami} diff --git a/docs/ru/sql-reference/statements/alter/constraint.md b/docs/ru/sql-reference/statements/alter/constraint.md index e26db208493..13396f33621 100644 --- a/docs/ru/sql-reference/statements/alter/constraint.md +++ b/docs/ru/sql-reference/statements/alter/constraint.md @@ -1,6 +1,6 @@ --- toc_priority: 43 -toc_title: "\u041c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438\u0020\u0441\u0020\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u043c\u0438" +toc_title: "Манипуляции с ограничениями" --- # Манипуляции с ограничениями (constraints) {#manipuliatsii-s-ogranicheniiami-constraints} diff --git a/docs/ru/sql-reference/statements/alter/index/index.md b/docs/ru/sql-reference/statements/alter/index/index.md index 2cadbbe065e..a42bccd7b47 100644 --- a/docs/ru/sql-reference/statements/alter/index/index.md +++ b/docs/ru/sql-reference/statements/alter/index/index.md @@ -1,7 +1,7 @@ --- toc_hidden_folder: true toc_priority: 42 -toc_title: "\u041c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438\u0020\u0441\u0020\u0438\u043d\u0434\u0435\u043a\u0441\u0430\u043c\u0438" +toc_title: "Манипуляции с индексами" --- # Манипуляции с индексами {#manipuliatsii-s-indeksami} diff --git a/docs/ru/sql-reference/statements/create/database.md b/docs/ru/sql-reference/statements/create/database.md index e6c561f8e0b..0e880517134 100644 --- a/docs/ru/sql-reference/statements/create/database.md +++ b/docs/ru/sql-reference/statements/create/database.md @@ -1,6 +1,6 @@ --- toc_priority: 35 -toc_title: "\u0411\u0430\u0437\u0430\u0020\u0434\u0430\u043d\u043d\u044b\u0445" +toc_title: "База данных" --- # CREATE DATABASE {#query-language-create-database} diff --git a/docs/ru/sql-reference/statements/create/dictionary.md b/docs/ru/sql-reference/statements/create/dictionary.md index 3134a89483b..dba2aa61ca1 100644 --- a/docs/ru/sql-reference/statements/create/dictionary.md +++ b/docs/ru/sql-reference/statements/create/dictionary.md @@ -1,6 +1,6 @@ --- toc_priority: 38 -toc_title: "\u0421\u043b\u043e\u0432\u0430\u0440\u044c" +toc_title: "Словарь" --- # CREATE DICTIONARY {#create-dictionary-query} diff --git a/docs/ru/sql-reference/statements/create/index.md b/docs/ru/sql-reference/statements/create/index.md index 28ddce2afe3..70961e4f404 100644 --- a/docs/ru/sql-reference/statements/create/index.md +++ b/docs/ru/sql-reference/statements/create/index.md @@ -1,7 +1,7 @@ --- toc_folder_title: CREATE toc_priority: 34 -toc_title: "\u041e\u0431\u0437\u043e\u0440" +toc_title: "Обзор" --- # Запросы CREATE {#create-queries} diff --git a/docs/ru/sql-reference/statements/create/quota.md b/docs/ru/sql-reference/statements/create/quota.md index 65762071ea2..f5ac0df010e 100644 --- a/docs/ru/sql-reference/statements/create/quota.md +++ b/docs/ru/sql-reference/statements/create/quota.md @@ -1,6 +1,6 @@ --- toc_priority: 42 -toc_title: "\u041a\u0432\u043e\u0442\u0430" +toc_title: "Квота" --- # CREATE QUOTA {#create-quota-statement} diff --git a/docs/ru/sql-reference/statements/create/role.md b/docs/ru/sql-reference/statements/create/role.md index 521117c0e89..8592f263156 100644 --- a/docs/ru/sql-reference/statements/create/role.md +++ b/docs/ru/sql-reference/statements/create/role.md @@ -1,6 +1,6 @@ --- toc_priority: 40 -toc_title: "\u0420\u043e\u043b\u044c" +toc_title: "Роль" --- # CREATE ROLE {#create-role-statement} diff --git a/docs/ru/sql-reference/statements/create/row-policy.md b/docs/ru/sql-reference/statements/create/row-policy.md index e79a19d4cbe..75f6fdfd2e1 100644 --- a/docs/ru/sql-reference/statements/create/row-policy.md +++ b/docs/ru/sql-reference/statements/create/row-policy.md @@ -1,6 +1,6 @@ --- toc_priority: 41 -toc_title: "\u041f\u043e\u043b\u0438\u0442\u0438\u043a\u0430\u0020\u0434\u043e\u0441\u0442\u0443\u043f\u0430" +toc_title: "Политика доступа" --- # CREATE ROW POLICY {#create-row-policy-statement} diff --git a/docs/ru/sql-reference/statements/create/settings-profile.md b/docs/ru/sql-reference/statements/create/settings-profile.md index 643f9d92eac..5838ddc9153 100644 --- a/docs/ru/sql-reference/statements/create/settings-profile.md +++ b/docs/ru/sql-reference/statements/create/settings-profile.md @@ -1,6 +1,6 @@ --- toc_priority: 43 -toc_title: "\u041f\u0440\u043e\u0444\u0438\u043b\u044c\u0020\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a" +toc_title: "Профиль настроек" --- # CREATE SETTINGS PROFILE {#create-settings-profile-statement} diff --git a/docs/ru/sql-reference/statements/create/table.md b/docs/ru/sql-reference/statements/create/table.md index 9f582042a36..8e2c471e548 100644 --- a/docs/ru/sql-reference/statements/create/table.md +++ b/docs/ru/sql-reference/statements/create/table.md @@ -1,6 +1,6 @@ --- toc_priority: 36 -toc_title: "\u0422\u0430\u0431\u043b\u0438\u0446\u0430" +toc_title: "Таблица" --- # CREATE TABLE {#create-table-query} diff --git a/docs/ru/sql-reference/statements/create/user.md b/docs/ru/sql-reference/statements/create/user.md index bcc9768eb43..ac9547691e6 100644 --- a/docs/ru/sql-reference/statements/create/user.md +++ b/docs/ru/sql-reference/statements/create/user.md @@ -1,6 +1,6 @@ --- toc_priority: 39 -toc_title: "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c" +toc_title: "Пользователь" --- # CREATE USER {#create-user-statement} diff --git a/docs/ru/sql-reference/statements/create/view.md b/docs/ru/sql-reference/statements/create/view.md index f4b91b5ae17..da021059a8e 100644 --- a/docs/ru/sql-reference/statements/create/view.md +++ b/docs/ru/sql-reference/statements/create/view.md @@ -1,6 +1,6 @@ --- toc_priority: 37 -toc_title: "\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435" +toc_title: "Представление" --- # CREATE VIEW {#create-view} diff --git a/docs/ru/sql-reference/statements/index.md b/docs/ru/sql-reference/statements/index.md index c7862015e64..5e72aa7cca0 100644 --- a/docs/ru/sql-reference/statements/index.md +++ b/docs/ru/sql-reference/statements/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0412\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u044F" +toc_folder_title: "Выражения" toc_priority: 31 --- diff --git a/docs/ru/sql-reference/statements/select/index.md b/docs/ru/sql-reference/statements/select/index.md index b0b6e80d7be..a548a988a89 100644 --- a/docs/ru/sql-reference/statements/select/index.md +++ b/docs/ru/sql-reference/statements/select/index.md @@ -1,8 +1,8 @@ --- -title: "\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0020\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432\u0020\u0053\u0045\u004c\u0045\u0043\u0054" +title: "Синтаксис запросов SELECT" toc_folder_title: SELECT toc_priority: 32 -toc_title: "\u041e\u0431\u0437\u043e\u0440" +toc_title: "Обзор" --- # Синтаксис запросов SELECT {#select-queries-syntax} diff --git a/docs/ru/sql-reference/statements/show.md b/docs/ru/sql-reference/statements/show.md index 56528f28c65..b214f0072e3 100644 --- a/docs/ru/sql-reference/statements/show.md +++ b/docs/ru/sql-reference/statements/show.md @@ -362,4 +362,69 @@ SHOW [CURRENT] QUOTA SHOW ACCESS ``` -[Оригинальная статья](https://clickhouse.tech/docs/ru/query_language/show/) +## SHOW SETTINGS {#show-settings} + +Возвращает список системных настроек и их значений. Использует данные из таблицы [system.settings](../../operations/system-tables/settings.md). + +**Синтаксис** + +```sql +SHOW [CHANGED] SETTINGS LIKE|ILIKE +``` + +**Секции** + +При использовании `LIKE|ILIKE` можно задавать шаблон для имени настройки. Этот шаблон может содержать символы подстановки, такие как `%` или `_`. При использовании `LIKE` шаблон чувствителен к регистру, а при использовании `ILIKE` — не чувствителен. + +Если используется `CHANGED`, запрос вернет только те настройки, значения которых были изменены, т.е. отличны от значений по умолчанию. + +**Примеры** + +Запрос с использованием `LIKE`: + +```sql +SHOW SETTINGS LIKE 'send_timeout'; +``` +Результат: + +```text +┌─name─────────┬─type────┬─value─┐ +│ send_timeout │ Seconds │ 300 │ +└──────────────┴─────────┴───────┘ +``` + +Запрос с использованием `ILIKE`: + +```sql +SHOW SETTINGS ILIKE '%CONNECT_timeout%' +``` + +Результат: + +```text +┌─name────────────────────────────────────┬─type─────────┬─value─┐ +│ connect_timeout │ Seconds │ 10 │ +│ connect_timeout_with_failover_ms │ Milliseconds │ 50 │ +│ connect_timeout_with_failover_secure_ms │ Milliseconds │ 100 │ +└─────────────────────────────────────────┴──────────────┴───────┘ +``` + +Запрос с использованием `CHANGED`: + +```sql +SHOW CHANGED SETTINGS ILIKE '%MEMORY%' +``` + +Результат: + +```text +┌─name─────────────┬─type───┬─value───────┐ +│ max_memory_usage │ UInt64 │ 10000000000 │ +└──────────────────┴────────┴─────────────┘ +``` + +**См. также** + +- Таблица [system.settings](../../operations/system-tables/settings.md) + +[Оригинальная статья](https://clickhouse.tech/docs/ru/sql-reference/statements/show/) diff --git a/docs/ru/sql-reference/syntax.md b/docs/ru/sql-reference/syntax.md index ca73d3a137e..d8eaa4f1731 100644 --- a/docs/ru/sql-reference/syntax.md +++ b/docs/ru/sql-reference/syntax.md @@ -1,6 +1,6 @@ --- toc_priority: 31 -toc_title: "\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441" +toc_title: "Синтаксис" --- # Синтаксис {#sintaksis} diff --git a/docs/ru/sql-reference/table-functions/index.md b/docs/ru/sql-reference/table-functions/index.md index 83225d54e60..da04b2c7a10 100644 --- a/docs/ru/sql-reference/table-functions/index.md +++ b/docs/ru/sql-reference/table-functions/index.md @@ -1,8 +1,7 @@ --- -toc_folder_title: "\u0422\u0430\u0431\u043B\u0438\u0447\u043D\u044B\u0435 \u0444\u0443\ - \u043D\u043A\u0446\u0438\u0438" +toc_folder_title: "Табличные функции" toc_priority: 34 -toc_title: "\u0412\u0432\u0435\u0434\u0435\u043D\u0438\u0435" +toc_title: "Введение" --- # Табличные функции {#table-functions} diff --git a/docs/ru/whats-new/index.md b/docs/ru/whats-new/index.md index 256f6fde14e..d8a26423813 100644 --- a/docs/ru/whats-new/index.md +++ b/docs/ru/whats-new/index.md @@ -1,5 +1,5 @@ --- -toc_folder_title: "\u0427\u0442\u043E \u043D\u043E\u0432\u043E\u0433\u043E?" +toc_folder_title: "Что нового?" toc_priority: 82 --- diff --git a/docs/zh/commercial/cloud.md b/docs/zh/commercial/cloud.md index 9cca8776d14..c74ffa93e9a 100644 --- a/docs/zh/commercial/cloud.md +++ b/docs/zh/commercial/cloud.md @@ -29,6 +29,18 @@ toc_title: 云 - 跨可用区扩展以实现性能和高可用性 - 内置监控和SQL查询编辑器 +## 阿里云 {#alibaba-cloud} + +阿里云的 ClickHouse 托管服务 [中国站](https://www.aliyun.com/product/clickhouse) (国际站于2021年5月初开放) 提供以下主要功能: + +- 基于阿里飞天分布式系统的高可靠云盘存储引擎 +- 按需扩容,无需手动进行数据搬迁 +- 支持单节点、单副本、多节点、多副本多种架构,支持冷热数据分层 +- 支持访问白名单和一键恢复,多层网络安全防护,云盘加密 +- 与云上日志系统、数据库、数据应用工具无缝集成 +- 内置监控和数据库管理平台 +- 专业的数据库专家技术支持和服务 + ## 腾讯云 {#tencent-cloud} [腾讯云的 ClickHouse 托管服务](https://cloud.tencent.com/product/cdwch)提供以下主要功能: diff --git a/programs/client/Client.cpp b/programs/client/Client.cpp index 3c27908741c..da7c729a737 100644 --- a/programs/client/Client.cpp +++ b/programs/client/Client.cpp @@ -2472,7 +2472,7 @@ public: /** If "--password [value]" is used but the value is omitted, the bad argument exception will be thrown. * implicit_value is used to avoid this exception (to allow user to type just "--password") * Since currently boost provides no way to check if a value has been set implicitly for an option, - * the "\n" is used to distinguish this case because there is hardly a chance an user would use "\n" + * the "\n" is used to distinguish this case because there is hardly a chance a user would use "\n" * as the password. */ ("password", po::value()->implicit_value("\n", ""), "password") diff --git a/programs/format/Format.cpp b/programs/format/Format.cpp index ab974169853..ba3d6e8557b 100644 --- a/programs/format/Format.cpp +++ b/programs/format/Format.cpp @@ -1,6 +1,6 @@ +#include #include #include -#include #include #include @@ -50,6 +50,7 @@ int mainEntryClickHouseFormat(int argc, char ** argv) ("quiet,q", "just check syntax, no output on success") ("multiquery,n", "allow multiple queries in the same file") ("obfuscate", "obfuscate instead of formatting") + ("backslash", "add a backslash at the end of each line of the formatted query") ("seed", po::value(), "seed (arbitrary string) that determines the result of obfuscation") ; @@ -70,6 +71,7 @@ int mainEntryClickHouseFormat(int argc, char ** argv) bool quiet = options.count("quiet"); bool multiple = options.count("multiquery"); bool obfuscate = options.count("obfuscate"); + bool backslash = options.count("backslash"); if (quiet && (hilite || oneline || obfuscate)) { @@ -148,12 +150,39 @@ int mainEntryClickHouseFormat(int argc, char ** argv) } if (!quiet) { - WriteBufferFromOStream res_buf(std::cout, 4096); - formatAST(*res, res_buf, hilite, oneline); - res_buf.next(); - if (multiple) - std::cout << "\n;\n"; - std::cout << std::endl; + if (!backslash) + { + WriteBufferFromOStream res_buf(std::cout, 4096); + formatAST(*res, res_buf, hilite, oneline); + res_buf.next(); + if (multiple) + std::cout << "\n;\n"; + std::cout << std::endl; + } + /// add additional '\' at the end of each line; + else + { + WriteBufferFromOwnString str_buf; + formatAST(*res, str_buf, hilite, oneline); + + auto res_string = str_buf.str(); + WriteBufferFromOStream res_cout(std::cout, 4096); + + const char * s_pos= res_string.data(); + const char * s_end = s_pos + res_string.size(); + + while (s_pos != s_end) + { + if (*s_pos == '\n') + res_cout.write(" \\", 2); + res_cout.write(*s_pos++); + } + + res_cout.next(); + if (multiple) + std::cout << " \\\n;\n"; + std::cout << std::endl; + } } do diff --git a/programs/local/LocalServer.cpp b/programs/local/LocalServer.cpp index 5a8d35e204d..7c6b60fbf8e 100644 --- a/programs/local/LocalServer.cpp +++ b/programs/local/LocalServer.cpp @@ -240,7 +240,7 @@ try /// Skip networking - /// Sets external authenticators config (LDAP). + /// Sets external authenticators config (LDAP, Kerberos). global_context->setExternalAuthenticatorsConfig(config()); setupUsers(); diff --git a/programs/server/config.xml b/programs/server/config.xml index b72cf53ca03..4220ecbcacd 100644 --- a/programs/server/config.xml +++ b/programs/server/config.xml @@ -362,6 +362,27 @@ --> + + @@ -578,7 +599,7 @@ - + - + + + + true + + clickhouse1 + 9440 + 1 + + + clickhouse2 + 9440 + 1 + + + clickhouse3 + 9440 + 1 + + + + + + + clickhouse1 + 9000 + + + + + clickhouse2 + 9000 + + + + + clickhouse3 + 9000 + + + + + + + clickhouse1 + 9440 + 1 + + + + + clickhouse2 + 9440 + 1 + + + + + clickhouse3 + 9440 + 1 + + + + + diff --git a/tests/testflows/kerberos/configs/clickhouse/config.d/ssl.xml b/tests/testflows/kerberos/configs/clickhouse/config.d/ssl.xml new file mode 100644 index 00000000000..ca65ffd5e04 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse/config.d/ssl.xml @@ -0,0 +1,17 @@ + + + + /etc/clickhouse-server/ssl/server.crt + /etc/clickhouse-server/ssl/server.key + none + true + + + true + none + + AcceptCertificateHandler + + + + diff --git a/tests/testflows/kerberos/configs/clickhouse/config.d/storage.xml b/tests/testflows/kerberos/configs/clickhouse/config.d/storage.xml new file mode 100644 index 00000000000..618fd6b6d24 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse/config.d/storage.xml @@ -0,0 +1,20 @@ + + + + + + 1024 + + + + + + + default + + + + + + + diff --git a/tests/testflows/kerberos/configs/clickhouse/config.d/zookeeper.xml b/tests/testflows/kerberos/configs/clickhouse/config.d/zookeeper.xml new file mode 100644 index 00000000000..96270e7b645 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse/config.d/zookeeper.xml @@ -0,0 +1,10 @@ + + + + + zookeeper + 2181 + + 15000 + + diff --git a/tests/testflows/kerberos/configs/clickhouse/config.xml b/tests/testflows/kerberos/configs/clickhouse/config.xml new file mode 100644 index 00000000000..a0133238f25 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse/config.xml @@ -0,0 +1,440 @@ + + + + + + trace + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + 1000M + 10 + + + + 8123 + 9000 + + + + + + + + + /etc/clickhouse-server/server.crt + /etc/clickhouse-server/server.key + + /etc/clickhouse-server/dhparam.pem + none + true + true + sslv2,sslv3 + true + + + + true + true + sslv2,sslv3 + true + + + + RejectCertificateHandler + + + + + + + + + 9009 + + + + + + + + 0.0.0.0 + + + + + + + + + + + + 4096 + 3 + + + 100 + + + + + + 8589934592 + + + 5368709120 + + + + /var/lib/clickhouse/ + + + /var/lib/clickhouse/tmp/ + + + /var/lib/clickhouse/user_files/ + + + + + + users.xml + + + + /var/lib/clickhouse/access/ + + + + + default + + + + + + default + + + + + + + + + false + + + + + + + + localhost + 9000 + + + + + + + localhost + 9000 + + + + + localhost + 9000 + + + + + + + localhost + 9440 + 1 + + + + + + + localhost + 9000 + + + + + localhost + 1 + + + + + + + + + + + + + + + + + 3600 + + + + 3600 + + + 60 + + + + + + + + + + system + query_log
+ + toYYYYMM(event_date) + + 7500 +
+ + + + system + trace_log
+ + toYYYYMM(event_date) + 7500 +
+ + + + system + query_thread_log
+ toYYYYMM(event_date) + 7500 +
+ + + + + + + + + + + + + + + + *_dictionary.xml + + + + + + + + + + /clickhouse/task_queue/ddl + + + + + + + + + + + + + + + + click_cost + any + + 0 + 3600 + + + 86400 + 60 + + + + max + + 0 + 60 + + + 3600 + 300 + + + 86400 + 3600 + + + + + + /var/lib/clickhouse/format_schemas/ + + + +
diff --git a/tests/testflows/kerberos/configs/clickhouse/ssl/dhparam.pem b/tests/testflows/kerberos/configs/clickhouse/ssl/dhparam.pem new file mode 100644 index 00000000000..2e6cee0798d --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse/ssl/dhparam.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAua92DDli13gJ+//ZXyGaggjIuidqB0crXfhUlsrBk9BV1hH3i7fR +XGP9rUdk2ubnB3k2ejBStL5oBrkHm9SzUFSQHqfDjLZjKoUpOEmuDc4cHvX1XTR5 +Pr1vf5cd0yEncJWG5W4zyUB8k++SUdL2qaeslSs+f491HBLDYn/h8zCgRbBvxhxb +9qeho1xcbnWeqkN6Kc9bgGozA16P9NLuuLttNnOblkH+lMBf42BSne/TWt3AlGZf +slKmmZcySUhF8aKfJnLKbkBCFqOtFRh8zBA9a7g+BT/lSANATCDPaAk1YVih2EKb +dpc3briTDbRsiqg2JKMI7+VdULY9bh3EawIBAg== +-----END DH PARAMETERS----- diff --git a/tests/testflows/kerberos/configs/clickhouse/ssl/server.crt b/tests/testflows/kerberos/configs/clickhouse/ssl/server.crt new file mode 100644 index 00000000000..7ade2d96273 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse/ssl/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIJANjx1QSR77HBMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV +BAMMCWxvY2FsaG9zdDAgFw0xODA3MzAxODE2MDhaGA8yMjkyMDUxNDE4MTYwOFow +FDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAs9uSo6lJG8o8pw0fbVGVu0tPOljSWcVSXH9uiJBwlZLQnhN4SFSFohfI +4K8U1tBDTnxPLUo/V1K9yzoLiRDGMkwVj6+4+hE2udS2ePTQv5oaMeJ9wrs+5c9T +4pOtlq3pLAdm04ZMB1nbrEysceVudHRkQbGHzHp6VG29Fw7Ga6YpqyHQihRmEkTU +7UCYNA+Vk7aDPdMS/khweyTpXYZimaK9f0ECU3/VOeG3fH6Sp2X6FN4tUj/aFXEj +sRmU5G2TlYiSIUMF2JPdhSihfk1hJVALrHPTU38SOL+GyyBRWdNcrIwVwbpvsvPg +pryMSNxnpr0AK0dFhjwnupIv5hJIOQIDAQABo1AwTjAdBgNVHQ4EFgQUjPLb3uYC +kcamyZHK4/EV8jAP0wQwHwYDVR0jBBgwFoAUjPLb3uYCkcamyZHK4/EV8jAP0wQw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAM/ocuDvfPus/KpMVD51j +4IdlU8R0vmnYLQ+ygzOAo7+hUWP5j0yvq4ILWNmQX6HNvUggCgFv9bjwDFhb/5Vr +85ieWfTd9+LTjrOzTw4avdGwpX9G+6jJJSSq15tw5ElOIFb/qNA9O4dBiu8vn03C +L/zRSXrARhSqTW5w/tZkUcSTT+M5h28+Lgn9ysx4Ff5vi44LJ1NnrbJbEAIYsAAD ++UA+4MBFKx1r6hHINULev8+lCfkpwIaeS8RL+op4fr6kQPxnULw8wT8gkuc8I4+L +P9gg/xDHB44T3ADGZ5Ib6O0DJaNiToO6rnoaaxs0KkotbvDWvRoxEytSbXKoYjYp +0g== +-----END CERTIFICATE----- diff --git a/tests/testflows/kerberos/configs/clickhouse/ssl/server.key b/tests/testflows/kerberos/configs/clickhouse/ssl/server.key new file mode 100644 index 00000000000..f0fb61ac443 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse/ssl/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCz25KjqUkbyjyn +DR9tUZW7S086WNJZxVJcf26IkHCVktCeE3hIVIWiF8jgrxTW0ENOfE8tSj9XUr3L +OguJEMYyTBWPr7j6ETa51LZ49NC/mhox4n3Cuz7lz1Pik62WreksB2bThkwHWdus +TKxx5W50dGRBsYfMenpUbb0XDsZrpimrIdCKFGYSRNTtQJg0D5WTtoM90xL+SHB7 +JOldhmKZor1/QQJTf9U54bd8fpKnZfoU3i1SP9oVcSOxGZTkbZOViJIhQwXYk92F +KKF+TWElUAusc9NTfxI4v4bLIFFZ01ysjBXBum+y8+CmvIxI3GemvQArR0WGPCe6 +ki/mEkg5AgMBAAECggEATrbIBIxwDJOD2/BoUqWkDCY3dGevF8697vFuZKIiQ7PP +TX9j4vPq0DfsmDjHvAPFkTHiTQXzlroFik3LAp+uvhCCVzImmHq0IrwvZ9xtB43f +7Pkc5P6h1l3Ybo8HJ6zRIY3TuLtLxuPSuiOMTQSGRL0zq3SQ5DKuGwkz+kVjHXUN +MR2TECFwMHKQ5VLrC+7PMpsJYyOMlDAWhRfUalxC55xOXTpaN8TxNnwQ8K2ISVY5 +212Jz/a4hn4LdwxSz3Tiu95PN072K87HLWx3EdT6vW4Ge5P/A3y+smIuNAlanMnu +plHBRtpATLiTxZt/n6npyrfQVbYjSH7KWhB8hBHtaQKBgQDh9Cq1c/KtqDtE0Ccr +/r9tZNTUwBE6VP+3OJeKdEdtsfuxjOCkS1oAjgBJiSDOiWPh1DdoDeVZjPKq6pIu +Mq12OE3Doa8znfCXGbkSzEKOb2unKZMJxzrz99kXt40W5DtrqKPNb24CNqTiY8Aa +CjtcX+3weat82VRXvph6U8ltMwKBgQDLxjiQQzNoY7qvg7CwJCjf9qq8jmLK766g +1FHXopqS+dTxDLM8eJSRrpmxGWJvNeNc1uPhsKsKgotqAMdBUQTf7rSTbt4MyoH5 +bUcRLtr+0QTK9hDWMOOvleqNXha68vATkohWYfCueNsC60qD44o8RZAS6UNy3ENq +cM1cxqe84wKBgQDKkHutWnooJtajlTxY27O/nZKT/HA1bDgniMuKaz4R4Gr1PIez +on3YW3V0d0P7BP6PWRIm7bY79vkiMtLEKdiKUGWeyZdo3eHvhDb/3DCawtau8L2K +GZsHVp2//mS1Lfz7Qh8/L/NedqCQ+L4iWiPnZ3THjjwn3CoZ05ucpvrAMwKBgB54 +nay039MUVq44Owub3KDg+dcIU62U+cAC/9oG7qZbxYPmKkc4oL7IJSNecGHA5SbU +2268RFdl/gLz6tfRjbEOuOHzCjFPdvAdbysanpTMHLNc6FefJ+zxtgk9sJh0C4Jh +vxFrw9nTKKzfEl12gQ1SOaEaUIO0fEBGbe8ZpauRAoGAMAlGV+2/K4ebvAJKOVTa +dKAzQ+TD2SJmeR1HZmKDYddNqwtZlzg3v4ZhCk4eaUmGeC1Bdh8MDuB3QQvXz4Dr +vOIP4UVaOr+uM+7TgAgVnP4/K6IeJGzUDhX93pmpWhODfdu/oojEKVcpCojmEmS1 +KCBtmIrQLqzMpnBpLNuSY+Q= +-----END PRIVATE KEY----- diff --git a/tests/testflows/kerberos/configs/clickhouse/users.xml b/tests/testflows/kerberos/configs/clickhouse/users.xml new file mode 100644 index 00000000000..86b2cd9e1e3 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse/users.xml @@ -0,0 +1,133 @@ + + + + + + + + 10000000000 + + + 0 + + + random + + + + + 1 + + + + + + + + + + + + + ::/0 + + + + default + + + default + + + 1 + + + + + + + + + + + + + + + + + 3600 + + + 0 + 0 + 0 + 0 + 0 + + + + diff --git a/tests/testflows/kerberos/configs/clickhouse1/config.d/kerberos.xml b/tests/testflows/kerberos/configs/clickhouse1/config.d/kerberos.xml new file mode 100644 index 00000000000..ceaa497c561 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse1/config.d/kerberos.xml @@ -0,0 +1,5 @@ + + + EXAMPLE.COM + + \ No newline at end of file diff --git a/tests/testflows/kerberos/configs/clickhouse1/config.d/macros.xml b/tests/testflows/kerberos/configs/clickhouse1/config.d/macros.xml new file mode 100644 index 00000000000..6cdcc1b440c --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse1/config.d/macros.xml @@ -0,0 +1,8 @@ + + + + clickhouse1 + 01 + 01 + + diff --git a/tests/testflows/kerberos/configs/clickhouse1/users.d/kerberos-users.xml b/tests/testflows/kerberos/configs/clickhouse1/users.d/kerberos-users.xml new file mode 100644 index 00000000000..7029f20217f --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse1/users.d/kerberos-users.xml @@ -0,0 +1,10 @@ + + + + + EXAMPLE.COM + + 1 + + + \ No newline at end of file diff --git a/tests/testflows/kerberos/configs/clickhouse2/config.d/kerberos.xml b/tests/testflows/kerberos/configs/clickhouse2/config.d/kerberos.xml new file mode 100644 index 00000000000..ceaa497c561 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse2/config.d/kerberos.xml @@ -0,0 +1,5 @@ + + + EXAMPLE.COM + + \ No newline at end of file diff --git a/tests/testflows/kerberos/configs/clickhouse2/config.d/macros.xml b/tests/testflows/kerberos/configs/clickhouse2/config.d/macros.xml new file mode 100644 index 00000000000..a114a9ce4ab --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse2/config.d/macros.xml @@ -0,0 +1,8 @@ + + + + clickhouse2 + 01 + 02 + + diff --git a/tests/testflows/kerberos/configs/clickhouse3/config.d/macros.xml b/tests/testflows/kerberos/configs/clickhouse3/config.d/macros.xml new file mode 100644 index 00000000000..904a27b0172 --- /dev/null +++ b/tests/testflows/kerberos/configs/clickhouse3/config.d/macros.xml @@ -0,0 +1,8 @@ + + + + clickhouse3 + 01 + 03 + + diff --git a/tests/testflows/kerberos/configs/kerberos/etc/krb5.conf b/tests/testflows/kerberos/configs/kerberos/etc/krb5.conf new file mode 100644 index 00000000000..b963fc25daa --- /dev/null +++ b/tests/testflows/kerberos/configs/kerberos/etc/krb5.conf @@ -0,0 +1,38 @@ +[kdc] + require-preauth = false + +[libdefaults] + default_realm = EXAMPLE.COM + ticket_lifetime = 24000 + dns_lookup_realm = false + dns_lookup_kdc = false + dns_fallback = false + rdns = false + +[realms] + EXAMPLE.COM = { + kdc = kerberos + admin_server = kerberos + } + OTHER.COM = { + kdc = kerberos + admin_server = kerberos + } + +[domain_realm] + docker-compose_default = EXAMPLE.COM + .docker-compose_default = EXAMPLE.COM + +[appdefaults] + validate = false + pam = { + debug = false + ticket_lifetime = 36000 + renew_lifetime = 36000 + forwardable = true + krb4_convert = false + } + +[logging] + kdc = FILE:/var/log/krb5kdc.log + admin_server = FILE:/var/log/kadmin.log diff --git a/tests/testflows/kerberos/configs/kerberos/etc/krb5kdc/kdc.conf b/tests/testflows/kerberos/configs/kerberos/etc/krb5kdc/kdc.conf new file mode 100644 index 00000000000..9afe5351467 --- /dev/null +++ b/tests/testflows/kerberos/configs/kerberos/etc/krb5kdc/kdc.conf @@ -0,0 +1,15 @@ +[kdcdefaults] + kdc_ports = 88 + +[realms] + EXAMPLE.COM = { + kadmind_port = 749 + max_life = 12h 0m 0s + max_renewable_life = 7d 0h 0m 0s + master_key_type = des3-hmac-sha1 + supported_enctypes = des3-hmac-sha1:normal des-cbc-crc:normal des-cbc-crc:v4 + } + +[logging] + kdc = FILE:/usr/local/var/krb5kdc/kdc.log + admin_server = FILE:/usr/local/var/krb5kdc/kadmin.log diff --git a/tests/testflows/kerberos/configs/kerberos/etc/supervisord.conf b/tests/testflows/kerberos/configs/kerberos/etc/supervisord.conf new file mode 100644 index 00000000000..bec4ae41077 --- /dev/null +++ b/tests/testflows/kerberos/configs/kerberos/etc/supervisord.conf @@ -0,0 +1,31 @@ +[inet_http_server] +port=9001 + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl = http://127.0.0.1:9001 + +[program:krb5kdc] +command = /usr/sbin/krb5kdc -n +startretries = 1 +startsecs = 5 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 + +[program:kadmind] +command = /usr/sbin/kadmind -nofork +startretries = 1 +startsecs = 5 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 + + +[supervisord] +logfile = /tmp/supervisord_zbx_server.log +loglevel = critical +nodaemon = true +user = root +pidfile = /tmp/supervisord_zbx_server.pid +directory = /tmp \ No newline at end of file diff --git a/tests/testflows/kerberos/docker-compose/clickhouse-service.yml b/tests/testflows/kerberos/docker-compose/clickhouse-service.yml new file mode 100644 index 00000000000..14736a264b8 --- /dev/null +++ b/tests/testflows/kerberos/docker-compose/clickhouse-service.yml @@ -0,0 +1,32 @@ +version: '2.3' + +services: + clickhouse: + image: yandex/clickhouse-integration-test:21454 + expose: + - "9000" + - "9009" + - "8123" + volumes: + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/ssl:/etc/clickhouse-server/ssl" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/config.xml:/etc/clickhouse-server/config.xml" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/users.xml:/etc/clickhouse-server/users.xml" + - "${CLICKHOUSE_TESTS_SERVER_BIN_PATH:-/usr/bin/clickhouse}:/usr/bin/clickhouse" + - "${CLICKHOUSE_TESTS_ODBC_BRIDGE_BIN_PATH:-/usr/bin/clickhouse-odbc-bridge}:/usr/bin/clickhouse-odbc-bridge" + - "${CLICKHOUSE_TESTS_DIR}/configs/kerberos/etc/krb5.conf:/etc/krb5.conf" + entrypoint: bash -c "clickhouse server --config-file=/etc/clickhouse-server/config.xml --log-file=/var/log/clickhouse-server/clickhouse-server.log --errorlog-file=/var/log/clickhouse-server/clickhouse-server.err.log" + healthcheck: + test: clickhouse client --query='select 1' + interval: 10s + timeout: 10s + retries: 3 + start_period: 300s + + environment: + KRB5_CLIENT_KTNAME: /etc/krb5.keytab + KRB5_KTNAME: /etc/krb5.keytab + + cap_add: + - SYS_PTRACE + security_opt: + - label:disable diff --git a/tests/testflows/kerberos/docker-compose/docker-compose.yml b/tests/testflows/kerberos/docker-compose/docker-compose.yml new file mode 100644 index 00000000000..d1a74662a83 --- /dev/null +++ b/tests/testflows/kerberos/docker-compose/docker-compose.yml @@ -0,0 +1,75 @@ +version: '2.3' + +services: + + zookeeper: + extends: + file: zookeeper-service.yml + service: zookeeper + + kerberos: + extends: + file: kerberos-service.yml + service: kerberos + hostname: kerberos + depends_on: + zookeeper: + condition: service_healthy + + clickhouse1: + extends: + file: clickhouse-service.yml + service: clickhouse + hostname: clickhouse1 + volumes: + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse1/database/:/var/lib/clickhouse/" + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse1/logs/:/var/log/clickhouse-server/" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse1/config.d:/etc/clickhouse-server/config.d" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse1/users.d:/etc/clickhouse-server/users.d" + depends_on: + zookeeper: + condition: service_healthy + + clickhouse2: + extends: + file: clickhouse-service.yml + service: clickhouse + hostname: clickhouse2 + volumes: + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse2/database/:/var/lib/clickhouse/" + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse2/logs/:/var/log/clickhouse-server/" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse2/config.d:/etc/clickhouse-server/config.d" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse2/users.d:/etc/clickhouse-server/users.d" + depends_on: + zookeeper: + condition: service_healthy + + clickhouse3: + extends: + file: clickhouse-service.yml + service: clickhouse + hostname: clickhouse3 + volumes: + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse3/database/:/var/lib/clickhouse/" + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse3/logs/:/var/log/clickhouse-server/" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse3/config.d:/etc/clickhouse-server/config.d" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse3/users.d:/etc/clickhouse-server/users.d" + depends_on: + zookeeper: + condition: service_healthy + + # dummy service which does nothing, but allows to postpone + # 'docker-compose up -d' till all dependecies will go healthy + all_services_ready: + image: hello-world + depends_on: + clickhouse1: + condition: service_healthy + clickhouse2: + condition: service_healthy + clickhouse3: + condition: service_healthy + zookeeper: + condition: service_healthy + kerberos: + condition: service_healthy diff --git a/tests/testflows/kerberos/docker-compose/kerberos-service.yml b/tests/testflows/kerberos/docker-compose/kerberos-service.yml new file mode 100644 index 00000000000..3f21e93e0b6 --- /dev/null +++ b/tests/testflows/kerberos/docker-compose/kerberos-service.yml @@ -0,0 +1,27 @@ +version: '2.3' + +services: + kerberos: + image: zvonand/docker-krb5-server:1.0.0 + restart: always + expose: + - "88" + - "464" + - "749" + healthcheck: + test: echo 1 + interval: 10s + timeout: 10s + retries: 3 + start_period: 300s + environment: + KRB5_PASS: pwd + KRB5_REALM: EXAMPLE.COM + KRB5_KDC: localhost + volumes: + - "${CLICKHOUSE_TESTS_DIR}/configs/kerberos/etc/krb5kdc/kdc.conf:/etc/krb5kdc/kdc.conf" + - "${CLICKHOUSE_TESTS_DIR}/_instances/kerberos/krb5kdc/log/kdc.log:/usr/local/var/krb5kdc/kdc.log" + - "${CLICKHOUSE_TESTS_DIR}/_instances/kerberos/krb5kdc/log/kadmin.log:/usr/local/var/krb5kdc/kadmin.log" + - "${CLICKHOUSE_TESTS_DIR}/_instances/kerberos/var/log:/var/log" + security_opt: + - label:disable diff --git a/tests/testflows/kerberos/docker-compose/zookeeper-service.yml b/tests/testflows/kerberos/docker-compose/zookeeper-service.yml new file mode 100644 index 00000000000..6691a2df31c --- /dev/null +++ b/tests/testflows/kerberos/docker-compose/zookeeper-service.yml @@ -0,0 +1,18 @@ +version: '2.3' + +services: + zookeeper: + image: zookeeper:3.4.12 + expose: + - "2181" + environment: + ZOO_TICK_TIME: 500 + ZOO_MY_ID: 1 + healthcheck: + test: echo stat | nc localhost 2181 + interval: 10s + timeout: 10s + retries: 3 + start_period: 300s + security_opt: + - label:disable diff --git a/tests/testflows/kerberos/regression.py b/tests/testflows/kerberos/regression.py new file mode 100644 index 00000000000..9675ba6e3c8 --- /dev/null +++ b/tests/testflows/kerberos/regression.py @@ -0,0 +1,38 @@ +import sys +from testflows.core import * + +append_path(sys.path, "..") + +from helpers.cluster import Cluster +from helpers.argparser import argparser +from kerberos.requirements.requirements import * + +xfails = { +} + + +@TestModule +@Name("kerberos") +@ArgumentParser(argparser) +@Requirements( + RQ_SRS_016_Kerberos("1.0") +) +@XFails(xfails) +def regression(self, local, clickhouse_binary_path, stress=None, parallel=None): + """ClickHouse Kerberos authentication test regression module. + """ + nodes = { + "clickhouse": ("clickhouse1", "clickhouse2", "clickhouse3"), + "kerberos": ("kerberos", ), + } + + with Cluster(local, clickhouse_binary_path, nodes=nodes) as cluster: + self.context.cluster = cluster + + Feature(run=load("kerberos.tests.generic", "generic"), flags=TE) + Feature(run=load("kerberos.tests.config", "config"), flags=TE) + Feature(run=load("kerberos.tests.parallel", "parallel"), flags=TE) + + +if main(): + regression() diff --git a/tests/testflows/kerberos/requirements/requirements.md b/tests/testflows/kerberos/requirements/requirements.md new file mode 100644 index 00000000000..2121dd343b8 --- /dev/null +++ b/tests/testflows/kerberos/requirements/requirements.md @@ -0,0 +1,281 @@ +# QA-SRS016 ClickHouse Kerberos Authentication +# Software Requirements Specification + +## Table of Contents + +* 1 [Revision History](#revision-history) +* 2 [Introduction](#introduction) +* 3 [Terminology](#terminology) +* 4 [Requirements](#requirements) + * 4.1 [Generic](#generic) + * 4.1.1 [RQ.SRS-016.Kerberos](#rqsrs-016kerberos) + * 4.2 [Configuration](#configuration) + * 4.2.1 [RQ.SRS-016.Kerberos.Configuration.MultipleAuthMethods](#rqsrs-016kerberosconfigurationmultipleauthmethods) + * 4.2.2 [RQ.SRS-016.Kerberos.Configuration.KerberosNotEnabled](#rqsrs-016kerberosconfigurationkerberosnotenabled) + * 4.2.3 [RQ.SRS-016.Kerberos.Configuration.MultipleKerberosSections](#rqsrs-016kerberosconfigurationmultiplekerberossections) + * 4.2.4 [RQ.SRS-016.Kerberos.Configuration.WrongUserRealm](#rqsrs-016kerberosconfigurationwronguserrealm) + * 4.2.5 [RQ.SRS-016.Kerberos.Configuration.PrincipalAndRealmSpecified](#rqsrs-016kerberosconfigurationprincipalandrealmspecified) + * 4.2.6 [RQ.SRS-016.Kerberos.Configuration.MultiplePrincipalSections](#rqsrs-016kerberosconfigurationmultipleprincipalsections) + * 4.2.7 [RQ.SRS-016.Kerberos.Configuration.MultipleRealmSections](#rqsrs-016kerberosconfigurationmultiplerealmsections) + * 4.3 [Valid User](#valid-user) + * 4.3.1 [RQ.SRS-016.Kerberos.ValidUser.XMLConfiguredUser](#rqsrs-016kerberosvaliduserxmlconfigureduser) + * 4.3.2 [RQ.SRS-016.Kerberos.ValidUser.RBACConfiguredUser](#rqsrs-016kerberosvaliduserrbacconfigureduser) + * 4.3.3 [RQ.SRS-016.Kerberos.ValidUser.KerberosNotConfigured](#rqsrs-016kerberosvaliduserkerberosnotconfigured) + * 4.4 [Invalid User](#invalid-user) + * 4.4.1 [RQ.SRS-016.Kerberos.InvalidUser](#rqsrs-016kerberosinvaliduser) + * 4.4.2 [RQ.SRS-016.Kerberos.InvalidUser.UserDeleted](#rqsrs-016kerberosinvaliduseruserdeleted) + * 4.5 [Kerberos Not Available](#kerberos-not-available) + * 4.5.1 [RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidServerTicket](#rqsrs-016kerberoskerberosnotavailableinvalidserverticket) + * 4.5.2 [RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidClientTicket](#rqsrs-016kerberoskerberosnotavailableinvalidclientticket) + * 4.5.3 [RQ.SRS-016.Kerberos.KerberosNotAvailable.ValidTickets](#rqsrs-016kerberoskerberosnotavailablevalidtickets) + * 4.6 [Kerberos Restarted](#kerberos-restarted) + * 4.6.1 [RQ.SRS-016.Kerberos.KerberosServerRestarted](#rqsrs-016kerberoskerberosserverrestarted) + * 4.7 [Performance](#performance) + * 4.7.1 [RQ.SRS-016.Kerberos.Performance](#rqsrs-016kerberosperformance) + * 4.8 [Parallel Requests processing](#parallel-requests-processing) + * 4.8.1 [RQ.SRS-016.Kerberos.Parallel](#rqsrs-016kerberosparallel) + * 4.8.2 [RQ.SRS-016.Kerberos.Parallel.ValidRequests.KerberosAndNonKerberos](#rqsrs-016kerberosparallelvalidrequestskerberosandnonkerberos) + * 4.8.3 [RQ.SRS-016.Kerberos.Parallel.ValidRequests.SameCredentials](#rqsrs-016kerberosparallelvalidrequestssamecredentials) + * 4.8.4 [RQ.SRS-016.Kerberos.Parallel.ValidRequests.DifferentCredentials](#rqsrs-016kerberosparallelvalidrequestsdifferentcredentials) + * 4.8.5 [RQ.SRS-016.Kerberos.Parallel.ValidInvalid](#rqsrs-016kerberosparallelvalidinvalid) + * 4.8.6 [RQ.SRS-016.Kerberos.Parallel.Deletion](#rqsrs-016kerberosparalleldeletion) +* 5 [References](#references) + +## Revision History + +This document is stored in an electronic form using [Git] source control management software +hosted in a [GitHub Repository]. +All the updates are tracked using the [Git]'s [Revision History]. + +## Introduction + +This document specifies the behavior for authenticating existing users via [Kerberos] authentication protocol. +Existing [ClickHouse] users, that are properly configured, have an ability to authenticate using [Kerberos]. Kerberos authentication is only supported for HTTP requests, and users configured to authenticate via Kerberos cannot be authenticated by any other means of authentication. + +In order to use Kerberos authentication, Kerberos needs to be properly configured in the environment: Kerberos server must be present and user's and server's credentials must be set up. Configuring the Kerberos environment is outside the scope of this document. + +## Terminology + +* **Principal** - + A unique identity that uses [Kerberos]. + +* **Realm** - + A logical group of resources and identities that use [Kerberos]. + +* **Ticket** - + An encrypted block of data that authenticates principal. + +* **Credentials** - + A Kerberos ticket and a session key. + +* **Kerberized request** - + A HTTP query to ClickHouse server, which uses GSS [SPNEGO] and [Kerberos] to authenticate client. + +* **Unkerberized request** - + A HTTP query to ClickHouse server, which uses any other mean of authentication than GSS [SPNEGO] or [Kerberos]. + +For a more detailed descriprion, visit [Kerberos terminology]. + +## Requirements + +### Generic + +#### RQ.SRS-016.Kerberos +version: 1.0 + +[ClickHouse] SHALL support user authentication using [Kerberos] server. + +### Configuration + +#### RQ.SRS-016.Kerberos.Configuration.MultipleAuthMethods +version: 1.0 + +[ClickHouse] SHALL generate an exception and TERMINATE in case some user in `users.xml` has a `` section specified alongside with any other authentication method's section, e.g. `ldap`, `password`. + +#### RQ.SRS-016.Kerberos.Configuration.KerberosNotEnabled +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication in case user is properly configured for using Kerberos, but Kerberos itself is not enabled in `config.xml`. For example: + +```xml + + + + +``` +```xml + + + + HTTP/clickhouse.example.com@EXAMPLE.COM + + +``` +```xml + + + + EXAMPLE.COM + + +``` + +#### RQ.SRS-016.Kerberos.Configuration.MultipleKerberosSections +version: 1.0 + +[ClickHouse] SHALL disable [Kerberos] and reject [Kerberos] authentication in case multiple `kerberos` sections are present in `config.xml`. + +#### RQ.SRS-016.Kerberos.Configuration.WrongUserRealm +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if user's realm specified in `users.xml` doesn't match the realm of the principal trying to authenticate. + +#### RQ.SRS-016.Kerberos.Configuration.PrincipalAndRealmSpecified +version: 1.0 + +[ClickHouse] SHALL generate an exception and disable [Kerberos] in case both `realm` and `principal` sections are defined in `config.xml`. + +#### RQ.SRS-016.Kerberos.Configuration.MultiplePrincipalSections +version: 1.0 + +[ClickHouse] SHALL generate an exception and disable [Kerberos] in case multiple `principal` sections are specified inside `kerberos` section in `config.xml`. + +#### RQ.SRS-016.Kerberos.Configuration.MultipleRealmSections +version: 1.0 + +[ClickHouse] SHALL generate an exception and disable [Kerberos] in case multiple `realm` sections are specified inside `kerberos` section in `config.xml`. + +### Valid User + +#### RQ.SRS-016.Kerberos.ValidUser.XMLConfiguredUser +version: 1.0 + +[ClickHouse] SHALL accept [Kerberos] authentication for a user that is configured in `users.xml` and has [Kerberos] enabled, i.e.: + +```xml + + + + + + + + EXAMPLE.COM + + + + +``` + +#### RQ.SRS-016.Kerberos.ValidUser.RBACConfiguredUser +version: 1.0 + +[ClickHouse] SHALL accept [Kerberos] authentication if user is configured to authenticate via [Kerberos] using SQL queries + +```sql +CREATE USER my_user IDENTIFIED WITH kerberos REALM 'EXAMPLE.COM' +``` + +or + +```sql +CREATE USER my_user IDENTIFIED WITH kerberos +``` + +#### RQ.SRS-016.Kerberos.ValidUser.KerberosNotConfigured +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if username is valid but [ClickHouse] user is not configured to be authenticated using [Kerberos]. + +### Invalid User + +#### RQ.SRS-016.Kerberos.InvalidUser +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if name of the principal attempting to authenticate does not translate to a valid [ClickHouse] username configured in `users.xml` or via SQL workflow. + +#### RQ.SRS-016.Kerberos.InvalidUser.UserDeleted +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if [ClickHouse] user was removed from the database using an SQL query. + +### Kerberos Not Available + +#### RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidServerTicket +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if [ClickHouse] user is configured to be authenticated using [Kerberos] and [Kerberos] server is unavailable, but [ClickHouse] doesn't have a valid Kerberos ticket or the ticket is expired. + +#### RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidClientTicket +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if [ClickHouse] user is configured to to be authenticated using [Kerberos] and [Kerberos] server is unavailable, but the client doesn't have a valid Kerberos ticket or the ticket is expired. + +#### RQ.SRS-016.Kerberos.KerberosNotAvailable.ValidTickets +version: 1.0 + +[ClickHouse] SHALL accept [Kerberos] authentication if no [Kerberos] server is reachable, but [ClickHouse] is configured to use valid credentials and [ClickHouse] has already processed some valid kerberized request (so it was granted a ticket), and the client has a valid ticket as well. + +### Kerberos Restarted + +#### RQ.SRS-016.Kerberos.KerberosServerRestarted +version: 1.0 + +[ClickHouse] SHALL accept [Kerberos] authentication if [Kerberos] server was restarted. + +### Performance + +#### RQ.SRS-016.Kerberos.Performance +version: 1.0 + +[ClickHouse]'s performance for [Kerberos] authentication SHALL be comparable to regular authentication. + +### Parallel Requests processing + +#### RQ.SRS-016.Kerberos.Parallel +version: 1.0 + +[ClickHouse] SHALL support parallel authentication using [Kerberos]. + +#### RQ.SRS-016.Kerberos.Parallel.ValidRequests.KerberosAndNonKerberos +version: 1.0 + +[ClickHouse] SHALL support processing of simultaneous kerberized (for users configured to authenticate via [Kerberos]) and non-kerberized (for users configured to authenticate with any other means) requests. + +#### RQ.SRS-016.Kerberos.Parallel.ValidRequests.SameCredentials +version: 1.0 + +[ClickHouse] SHALL support processing of simultaneously sent [Kerberos] requests under the same credentials. + +#### RQ.SRS-016.Kerberos.Parallel.ValidRequests.DifferentCredentials +version: 1.0 + +[ClickHouse] SHALL support processing of simultaneously sent [Kerberos] requests under different credentials. + +#### RQ.SRS-016.Kerberos.Parallel.ValidInvalid +version: 1.0 + +[ClickHouse] SHALL support parallel authentication of users using [Kerberos] server, some of which are valid and some invalid. Valid users' authentication should not be affected by invalid users' attempts. + +#### RQ.SRS-016.Kerberos.Parallel.Deletion +version: 1.0 + +[ClickHouse] SHALL not crash when two or more [Kerberos] users are simultaneously deleting one another. + +## References + +* **ClickHouse:** https://clickhouse.tech +* **GitHub Repository:** https://github.com/ClickHouse/ClickHouse/blob/master/tests/testflows/kerberos/requirements/requirements.md +* **Revision History:** https://github.com/ClickHouse/ClickHouse/commits/master/tests/testflows/kerberos/requirements/requirements.md +* **Git:** https://git-scm.com/ +* **Kerberos terminology:** https://web.mit.edu/kerberos/kfw-4.1/kfw-4.1/kfw-4.1-help/html/kerberos_terminology.htm + +[Kerberos]: https://en.wikipedia.org/wiki/Kerberos_(protocol) +[SPNEGO]: https://en.wikipedia.org/wiki/SPNEGO +[ClickHouse]: https://clickhouse.tech +[GitHub]: https://gitlab.com +[GitHub Repository]: https://github.com/ClickHouse/ClickHouse/blob/master/tests/testflows/kerberos/requirements/requirements.md +[Revision History]: https://github.com/ClickHouse/ClickHouse/commits/master/tests/testflows/kerberos/requirements/requirements.md +[Git]: https://git-scm.com/ +[Kerberos terminology]: https://web.mit.edu/kerberos/kfw-4.1/kfw-4.1/kfw-4.1-help/html/kerberos_terminology.htm + diff --git a/tests/testflows/kerberos/requirements/requirements.py b/tests/testflows/kerberos/requirements/requirements.py new file mode 100644 index 00000000000..5c49e7d127f --- /dev/null +++ b/tests/testflows/kerberos/requirements/requirements.py @@ -0,0 +1,800 @@ +# These requirements were auto generated +# from software requirements specification (SRS) +# document by TestFlows v1.6.201216.1172002. +# Do not edit by hand but re-generate instead +# using 'tfs requirements generate' command. +from testflows.core import Specification +from testflows.core import Requirement + +Heading = Specification.Heading + +RQ_SRS_016_Kerberos = Requirement( + name='RQ.SRS-016.Kerberos', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support user authentication using [Kerberos] server.\n' + '\n' + ), + link=None, + level=3, + num='4.1.1') + +RQ_SRS_016_Kerberos_Configuration_MultipleAuthMethods = Requirement( + name='RQ.SRS-016.Kerberos.Configuration.MultipleAuthMethods', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + "[ClickHouse] SHALL generate an exception and TERMINATE in case some user in `users.xml` has a `` section specified alongside with any other authentication method's section, e.g. `ldap`, `password`.\n" + '\n' + ), + link=None, + level=3, + num='4.2.1') + +RQ_SRS_016_Kerberos_Configuration_KerberosNotEnabled = Requirement( + name='RQ.SRS-016.Kerberos.Configuration.KerberosNotEnabled', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL reject [Kerberos] authentication in case user is properly configured for using Kerberos, but Kerberos itself is not enabled in `config.xml`. For example:\n' + '\n' + '```xml\n' + '\n' + ' \n' + ' \n' + '\n' + '```\n' + '```xml\n' + '\n' + ' \n' + ' \n' + ' HTTP/clickhouse.example.com@EXAMPLE.COM\n' + ' \n' + '\n' + '```\n' + '```xml\n' + '\n' + ' \n' + ' \n' + ' EXAMPLE.COM\n' + ' \n' + '\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='4.2.2') + +RQ_SRS_016_Kerberos_Configuration_MultipleKerberosSections = Requirement( + name='RQ.SRS-016.Kerberos.Configuration.MultipleKerberosSections', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL disable [Kerberos] and reject [Kerberos] authentication in case multiple `kerberos` sections are present in `config.xml`.\n' + '\n' + ), + link=None, + level=3, + num='4.2.3') + +RQ_SRS_016_Kerberos_Configuration_WrongUserRealm = Requirement( + name='RQ.SRS-016.Kerberos.Configuration.WrongUserRealm', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + "[ClickHouse] SHALL reject [Kerberos] authentication if user's realm specified in `users.xml` doesn't match the realm of the principal trying to authenticate.\n" + '\n' + ), + link=None, + level=3, + num='4.2.4') + +RQ_SRS_016_Kerberos_Configuration_PrincipalAndRealmSpecified = Requirement( + name='RQ.SRS-016.Kerberos.Configuration.PrincipalAndRealmSpecified', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL generate an exception and disable [Kerberos] in case both `realm` and `principal` sections are defined in `config.xml`.\n' + '\n' + ), + link=None, + level=3, + num='4.2.5') + +RQ_SRS_016_Kerberos_Configuration_MultiplePrincipalSections = Requirement( + name='RQ.SRS-016.Kerberos.Configuration.MultiplePrincipalSections', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL generate an exception and disable [Kerberos] in case multiple `principal` sections are specified inside `kerberos` section in `config.xml`.\n' + '\n' + ), + link=None, + level=3, + num='4.2.6') + +RQ_SRS_016_Kerberos_Configuration_MultipleRealmSections = Requirement( + name='RQ.SRS-016.Kerberos.Configuration.MultipleRealmSections', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL generate an exception and disable [Kerberos] in case multiple `realm` sections are specified inside `kerberos` section in `config.xml`.\n' + '\n' + ), + link=None, + level=3, + num='4.2.7') + +RQ_SRS_016_Kerberos_ValidUser_XMLConfiguredUser = Requirement( + name='RQ.SRS-016.Kerberos.ValidUser.XMLConfiguredUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL accept [Kerberos] authentication for a user that is configured in `users.xml` and has [Kerberos] enabled, i.e.:\n' + '\n' + '```xml\n' + '\n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' EXAMPLE.COM\n' + ' \n' + ' \n' + ' \n' + '\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='4.3.1') + +RQ_SRS_016_Kerberos_ValidUser_RBACConfiguredUser = Requirement( + name='RQ.SRS-016.Kerberos.ValidUser.RBACConfiguredUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL accept [Kerberos] authentication if user is configured to authenticate via [Kerberos] using SQL queries\n' + '\n' + '```sql\n' + "CREATE USER my_user IDENTIFIED WITH kerberos REALM 'EXAMPLE.COM'\n" + '```\n' + '\n' + 'or\n' + '\n' + '```sql\n' + 'CREATE USER my_user IDENTIFIED WITH kerberos\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='4.3.2') + +RQ_SRS_016_Kerberos_ValidUser_KerberosNotConfigured = Requirement( + name='RQ.SRS-016.Kerberos.ValidUser.KerberosNotConfigured', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL reject [Kerberos] authentication if username is valid but [ClickHouse] user is not configured to be authenticated using [Kerberos].\n' + '\n' + ), + link=None, + level=3, + num='4.3.3') + +RQ_SRS_016_Kerberos_InvalidUser = Requirement( + name='RQ.SRS-016.Kerberos.InvalidUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL reject [Kerberos] authentication if name of the principal attempting to authenticate does not translate to a valid [ClickHouse] username configured in `users.xml` or via SQL workflow.\n' + '\n' + ), + link=None, + level=3, + num='4.4.1') + +RQ_SRS_016_Kerberos_InvalidUser_UserDeleted = Requirement( + name='RQ.SRS-016.Kerberos.InvalidUser.UserDeleted', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL reject [Kerberos] authentication if [ClickHouse] user was removed from the database using an SQL query.\n' + '\n' + ), + link=None, + level=3, + num='4.4.2') + +RQ_SRS_016_Kerberos_KerberosNotAvailable_InvalidServerTicket = Requirement( + name='RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidServerTicket', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + "[ClickHouse] SHALL reject [Kerberos] authentication if [ClickHouse] user is configured to be authenticated using [Kerberos] and [Kerberos] server is unavailable, but [ClickHouse] doesn't have a valid Kerberos ticket or the ticket is expired.\n" + '\n' + ), + link=None, + level=3, + num='4.5.1') + +RQ_SRS_016_Kerberos_KerberosNotAvailable_InvalidClientTicket = Requirement( + name='RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidClientTicket', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + "[ClickHouse] SHALL reject [Kerberos] authentication if [ClickHouse] user is configured to to be authenticated using [Kerberos] and [Kerberos] server is unavailable, but the client doesn't have a valid Kerberos ticket or the ticket is expired.\n" + '\n' + ), + link=None, + level=3, + num='4.5.2') + +RQ_SRS_016_Kerberos_KerberosNotAvailable_ValidTickets = Requirement( + name='RQ.SRS-016.Kerberos.KerberosNotAvailable.ValidTickets', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL accept [Kerberos] authentication if no [Kerberos] server is reachable, but [ClickHouse] is configured to use valid credentials and [ClickHouse] has already processed some valid kerberized request (so it was granted a ticket), and the client has a valid ticket as well.\n' + '\n' + ), + link=None, + level=3, + num='4.5.3') + +RQ_SRS_016_Kerberos_KerberosServerRestarted = Requirement( + name='RQ.SRS-016.Kerberos.KerberosServerRestarted', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL accept [Kerberos] authentication if [Kerberos] server was restarted.\n' + '\n' + ), + link=None, + level=3, + num='4.6.1') + +RQ_SRS_016_Kerberos_Performance = Requirement( + name='RQ.SRS-016.Kerberos.Performance', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + "[ClickHouse]'s performance for [Kerberos] authentication SHALL be comparable to regular authentication.\n" + '\n' + ), + link=None, + level=3, + num='4.7.1') + +RQ_SRS_016_Kerberos_Parallel = Requirement( + name='RQ.SRS-016.Kerberos.Parallel', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support parallel authentication using [Kerberos].\n' + '\n' + ), + link=None, + level=3, + num='4.8.1') + +RQ_SRS_016_Kerberos_Parallel_ValidRequests_KerberosAndNonKerberos = Requirement( + name='RQ.SRS-016.Kerberos.Parallel.ValidRequests.KerberosAndNonKerberos', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support processing of simultaneous kerberized (for users configured to authenticate via [Kerberos]) and non-kerberized (for users configured to authenticate with any other means) requests.\n' + '\n' + ), + link=None, + level=3, + num='4.8.2') + +RQ_SRS_016_Kerberos_Parallel_ValidRequests_SameCredentials = Requirement( + name='RQ.SRS-016.Kerberos.Parallel.ValidRequests.SameCredentials', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support processing of simultaneously sent [Kerberos] requests under the same credentials.\n' + '\n' + ), + link=None, + level=3, + num='4.8.3') + +RQ_SRS_016_Kerberos_Parallel_ValidRequests_DifferentCredentials = Requirement( + name='RQ.SRS-016.Kerberos.Parallel.ValidRequests.DifferentCredentials', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support processing of simultaneously sent [Kerberos] requests under different credentials.\n' + '\n' + ), + link=None, + level=3, + num='4.8.4') + +RQ_SRS_016_Kerberos_Parallel_ValidInvalid = Requirement( + name='RQ.SRS-016.Kerberos.Parallel.ValidInvalid', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + "[ClickHouse] SHALL support parallel authentication of users using [Kerberos] server, some of which are valid and some invalid. Valid users' authentication should not be affected by invalid users' attempts.\n" + '\n' + ), + link=None, + level=3, + num='4.8.5') + +RQ_SRS_016_Kerberos_Parallel_Deletion = Requirement( + name='RQ.SRS-016.Kerberos.Parallel.Deletion', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL not crash when two or more [Kerberos] users are simultaneously deleting one another.\n' + '\n' + ), + link=None, + level=3, + num='4.8.6') + +QA_SRS016_ClickHouse_Kerberos_Authentication = Specification( + name='QA-SRS016 ClickHouse Kerberos Authentication', + description=None, + author='Andrey Zvonov', + date='December 14, 2020', + status='-', + approved_by='-', + approved_date='-', + approved_version='-', + version=None, + group=None, + type=None, + link=None, + uid=None, + parent=None, + children=None, + headings=( + Heading(name='Revision History', level=1, num='1'), + Heading(name='Introduction', level=1, num='2'), + Heading(name='Terminology', level=1, num='3'), + Heading(name='Requirements', level=1, num='4'), + Heading(name='Generic', level=2, num='4.1'), + Heading(name='RQ.SRS-016.Kerberos', level=3, num='4.1.1'), + Heading(name='Configuration', level=2, num='4.2'), + Heading(name='RQ.SRS-016.Kerberos.Configuration.MultipleAuthMethods', level=3, num='4.2.1'), + Heading(name='RQ.SRS-016.Kerberos.Configuration.KerberosNotEnabled', level=3, num='4.2.2'), + Heading(name='RQ.SRS-016.Kerberos.Configuration.MultipleKerberosSections', level=3, num='4.2.3'), + Heading(name='RQ.SRS-016.Kerberos.Configuration.WrongUserRealm', level=3, num='4.2.4'), + Heading(name='RQ.SRS-016.Kerberos.Configuration.PrincipalAndRealmSpecified', level=3, num='4.2.5'), + Heading(name='RQ.SRS-016.Kerberos.Configuration.MultiplePrincipalSections', level=3, num='4.2.6'), + Heading(name='RQ.SRS-016.Kerberos.Configuration.MultipleRealmSections', level=3, num='4.2.7'), + Heading(name='Valid User', level=2, num='4.3'), + Heading(name='RQ.SRS-016.Kerberos.ValidUser.XMLConfiguredUser', level=3, num='4.3.1'), + Heading(name='RQ.SRS-016.Kerberos.ValidUser.RBACConfiguredUser', level=3, num='4.3.2'), + Heading(name='RQ.SRS-016.Kerberos.ValidUser.KerberosNotConfigured', level=3, num='4.3.3'), + Heading(name='Invalid User', level=2, num='4.4'), + Heading(name='RQ.SRS-016.Kerberos.InvalidUser', level=3, num='4.4.1'), + Heading(name='RQ.SRS-016.Kerberos.InvalidUser.UserDeleted', level=3, num='4.4.2'), + Heading(name='Kerberos Not Available', level=2, num='4.5'), + Heading(name='RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidServerTicket', level=3, num='4.5.1'), + Heading(name='RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidClientTicket', level=3, num='4.5.2'), + Heading(name='RQ.SRS-016.Kerberos.KerberosNotAvailable.ValidTickets', level=3, num='4.5.3'), + Heading(name='Kerberos Restarted', level=2, num='4.6'), + Heading(name='RQ.SRS-016.Kerberos.KerberosServerRestarted', level=3, num='4.6.1'), + Heading(name='Performance', level=2, num='4.7'), + Heading(name='RQ.SRS-016.Kerberos.Performance', level=3, num='4.7.1'), + Heading(name='Parallel Requests processing', level=2, num='4.8'), + Heading(name='RQ.SRS-016.Kerberos.Parallel', level=3, num='4.8.1'), + Heading(name='RQ.SRS-016.Kerberos.Parallel.ValidRequests.KerberosAndNonKerberos', level=3, num='4.8.2'), + Heading(name='RQ.SRS-016.Kerberos.Parallel.ValidRequests.SameCredentials', level=3, num='4.8.3'), + Heading(name='RQ.SRS-016.Kerberos.Parallel.ValidRequests.DifferentCredentials', level=3, num='4.8.4'), + Heading(name='RQ.SRS-016.Kerberos.Parallel.ValidInvalid', level=3, num='4.8.5'), + Heading(name='RQ.SRS-016.Kerberos.Parallel.Deletion', level=3, num='4.8.6'), + Heading(name='References', level=1, num='5'), + ), + requirements=( + RQ_SRS_016_Kerberos, + RQ_SRS_016_Kerberos_Configuration_MultipleAuthMethods, + RQ_SRS_016_Kerberos_Configuration_KerberosNotEnabled, + RQ_SRS_016_Kerberos_Configuration_MultipleKerberosSections, + RQ_SRS_016_Kerberos_Configuration_WrongUserRealm, + RQ_SRS_016_Kerberos_Configuration_PrincipalAndRealmSpecified, + RQ_SRS_016_Kerberos_Configuration_MultiplePrincipalSections, + RQ_SRS_016_Kerberos_Configuration_MultipleRealmSections, + RQ_SRS_016_Kerberos_ValidUser_XMLConfiguredUser, + RQ_SRS_016_Kerberos_ValidUser_RBACConfiguredUser, + RQ_SRS_016_Kerberos_ValidUser_KerberosNotConfigured, + RQ_SRS_016_Kerberos_InvalidUser, + RQ_SRS_016_Kerberos_InvalidUser_UserDeleted, + RQ_SRS_016_Kerberos_KerberosNotAvailable_InvalidServerTicket, + RQ_SRS_016_Kerberos_KerberosNotAvailable_InvalidClientTicket, + RQ_SRS_016_Kerberos_KerberosNotAvailable_ValidTickets, + RQ_SRS_016_Kerberos_KerberosServerRestarted, + RQ_SRS_016_Kerberos_Performance, + RQ_SRS_016_Kerberos_Parallel, + RQ_SRS_016_Kerberos_Parallel_ValidRequests_KerberosAndNonKerberos, + RQ_SRS_016_Kerberos_Parallel_ValidRequests_SameCredentials, + RQ_SRS_016_Kerberos_Parallel_ValidRequests_DifferentCredentials, + RQ_SRS_016_Kerberos_Parallel_ValidInvalid, + RQ_SRS_016_Kerberos_Parallel_Deletion, + ), + content=''' +# QA-SRS016 ClickHouse Kerberos Authentication +# Software Requirements Specification + +(c) 2020 Altinity LTD. All Rights Reserved. + +**Document status:** Confidential + +**Author:** Andrey Zvonov + +**Date:** December 14, 2020 + +## Approval + +**Status:** - + +**Version:** - + +**Approved by:** - + +**Date:** - + + +## Table of Contents + +* 1 [Revision History](#revision-history) +* 2 [Introduction](#introduction) +* 3 [Terminology](#terminology) +* 4 [Requirements](#requirements) + * 4.1 [Generic](#generic) + * 4.1.1 [RQ.SRS-016.Kerberos](#rqsrs-016kerberos) + * 4.2 [Configuration](#configuration) + * 4.2.1 [RQ.SRS-016.Kerberos.Configuration.MultipleAuthMethods](#rqsrs-016kerberosconfigurationmultipleauthmethods) + * 4.2.2 [RQ.SRS-016.Kerberos.Configuration.KerberosNotEnabled](#rqsrs-016kerberosconfigurationkerberosnotenabled) + * 4.2.3 [RQ.SRS-016.Kerberos.Configuration.MultipleKerberosSections](#rqsrs-016kerberosconfigurationmultiplekerberossections) + * 4.2.4 [RQ.SRS-016.Kerberos.Configuration.WrongUserRealm](#rqsrs-016kerberosconfigurationwronguserrealm) + * 4.2.5 [RQ.SRS-016.Kerberos.Configuration.PrincipalAndRealmSpecified](#rqsrs-016kerberosconfigurationprincipalandrealmspecified) + * 4.2.6 [RQ.SRS-016.Kerberos.Configuration.MultiplePrincipalSections](#rqsrs-016kerberosconfigurationmultipleprincipalsections) + * 4.2.7 [RQ.SRS-016.Kerberos.Configuration.MultipleRealmSections](#rqsrs-016kerberosconfigurationmultiplerealmsections) + * 4.3 [Valid User](#valid-user) + * 4.3.1 [RQ.SRS-016.Kerberos.ValidUser.XMLConfiguredUser](#rqsrs-016kerberosvaliduserxmlconfigureduser) + * 4.3.2 [RQ.SRS-016.Kerberos.ValidUser.RBACConfiguredUser](#rqsrs-016kerberosvaliduserrbacconfigureduser) + * 4.3.3 [RQ.SRS-016.Kerberos.ValidUser.KerberosNotConfigured](#rqsrs-016kerberosvaliduserkerberosnotconfigured) + * 4.4 [Invalid User](#invalid-user) + * 4.4.1 [RQ.SRS-016.Kerberos.InvalidUser](#rqsrs-016kerberosinvaliduser) + * 4.4.2 [RQ.SRS-016.Kerberos.InvalidUser.UserDeleted](#rqsrs-016kerberosinvaliduseruserdeleted) + * 4.5 [Kerberos Not Available](#kerberos-not-available) + * 4.5.1 [RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidServerTicket](#rqsrs-016kerberoskerberosnotavailableinvalidserverticket) + * 4.5.2 [RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidClientTicket](#rqsrs-016kerberoskerberosnotavailableinvalidclientticket) + * 4.5.3 [RQ.SRS-016.Kerberos.KerberosNotAvailable.ValidTickets](#rqsrs-016kerberoskerberosnotavailablevalidtickets) + * 4.6 [Kerberos Restarted](#kerberos-restarted) + * 4.6.1 [RQ.SRS-016.Kerberos.KerberosServerRestarted](#rqsrs-016kerberoskerberosserverrestarted) + * 4.7 [Performance](#performance) + * 4.7.1 [RQ.SRS-016.Kerberos.Performance](#rqsrs-016kerberosperformance) + * 4.8 [Parallel Requests processing](#parallel-requests-processing) + * 4.8.1 [RQ.SRS-016.Kerberos.Parallel](#rqsrs-016kerberosparallel) + * 4.8.2 [RQ.SRS-016.Kerberos.Parallel.ValidRequests.KerberosAndNonKerberos](#rqsrs-016kerberosparallelvalidrequestskerberosandnonkerberos) + * 4.8.3 [RQ.SRS-016.Kerberos.Parallel.ValidRequests.SameCredentials](#rqsrs-016kerberosparallelvalidrequestssamecredentials) + * 4.8.4 [RQ.SRS-016.Kerberos.Parallel.ValidRequests.DifferentCredentials](#rqsrs-016kerberosparallelvalidrequestsdifferentcredentials) + * 4.8.5 [RQ.SRS-016.Kerberos.Parallel.ValidInvalid](#rqsrs-016kerberosparallelvalidinvalid) + * 4.8.6 [RQ.SRS-016.Kerberos.Parallel.Deletion](#rqsrs-016kerberosparalleldeletion) +* 5 [References](#references) + +## Revision History + +This document is stored in an electronic form using [Git] source control management software +hosted in a [GitLab Repository]. +All the updates are tracked using the [Git]'s [Revision History]. + +## Introduction + +This document specifies the behavior for authenticating existing users using [Kerberos] authentication protocol. +Existing [ClickHouse] users, that are properly configured, have an ability to authenticate using [Kerberos]. Kerberos authentication is only supported for HTTP requests, and users configured to authenticate via Kerberos cannot be authenticated by any other means of authentication. + +In order to use Kerberos authentication, Kerberos needs to be properly configured in the environment: Kerberos server must be present and user's and server's credentials must be set up. Configuring the Kerberos environment is outside the scope of this document. + +## Terminology + +* **Principal** - + A unique identity that uses [Kerberos]. + +* **Realm** - + A logical group of resources and identities that use [Kerberos]. + +* **Ticket** - + An encrypted block of data that authenticates principal. + +* **Credentials** - + A Kerberos ticket and a session key. + +* **Kerberized request** - + A HTTP query to ClickHouse server, which uses GSS [SPNEGO] and [Kerberos] to authenticate client. + +* **Unkerberized request** - + A HTTP query to ClickHouse server, which uses any other mean of authentication than GSS [SPNEGO] or [Kerberos]. + +For a more detailed descriprion, visit [Kerberos terminology]. + +## Requirements + +### Generic + +#### RQ.SRS-016.Kerberos +version: 1.0 + +[ClickHouse] SHALL support user authentication using [Kerberos] server. + +### Configuration + +#### RQ.SRS-016.Kerberos.Configuration.MultipleAuthMethods +version: 1.0 + +[ClickHouse] SHALL generate an exception and TERMINATE in case some user in `users.xml` has a `` section specified alongside with any other authentication method's section, e.g. `ldap`, `password`. + +#### RQ.SRS-016.Kerberos.Configuration.KerberosNotEnabled +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication in case user is properly configured for using Kerberos, but Kerberos itself is not enabled in `config.xml`. For example: + +```xml + + + + +``` +```xml + + + + HTTP/clickhouse.example.com@EXAMPLE.COM + + +``` +```xml + + + + EXAMPLE.COM + + +``` + +#### RQ.SRS-016.Kerberos.Configuration.MultipleKerberosSections +version: 1.0 + +[ClickHouse] SHALL disable [Kerberos] and reject [Kerberos] authentication in case multiple `kerberos` sections are present in `config.xml`. + +#### RQ.SRS-016.Kerberos.Configuration.WrongUserRealm +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if user's realm specified in `users.xml` doesn't match the realm of the principal trying to authenticate. + +#### RQ.SRS-016.Kerberos.Configuration.PrincipalAndRealmSpecified +version: 1.0 + +[ClickHouse] SHALL generate an exception and disable [Kerberos] in case both `realm` and `principal` sections are defined in `config.xml`. + +#### RQ.SRS-016.Kerberos.Configuration.MultiplePrincipalSections +version: 1.0 + +[ClickHouse] SHALL generate an exception and disable [Kerberos] in case multiple `principal` sections are specified inside `kerberos` section in `config.xml`. + +#### RQ.SRS-016.Kerberos.Configuration.MultipleRealmSections +version: 1.0 + +[ClickHouse] SHALL generate an exception and disable [Kerberos] in case multiple `realm` sections are specified inside `kerberos` section in `config.xml`. + +### Valid User + +#### RQ.SRS-016.Kerberos.ValidUser.XMLConfiguredUser +version: 1.0 + +[ClickHouse] SHALL accept [Kerberos] authentication for a user that is configured in `users.xml` and has [Kerberos] enabled, i.e.: + +```xml + + + + + + + + EXAMPLE.COM + + + + +``` + +#### RQ.SRS-016.Kerberos.ValidUser.RBACConfiguredUser +version: 1.0 + +[ClickHouse] SHALL accept [Kerberos] authentication if user is configured to authenticate via [Kerberos] using SQL queries + +```sql +CREATE USER my_user IDENTIFIED WITH kerberos REALM 'EXAMPLE.COM' +``` + +or + +```sql +CREATE USER my_user IDENTIFIED WITH kerberos +``` + +#### RQ.SRS-016.Kerberos.ValidUser.KerberosNotConfigured +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if username is valid but [ClickHouse] user is not configured to be authenticated using [Kerberos]. + +### Invalid User + +#### RQ.SRS-016.Kerberos.InvalidUser +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if name of the principal attempting to authenticate does not translate to a valid [ClickHouse] username configured in `users.xml` or via SQL workflow. + +#### RQ.SRS-016.Kerberos.InvalidUser.UserDeleted +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if [ClickHouse] user was removed from the database using an SQL query. + +### Kerberos Not Available + +#### RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidServerTicket +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if [ClickHouse] user is configured to be authenticated using [Kerberos] and [Kerberos] server is unavailable, but [ClickHouse] doesn't have a valid Kerberos ticket or the ticket is expired. + +#### RQ.SRS-016.Kerberos.KerberosNotAvailable.InvalidClientTicket +version: 1.0 + +[ClickHouse] SHALL reject [Kerberos] authentication if [ClickHouse] user is configured to to be authenticated using [Kerberos] and [Kerberos] server is unavailable, but the client doesn't have a valid Kerberos ticket or the ticket is expired. + +#### RQ.SRS-016.Kerberos.KerberosNotAvailable.ValidTickets +version: 1.0 + +[ClickHouse] SHALL accept [Kerberos] authentication if no [Kerberos] server is reachable, but [ClickHouse] is configured to use valid credentials and [ClickHouse] has already processed some valid kerberized request (so it was granted a ticket), and the client has a valid ticket as well. + +### Kerberos Restarted + +#### RQ.SRS-016.Kerberos.KerberosServerRestarted +version: 1.0 + +[ClickHouse] SHALL accept [Kerberos] authentication if [Kerberos] server was restarted. + +### Performance + +#### RQ.SRS-016.Kerberos.Performance +version: 1.0 + +[ClickHouse]'s performance for [Kerberos] authentication SHALL be comparable to regular authentication. + +### Parallel Requests processing + +#### RQ.SRS-016.Kerberos.Parallel +version: 1.0 + +[ClickHouse] SHALL support parallel authentication using [Kerberos]. + +#### RQ.SRS-016.Kerberos.Parallel.ValidRequests.KerberosAndNonKerberos +version: 1.0 + +[ClickHouse] SHALL support processing of simultaneous kerberized (for users configured to authenticate via [Kerberos]) and non-kerberized (for users configured to authenticate with any other means) requests. + +#### RQ.SRS-016.Kerberos.Parallel.ValidRequests.SameCredentials +version: 1.0 + +[ClickHouse] SHALL support processing of simultaneously sent [Kerberos] requests under the same credentials. + +#### RQ.SRS-016.Kerberos.Parallel.ValidRequests.DifferentCredentials +version: 1.0 + +[ClickHouse] SHALL support processing of simultaneously sent [Kerberos] requests under different credentials. + +#### RQ.SRS-016.Kerberos.Parallel.ValidInvalid +version: 1.0 + +[ClickHouse] SHALL support parallel authentication of users using [Kerberos] server, some of which are valid and some invalid. Valid users' authentication should not be affected by invalid users' attempts. + +#### RQ.SRS-016.Kerberos.Parallel.Deletion +version: 1.0 + +[ClickHouse] SHALL not crash when two or more [Kerberos] users are simultaneously deleting one another. + +## References + +* **ClickHouse:** https://clickhouse.tech +* **Gitlab Repository:** https://gitlab.com/altinity-qa/documents/qa-srs016-clickhouse-kerberos-authentication/-/blob/master/QA_SRS016_ClickHouse_Kerberos_Authentication.md +* **Revision History:** https://gitlab.com/altinity-qa/documents/qa-srs016-clickhouse-kerberos-authentication/-/commits/master/QA_SRS016_ClickHouse_Kerberos_Authentication.md +* **Git:** https://git-scm.com/ +* **Kerberos terminology:** https://web.mit.edu/kerberos/kfw-4.1/kfw-4.1/kfw-4.1-help/html/kerberos_terminology.htm + +[Kerberos]: https://en.wikipedia.org/wiki/Kerberos_(protocol) +[SPNEGO]: https://en.wikipedia.org/wiki/SPNEGO +[ClickHouse]: https://clickhouse.tech +[GitLab]: https://gitlab.com +[GitLab Repository]: https://gitlab.com/altinity-qa/documents/qa-srs016-clickhouse-kerberos-authentication/-/blob/master/QA_SRS016_ClickHouse_Kerberos_Authentication.md +[Revision History]: https://gitlab.com/altinity-qa/documents/qa-srs016-clickhouse-kerberos-authentication/-/commits/master/QA_SRS016_ClickHouse_Kerberos_Authentication.md +[Git]: https://git-scm.com/ +[Kerberos terminology]: https://web.mit.edu/kerberos/kfw-4.1/kfw-4.1/kfw-4.1-help/html/kerberos_terminology.htm +''') diff --git a/tests/testflows/kerberos/tests/common.py b/tests/testflows/kerberos/tests/common.py new file mode 100644 index 00000000000..e768a78cad5 --- /dev/null +++ b/tests/testflows/kerberos/tests/common.py @@ -0,0 +1,225 @@ +from testflows.core import * +from testflows.asserts import error +from contextlib import contextmanager +import xml.etree.ElementTree as xmltree + +import time +import uuid + + +def getuid(): + return str(uuid.uuid1()).replace('-', '_') + + +def xml_append(root, tag, text=Null): + element = xmltree.Element(tag) + if text: + element.text = text + root.append(element) + + +def xml_write(data, filename): + strdata = xmltree.tostring(data) + with open(filename, "wb") as f: + f.write(strdata) + + +def xml_parse_file(filename): + return xmltree.parse(filename).getroot() + + +def create_default_config(filename): + contents = "" + if "kerberos_users.xml" in filename: + contents = "EXAMPLE.COM" \ + "" + elif "kerberos.xml" in filename: + contents = "EXAMPLE.COM" + + with open(filename, "w") as f: + f.write(contents) + + +def test_select_query(node, krb_auth=True, req="SELECT currentUser()"): + """ Helper forming a HTTP query to ClickHouse server + """ + if krb_auth: + return f"echo '{req}' | curl --negotiate -u : 'http://{node.name}:8123/' --data-binary @-" + else: + return f"echo '{req}' | curl 'http://{node.name}:8123/' --data-binary @-" + + +@TestStep(Given) +def kinit_no_keytab(self, node, principal="kerberos_user", lifetime_option="-l 10:00"): + """ Helper for obtaining Kerberos ticket for client + """ + try: + node.cmd("echo pwd | kinit admin/admin") + node.cmd(f"kadmin -w pwd -q \"add_principal -pw pwd {principal}\"") + node.cmd(f"echo pwd | kinit {lifetime_option} {principal}") + yield + finally: + node.cmd("kdestroy") + + +@TestStep(Given) +def create_server_principal(self, node): + """ Helper for obtaining Kerberos ticket for server + """ + try: + node.cmd("echo pwd | kinit admin/admin") + node.cmd(f"kadmin -w pwd -q \"add_principal -randkey HTTP/docker-compose_{node.name}_1.docker-compose_default\"") + node.cmd(f"kadmin -w pwd -q \"ktadd -k /etc/krb5.keytab HTTP/docker-compose_{node.name}_1.docker-compose_default\"") + yield + finally: + node.cmd("kdestroy") + node.cmd("rm /etc/krb5.keytab") + + +@TestStep(Given) +def save_file_state(self, node, filename): + """ Save current file and then restore it, restarting the node + """ + try: + with When("I save file state"): + with open(filename, 'r') as f: + a = f.read() + yield + finally: + with Finally("I restore initial state"): + with open(filename, 'w') as f: + f.write(a) + node.restart() + + +@TestStep(Given) +def temp_erase(self, node, filename=None): + """ Temporary erasing config file and restarting the node + """ + if filename is None: + filename = f"kerberos/configs/{node.name}/config.d/kerberos.xml" + with When("I save file state"): + with open(filename, 'r') as f: + a = f.read() + try: + with Then("I overwrite file to be dummy"): + with open(filename, 'w') as f: + f.write("\n") + node.restart() + yield + finally: + with Finally("I restore initial file state"): + with open(filename, 'w') as f: + f.write(a) + node.restart() + + +def restart(node, config_path, safe=False, timeout=60): + """Restart ClickHouse server and wait for config to be reloaded. + """ + + filename = '/etc/clickhouse-server/config.xml' if 'config.d' in config_path else '/etc/clickhouse-server/users.xml' + with When("I restart ClickHouse server node"): + with node.cluster.shell(node.name) as bash: + bash.expect(bash.prompt) + + with By("closing terminal to the node to be restarted"): + bash.close() + + with And("getting current log size"): + logsize = \ + node.command("stat --format=%s /var/log/clickhouse-server/clickhouse-server.log").output.split(" ")[0].strip() + + with And("restarting ClickHouse server"): + node.restart(safe=safe) + + with Then("tailing the log file from using previous log size as the offset"): + bash.prompt = bash.__class__.prompt + bash.open() + bash.send(f"tail -c +{logsize} -f /var/log/clickhouse-server/clickhouse-server.log") + + with And("waiting for config reload message in the log file"): + bash.expect( + f"ConfigReloader: Loaded config '{filename}', performed update on configuration", + timeout=timeout) + + +@TestStep +def check_wrong_config(self, node, client, config_path, modify_file, log_error="", output="", + tail=120, timeout=60, healthy_on_restart=True): + """Check that ClickHouse errors when trying to load invalid configuration file. + """ + preprocessed_name = "config.xml" if "config.d" in config_path else "users.xml" + + full_config_path = "/etc/clickhouse-server/config.d/kerberos.xml" if "config.d" in config_path else "/etc/clickhouse-server/users.d/kerberos-users.xml" + + uid = getuid() + + try: + with Given("I save config file to restore it later"): + with open(config_path, 'r') as f: + initial_contents = f.read() + + with And("I prepare the error log by writing empty lines into it"): + node.command("echo -e \"%s\" > /var/log/clickhouse-server/clickhouse-server.err.log" % ("-\\n" * tail)) + + with When("I modify xml file"): + root = xml_parse_file(config_path) + root = modify_file(root) + root.append(xmltree.fromstring(f"{uid}")) + config_contents = xmltree.tostring(root, encoding='utf8', method='xml').decode('utf-8') + command = f"cat < {full_config_path}\n{config_contents}\nHEREDOC" + node.command(command, steps=False, exitcode=0) + # time.sleep(1) + + with Then(f"{preprocessed_name} should be updated", description=f"timeout {timeout}"): + started = time.time() + command = f"cat /var/lib/clickhouse/preprocessed_configs/{preprocessed_name} | grep {uid} > /dev/null" + while time.time() - started < timeout: + exitcode = node.command(command, steps=False).exitcode + if exitcode == 0: + break + time.sleep(1) + assert exitcode == 0, error() + + with When("I restart ClickHouse to apply the config changes"): + if output: + node.restart(safe=False, wait_healthy=True) + else: + node.restart(safe=False, wait_healthy=False) + + if output != "": + with Then(f"check {output} is in output"): + time.sleep(5) + started = time.time() + while time.time() - started < timeout: + kinit_no_keytab(node=client) + create_server_principal(node=node) + r = client.cmd(test_select_query(node=node), no_checks=True) + if output in r.output: + assert True, error() + break + time.sleep(1) + else: + assert False, error() + + finally: + with Finally("I restore original config"): + with By("restoring the (correct) config file"): + with open(config_path, 'w') as f: + f.write(initial_contents) + with And("restarting the node"): + node.restart(safe=False) + + if log_error != "": + with Then("error log should contain the expected error message"): + started = time.time() + command = f"tail -n {tail} /var/log/clickhouse-server/clickhouse-server.err.log | grep \"{log_error}\"" + while time.time() - started < timeout: + exitcode = node.command(command, steps=False).exitcode + if exitcode == 0: + break + time.sleep(1) + assert exitcode == 0, error() + + diff --git a/tests/testflows/kerberos/tests/config.py b/tests/testflows/kerberos/tests/config.py new file mode 100644 index 00000000000..3f4bf15deb5 --- /dev/null +++ b/tests/testflows/kerberos/tests/config.py @@ -0,0 +1,163 @@ +from testflows.core import * +from kerberos.tests.common import * +from kerberos.requirements.requirements import * + +import time +import datetime +import itertools + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Configuration_KerberosNotEnabled("1.0") +) +def kerberos_not_enabled(self): + """ClickHouse SHALL reject Kerberos authentication if user is properly configured for Kerberos, + but Kerberos itself is not enabled in config.xml. + """ + ch_nodes = self.context.ch_nodes + config_path = f"kerberos/configs/{ch_nodes[0].name}/config.d/kerberos.xml" + + def modify_file(root): + return xmltree.fromstring("") + + check_wrong_config(node=ch_nodes[0], client=ch_nodes[2], config_path=config_path, modify_file=modify_file, + output="Kerberos is not enabled") + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Configuration_MultipleKerberosSections("1.0") +) +def multiple_kerberos(self): + """ClickHouse SHALL disable Kerberos authentication if more than one kerberos sections specified in config.xml. + """ + ch_nodes = self.context.ch_nodes + config_path = f"kerberos/configs/{ch_nodes[0].name}/config.d/kerberos.xml" + + def modify_file(root): + second_section = "EXAM.COM" + root.append(xmltree.fromstring(second_section)) + return root + + check_wrong_config(node=ch_nodes[0], client=ch_nodes[2], config_path=config_path, modify_file=modify_file, + log_error="Multiple kerberos sections are not allowed", healthy_on_restart=False) + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Configuration_WrongUserRealm("1.0") +) +def wrong_user_realm(self): + """ClickHouse SHALL reject Kerberos authentication if user's realm specified in users.xml + doesn't match the realm of the principal trying to authenticate. + """ + + ch_nodes = self.context.ch_nodes + config_path = f"kerberos/configs/{ch_nodes[0].name}/users.d/kerberos-users.xml" + + def modify_file(root): + krb = root.find('users').find('kerberos_user') + krb.find('kerberos').find('realm').text = "OTHER.COM" + return root + + check_wrong_config(node=ch_nodes[0], client=ch_nodes[2], config_path=config_path, modify_file=modify_file, + output="Authentication failed") + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Configuration_MultipleAuthMethods("1.0") +) +def multiple_auth_methods(self): + """ClickHouse SHALL reject Kerberos authentication if other + auth method is specified for user alongside with Kerberos. + """ + ch_nodes = self.context.ch_nodes + config_path = f"kerberos/configs/{ch_nodes[0].name}/users.d/kerberos-users.xml" + + def modify_file(root): + krb = root.find('users').find('kerberos_user') + xml_append(krb, 'password', 'qwerty') + return root + + check_wrong_config(node=ch_nodes[0], client=ch_nodes[2], config_path=config_path, modify_file=modify_file, + log_error="More than one field of", healthy_on_restart=False) + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Configuration_PrincipalAndRealmSpecified("1.0") +) +def principal_and_realm_specified(self): + """ClickHouse SHALL drop an exception if both realm and principal fields are specified in config.xml. + """ + ch_nodes = self.context.ch_nodes + config_path = f"kerberos/configs/{ch_nodes[0].name}/config.d/kerberos.xml" + + def modify_file(root): + krb = root.find('kerberos') + xml_append(krb, 'principal', 'HTTP/srv1@EXAMPLE.COM') + return root + + check_wrong_config(node=ch_nodes[0], client=ch_nodes[2], config_path=config_path, modify_file=modify_file, + log_error="Realm and principal name cannot be specified simultaneously", + output="Kerberos is not enabled") + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Configuration_MultipleRealmSections("1.0") +) +def multiple_realm(self): + """ClickHouse SHALL throw an exception and disable Kerberos if more than one realm is specified in config.xml. + """ + ch_nodes = self.context.ch_nodes + config_path = f"kerberos/configs/{ch_nodes[0].name}/config.d/kerberos.xml" + + def modify_file(root): + krb = root.find('kerberos') + xml_append(krb, 'realm', 'EXAM.COM') + return root + + check_wrong_config(node=ch_nodes[0], client=ch_nodes[2], config_path=config_path, modify_file=modify_file, + log_error="Multiple realm sections are not allowed") + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Configuration_MultiplePrincipalSections("1.0") +) +def multiple_principal(self): + """ClickHouse SHALL throw an exception and disable Kerberos if more than one principal is specified in config.xml. + """ + ch_nodes = self.context.ch_nodes + config_path = f"kerberos/configs/{ch_nodes[0].name}/config.d/kerberos.xml" + + def modify_file(root): + krb = root.find('kerberos') + krb.remove(krb.find('realm')) + xml_append(krb, 'principal', 'HTTP/s1@EXAMPLE.COM') + xml_append(krb, 'principal', 'HTTP/s2@EXAMPLE.COM') + return root + + check_wrong_config(node=ch_nodes[0], client=ch_nodes[2], config_path=config_path, modify_file=modify_file, + log_error="Multiple principal sections are not allowed") + + + + + + + +@TestFeature +def config(self): + """Perform ClickHouse Kerberos authentication testing for incorrect configuration files + """ + + self.context.ch_nodes = [self.context.cluster.node(f"clickhouse{i}") for i in range(1, 4)] + self.context.krb_server = self.context.cluster.node("kerberos") + self.context.clients = [self.context.cluster.node(f"krb-client{i}") for i in range(1, 6)] + + for scenario in loads(current_module(), Scenario, Suite): + Scenario(run=scenario, flags=TE) diff --git a/tests/testflows/kerberos/tests/generic.py b/tests/testflows/kerberos/tests/generic.py new file mode 100644 index 00000000000..3276fd5ec5f --- /dev/null +++ b/tests/testflows/kerberos/tests/generic.py @@ -0,0 +1,332 @@ +from testflows.core import * +from kerberos.tests.common import * +from kerberos.requirements.requirements import * + +import time +import datetime +import itertools + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_ValidUser_XMLConfiguredUser("1.0") +) +def xml_configured_user(self): + """ClickHouse SHALL accept Kerberos authentication for valid XML-configured user + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for client"): + kinit_no_keytab(node=ch_nodes[2]) + + with And("kinit for server"): + create_server_principal(node=ch_nodes[0]) + + with When("I attempt to authenticate"): + r = ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])) + + with Then(f"I expect 'kerberos_user'"): + assert r.output == "kerberos_user", error() + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_ValidUser_RBACConfiguredUser("1.0") +) +def rbac_configured_user(self): + """ClickHouse SHALL accept Kerberos authentication for valid RBAC-configured user + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for client"): + kinit_no_keytab(node=ch_nodes[2], principal="krb_rbac") + + with And("kinit for server"): + create_server_principal(node=ch_nodes[0]) + + with When("I create a RBAC user"): + ch_nodes[0].query("CREATE USER krb_rbac IDENTIFIED WITH kerberos REALM 'EXAMPLE.COM'") + + with When("I attempt to authenticate"): + r = ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])) + + with Then("I restore server original state"): + ch_nodes[0].query("DROP USER krb_rbac") + + with Finally("I expect 'krb_rbac'"): + assert r.output == "krb_rbac", error() + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_KerberosNotAvailable_InvalidServerTicket("1.0") +) +def invalid_server_ticket(self): + """ClickHouse SHALL reject Kerberos authentication no Kerberos server is reachable + and CH-server has no valid ticket (or the existing ticket is outdated). + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for client"): + kinit_no_keytab(node=ch_nodes[2]) + + with And("setting up server principal"): + create_server_principal(node=ch_nodes[0]) + + with And("I kill kerberos-server"): + self.context.krb_server.stop() + + with When("I attempt to authenticate as kerberos_user"): + r = ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])) + + with Then("I start kerberos server again"): + self.context.krb_server.start() + ch_nodes[2].cmd("kdestroy") + while True: + kinit_no_keytab(node=ch_nodes[2]) + if ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])).output == "kerberos_user": + break + ch_nodes[2].cmd("kdestroy") + + with And("I expect the user to be default"): + assert r.output == "default", error() + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_KerberosNotAvailable_InvalidClientTicket("1.0") +) +def invalid_client_ticket(self): + """ClickHouse SHALL reject Kerberos authentication no Kerberos server is reachable + and client has no valid ticket (or the existing ticket is outdated). + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for client"): + kinit_no_keytab(node=ch_nodes[2], lifetime_option="-l 00:00:05") + + with And("setting up server principal"): + create_server_principal(node=ch_nodes[0]) + + with And("I kill kerberos-server"): + self.context.krb_server.stop() + + with And("I wait until client ticket is expired"): + time.sleep(10) + + with When("I attempt to authenticate as kerberos_user"): + r = ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])) + + with Then("I expect the user to be default"): + assert r.output == "default", error() + + with Finally("I start kerberos server again"): + self.context.krb_server.start() + ch_nodes[2].cmd("kdestroy") + while True: + kinit_no_keytab(node=ch_nodes[2]) + if ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])).output == "kerberos_user": + break + ch_nodes[2].cmd("kdestroy") + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_KerberosNotAvailable_ValidTickets("1.0") +) +def kerberos_unreachable_valid_tickets(self): + """ClickHouse SHALL accept Kerberos authentication if no Kerberos server is reachable + but both CH-server and client have valid tickets. + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for client"): + kinit_no_keytab(node=ch_nodes[2]) + + with And("setting up server principal"): + create_server_principal(node=ch_nodes[0]) + + with And("make sure server obtained ticket"): + ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])) + + with And("I kill kerberos-server"): + self.context.krb_server.stop() + + with When("I attempt to authenticate as kerberos_user"): + r = ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])) + + with Then("I expect the user to be default"): + assert r.output == "kerberos_user", error() + + with Finally("I start kerberos server again"): + self.context.krb_server.start() + ch_nodes[2].cmd("kdestroy") + while True: + kinit_no_keytab(node=ch_nodes[2]) + if ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])).output == "kerberos_user": + break + ch_nodes[2].cmd("kdestroy") + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_ValidUser_KerberosNotConfigured("1.0") +) +def kerberos_not_configured(self): + """ClickHouse SHALL reject Kerberos authentication if user is not a kerberos-auth user. + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for client"): + kinit_no_keytab(node=ch_nodes[2], principal="unkerberized") + + with And('Kinit for server'): + create_server_principal(node=ch_nodes[0]) + + with By("I add non-Kerberos user to ClickHouse"): + ch_nodes[0].query("CREATE USER unkerberized IDENTIFIED WITH plaintext_password BY 'qwerty'") + + with When("I attempt to authenticate"): + r = ch_nodes[2].cmd(test_select_query(node=ch_nodes[0]), no_checks=True) + + with Then("I expect authentication failure"): + assert "Authentication failed" in r.output, error() + + with Finally("I drop the user"): + ch_nodes[0].query("DROP USER unkerberized") + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_KerberosServerRestarted("1.0") +) +def kerberos_server_restarted(self): + """ClickHouse SHALL accept Kerberos authentication if Kerberos server was restarted. + """ + ch_nodes = self.context.ch_nodes + krb_server = self.context.krb_server + + with Given("I obtain keytab for user"): + kinit_no_keytab(node=ch_nodes[2]) + with And("I create server principal"): + create_server_principal(node=ch_nodes[0]) + with And("I obtain server ticket"): + ch_nodes[2].cmd(test_select_query(node=ch_nodes[0]), no_checks=True) + with By("I dump, restart and restore kerberos server"): + krb_server.cmd("kdb5_util dump dump.dmp", shell_command="/bin/sh") + krb_server.restart() + krb_server.cmd("kdb5_util load dump.dmp", shell_command="/bin/sh") + + with When("I attempt to authenticate"): + r = ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])) + + with And("I wait for kerberos to be healthy"): + ch_nodes[2].cmd("kdestroy") + while True: + kinit_no_keytab(node=ch_nodes[2]) + if ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])).output == "kerberos_user": + break + + with Then(f"I expect kerberos_user"): + assert r.output == "kerberos_user", error() + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_InvalidUser("1.0") +) +def invalid_user(self): + """ClickHouse SHALL reject Kerberos authentication for invalid principal + """ + ch_nodes = self.context.ch_nodes + + with Given("I obtain keytab for invalid user"): + kinit_no_keytab(node=ch_nodes[2], principal="invalid") + + with And("I create server principal"): + create_server_principal(node=ch_nodes[0]) + + with When("I attempt to authenticate"): + r = ch_nodes[2].cmd(test_select_query(node=ch_nodes[0]), no_checks=True) + + with Then(f"I expect default"): + assert "Authentication failed: password is incorrect or there is no user with such name" in r.output, error() + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_InvalidUser_UserDeleted("1.0") +) +def user_deleted(self): + """ClickHouse SHALL reject Kerberos authentication if Kerberos user was deleted prior to query. + """ + ch_nodes = self.context.ch_nodes + + with Given("I obtain keytab for a user"): + kinit_no_keytab(node=ch_nodes[2], principal="krb_rbac") + + with And("I create server principal"): + create_server_principal(node=ch_nodes[0]) + + with And("I create and then delete kerberized user"): + ch_nodes[0].query("CREATE USER krb_rbac IDENTIFIED WITH kerberos REALM 'EXAMPLE.COM'") + ch_nodes[0].query("DROP USER krb_rbac") + + with When("I attempt to authenticate"): + r = ch_nodes[2].cmd(test_select_query(node=ch_nodes[0]), no_checks=True) + + with Then(f"I expect error"): + assert "Authentication failed: password is incorrect or there is no user with such name" in r.output, error() + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Performance("1.0") +) +def authentication_performance(self): + """ClickHouse's performance for Kerberos authentication SHALL shall be comparable to regular authentication. + """ + ch_nodes = self.context.ch_nodes + + with Given("I obtain keytab for a user"): + kinit_no_keytab(node=ch_nodes[2]) + + with And("I create server principal"): + create_server_principal(node=ch_nodes[0]) + + with And("I create a password-identified user"): + ch_nodes[0].query("CREATE USER pwd_user IDENTIFIED WITH plaintext_password BY 'pwd'") + + with When("I measure kerberos auth time"): + start_time_krb = time.time() + for i in range(100): + ch_nodes[2].cmd(test_select_query(node=ch_nodes[0])) + krb_time = (time.time() - start_time_krb) / 100 + + with And("I measure password auth time"): + start_time_usual = time.time() + for i in range(100): + ch_nodes[2].cmd(f"echo 'SELECT 1' | curl 'http://pwd_user:pwd@clickhouse1:8123/' -d @-") + usual_time = (time.time() - start_time_usual) / 100 + + with Then("measuring the performance compared to password auth"): + metric("percentage_improvement", units="%", value=100*(krb_time - usual_time)/usual_time) + + with Finally("I drop pwd_user"): + ch_nodes[0].query("DROP USER pwd_user") + + + + + +@TestFeature +def generic(self): + """Perform ClickHouse Kerberos authentication testing + """ + + self.context.ch_nodes = [self.context.cluster.node(f"clickhouse{i}") for i in range(1, 4)] + self.context.krb_server = self.context.cluster.node("kerberos") + self.context.clients = [self.context.cluster.node(f"krb-client{i}") for i in range(1, 6)] + + for scenario in loads(current_module(), Scenario, Suite): + Scenario(run=scenario, flags=TE) diff --git a/tests/testflows/kerberos/tests/parallel.py b/tests/testflows/kerberos/tests/parallel.py new file mode 100644 index 00000000000..694245e524c --- /dev/null +++ b/tests/testflows/kerberos/tests/parallel.py @@ -0,0 +1,204 @@ +from testflows.core import * +from kerberos.tests.common import * +from kerberos.requirements.requirements import * +from multiprocessing.dummy import Pool + +import time +import datetime +import itertools + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Parallel_ValidRequests_SameCredentials("1.0") +) +def valid_requests_same_credentials(self): + """ClickHouse should be able to process parallel requests sent under the same credentials. + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for clients"): + kinit_no_keytab(node=ch_nodes[1]) + kinit_no_keytab(node=ch_nodes[2]) + + with And('create server principal'): + create_server_principal(node=ch_nodes[0]) + + def helper(cmd): + return cmd(test_select_query(node=ch_nodes[0])) + + for i in range(15): + pool = Pool(2) + tasks = [] + with When("I try simultaneous authentication"): + tasks.append(pool.apply_async(helper, (ch_nodes[1].cmd, ))) + tasks.append(pool.apply_async(helper, (ch_nodes[2].cmd, ))) + tasks[0].wait(timeout=200) + tasks[1].wait(timeout=200) + + with Then(f"I expect requests to success"): + assert tasks[0].get(timeout=300).output == "kerberos_user", error() + assert tasks[1].get(timeout=300).output == "kerberos_user", error() + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Parallel_ValidRequests_DifferentCredentials("1.0") +) +def valid_requests_different_credentials(self): + """ClickHouse should be able to process parallel requests by different users. + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for clients"): + kinit_no_keytab(node=ch_nodes[1], principal="krb1") + kinit_no_keytab(node=ch_nodes[2], principal="krb2") + + with And("create server principal"): + create_server_principal(node=ch_nodes[0]) + + def helper(cmd): + return cmd(test_select_query(node=ch_nodes[0])) + + for i in range(15): + pool = Pool(2) + tasks = [] + + with And("add 2 kerberos users via RBAC"): + ch_nodes[0].query("CREATE USER krb1 IDENTIFIED WITH kerberos REALM 'EXAMPLE.COM'") + ch_nodes[0].query("CREATE USER krb2 IDENTIFIED WITH kerberos REALM 'EXAMPLE.COM'") + + with When("I try simultaneous authentication for valid and invalid"): + tasks.append(pool.apply_async(helper, (ch_nodes[1].cmd, ))) + tasks.append(pool.apply_async(helper, (ch_nodes[2].cmd, ))) + tasks[0].wait(timeout=200) + tasks[1].wait(timeout=200) + + with Then(f"I expect have auth failure"): + assert tasks[1].get(timeout=300).output == "krb2", error() + assert tasks[0].get(timeout=300).output == "krb1", error() + + with Finally("I make sure both users are removed"): + ch_nodes[0].query("DROP USER krb1", no_checks=True) + ch_nodes[0].query("DROP USER krb2", no_checks=True) + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Parallel_ValidInvalid("1.0") +) +def valid_invalid(self): + """Valid users' Kerberos authentication should not be affected by invalid users' attempts. + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for clients"): + kinit_no_keytab(node=ch_nodes[2]) + kinit_no_keytab(node=ch_nodes[1], principal="invalid_user") + + with And('create server principal'): + create_server_principal(node=ch_nodes[0]) + + def helper(cmd): + return cmd(test_select_query(node=ch_nodes[0]), no_checks=True) + + for i in range(15): + pool = Pool(2) + tasks = [] + with When("I try simultaneous authentication for valid and invalid"): + tasks.append(pool.apply_async(helper, (ch_nodes[1].cmd, ))) # invalid + tasks.append(pool.apply_async(helper, (ch_nodes[2].cmd, ))) # valid + + with Then(f"I expect have auth failure"): + assert tasks[1].get(timeout=300).output == "kerberos_user", error() + assert tasks[0].get(timeout=300).output != "kerberos_user", error() + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Parallel_Deletion("1.0") +) +def deletion(self): + """ClickHouse SHALL NOT crash when 2 Kerberos users are simultaneously deleting one another. + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for clients"): + kinit_no_keytab(node=ch_nodes[1], principal="krb1") + kinit_no_keytab(node=ch_nodes[2], principal="krb2") + + with And("create server principal"): + create_server_principal(node=ch_nodes[0]) + + def helper(cmd, todel): + return cmd(test_select_query(node=ch_nodes[0], req=f"DROP USER {todel}"), no_checks=True) + + for i in range(15): + pool = Pool(2) + tasks = [] + + with And("add 2 kerberos users via RBAC"): + ch_nodes[0].query("CREATE USER krb1 IDENTIFIED WITH kerberos REALM 'EXAMPLE.COM'") + ch_nodes[0].query("CREATE USER krb2 IDENTIFIED WITH kerberos REALM 'EXAMPLE.COM'") + ch_nodes[0].query("GRANT ACCESS MANAGEMENT ON *.* TO krb1") + ch_nodes[0].query("GRANT ACCESS MANAGEMENT ON *.* TO krb2") + + + with When("I try simultaneous authentication for valid and invalid"): + tasks.append(pool.apply_async(helper, (ch_nodes[1].cmd, "krb2"))) + tasks.append(pool.apply_async(helper, (ch_nodes[2].cmd, "krb1"))) + tasks[0].wait(timeout=200) + tasks[1].wait(timeout=200) + + with Then(f"I check CH is alive"): + assert ch_nodes[0].query("SELECT 1").output == "1", error() + + with Finally("I make sure both users are removed"): + ch_nodes[0].query("DROP USER krb1", no_checks=True) + ch_nodes[0].query("DROP USER krb2", no_checks=True) + + +@TestScenario +@Requirements( + RQ_SRS_016_Kerberos_Parallel_ValidRequests_KerberosAndNonKerberos("1.0") +) +def kerberos_and_nonkerberos(self): + """ClickHouse SHALL support processing of simultaneous kerberized and non-kerberized requests. + """ + ch_nodes = self.context.ch_nodes + + with Given("kinit for clients"): + kinit_no_keytab(node=ch_nodes[2]) + + with And('create server principal'): + create_server_principal(node=ch_nodes[0]) + + def helper(cmd, krb_auth): + return cmd(test_select_query(node=ch_nodes[0], krb_auth=krb_auth), no_checks=True) + + for i in range(15): + pool = Pool(2) + tasks = [] + with When("I try simultaneous authentication for valid and invalid"): + tasks.append(pool.apply_async(helper, (ch_nodes[1].cmd, False))) # non-kerberos + tasks.append(pool.apply_async(helper, (ch_nodes[2].cmd, True))) # kerberos + + with Then(f"I expect have auth failure"): + assert tasks[1].get(timeout=300).output == "kerberos_user", error() + assert tasks[0].get(timeout=300).output == "default", error() + + +@TestFeature +@Requirements( + RQ_SRS_016_Kerberos_Parallel("1.0") +) +def parallel(self): + """Perform ClickHouse Kerberos authentication testing for incorrect configuration files + """ + + self.context.ch_nodes = [self.context.cluster.node(f"clickhouse{i}") for i in range(1, 4)] + self.context.krb_server = self.context.cluster.node("kerberos") + self.context.clients = [self.context.cluster.node(f"krb-client{i}") for i in range(1, 6)] + + for scenario in loads(current_module(), Scenario, Suite): + Scenario(run=scenario, flags=TE) diff --git a/tests/testflows/ldap/authentication/configs/clickhouse/config.xml b/tests/testflows/ldap/authentication/configs/clickhouse/config.xml index e28a0c8e255..3db8338b865 100644 --- a/tests/testflows/ldap/authentication/configs/clickhouse/config.xml +++ b/tests/testflows/ldap/authentication/configs/clickhouse/config.xml @@ -412,7 +412,7 @@ 86400 - 60 + 7200 diff --git a/tests/testflows/ldap/authentication/requirements/requirements.md b/tests/testflows/ldap/authentication/requirements/requirements.md index 27ce8c921a0..e27a0ca14f7 100644 --- a/tests/testflows/ldap/authentication/requirements/requirements.md +++ b/tests/testflows/ldap/authentication/requirements/requirements.md @@ -468,7 +468,7 @@ version: 1.0 the following RBAC command ```sql -CREATE USER name IDENTIFIED WITH ldap_server BY 'server_name' +CREATE USER name IDENTIFIED WITH ldap SERVER 'server_name' ``` #### RQ.SRS-007.LDAP.Configuration.User.Syntax diff --git a/tests/testflows/ldap/authentication/requirements/requirements.py b/tests/testflows/ldap/authentication/requirements/requirements.py index 25b943d18c2..2437711dd22 100644 --- a/tests/testflows/ldap/authentication/requirements/requirements.py +++ b/tests/testflows/ldap/authentication/requirements/requirements.py @@ -903,7 +903,7 @@ RQ_SRS_007_LDAP_Configuration_User_RBAC = Requirement( 'the following RBAC command\n' '\n' '```sql\n' - "CREATE USER name IDENTIFIED WITH ldap_server BY 'server_name'\n" + "CREATE USER name IDENTIFIED WITH ldap SERVER 'server_name'\n" '```\n' '\n' ), @@ -1841,7 +1841,7 @@ version: 1.0 the following RBAC command ```sql -CREATE USER name IDENTIFIED WITH ldap_server BY 'server_name' +CREATE USER name IDENTIFIED WITH ldap SERVER 'server_name' ``` #### RQ.SRS-007.LDAP.Configuration.User.Syntax diff --git a/tests/testflows/ldap/authentication/tests/common.py b/tests/testflows/ldap/authentication/tests/common.py index 7f9f16e827c..6b6ce0413a4 100644 --- a/tests/testflows/ldap/authentication/tests/common.py +++ b/tests/testflows/ldap/authentication/tests/common.py @@ -248,7 +248,7 @@ def add_users_identified_with_ldap(*users): try: with Given("I create users"): for user in users: - node.query(f"CREATE USER '{user['username']}' IDENTIFIED WITH ldap_server BY '{user['server']}'") + node.query(f"CREATE USER '{user['username']}' IDENTIFIED WITH ldap SERVER '{user['server']}'") yield finally: with Finally("I remove users"): diff --git a/tests/testflows/rbac/configs/clickhouse/config.xml b/tests/testflows/rbac/configs/clickhouse/config.xml index 4ec12232539..265bcd1882a 100644 --- a/tests/testflows/rbac/configs/clickhouse/config.xml +++ b/tests/testflows/rbac/configs/clickhouse/config.xml @@ -418,7 +418,7 @@ 86400 - 60 + 7200 diff --git a/tests/testflows/rbac/docker-compose/clickhouse-service.yml b/tests/testflows/rbac/docker-compose/clickhouse-service.yml index d5f981ca8b7..2d79443dcbb 100755 --- a/tests/testflows/rbac/docker-compose/clickhouse-service.yml +++ b/tests/testflows/rbac/docker-compose/clickhouse-service.yml @@ -20,7 +20,7 @@ services: test: clickhouse client --query='select 1' interval: 10s timeout: 10s - retries: 10 + retries: 3 start_period: 300s cap_add: - SYS_PTRACE diff --git a/tests/testflows/rbac/docker-compose/zookeeper-service.yml b/tests/testflows/rbac/docker-compose/zookeeper-service.yml index f27405b97a2..f3df33358be 100755 --- a/tests/testflows/rbac/docker-compose/zookeeper-service.yml +++ b/tests/testflows/rbac/docker-compose/zookeeper-service.yml @@ -2,7 +2,7 @@ version: '2.3' services: zookeeper: - image: zookeeper:3.6.2 + image: zookeeper:3.4.12 expose: - "2181" environment: diff --git a/tests/testflows/rbac/helper/common.py b/tests/testflows/rbac/helper/common.py index 47e38560714..c140e01f34f 100755 --- a/tests/testflows/rbac/helper/common.py +++ b/tests/testflows/rbac/helper/common.py @@ -2,6 +2,7 @@ import uuid from contextlib import contextmanager from multiprocessing.dummy import Pool +from multiprocessing import TimeoutError as PoolTaskTimeoutError from testflows.core.name import basename, parentname from testflows._core.testtype import TestSubType @@ -30,6 +31,9 @@ def instrument_clickhouse_server_log(self, node=None, clickhouse_server_log="/va yield finally: + if self.context.cluster.terminating is True: + return + with Finally("adding test name end message to the clickhouse-server.log", flags=TE): node.command(f"echo -e \"\\n-- end: {current().name} --\\n\" >> {clickhouse_server_log}") @@ -38,14 +42,20 @@ def instrument_clickhouse_server_log(self, node=None, clickhouse_server_log="/va with Then("dumping clickhouse-server.log for this test"): node.command(f"tail -c +{logsize} {clickhouse_server_log}") -def join(tasks): +def join(tasks, polling_timeout=5): """Join all parallel tests. """ exc = None while tasks: try: - tasks[0].get() - tasks.pop(0) + try: + tasks[0].get(timeout=polling_timeout) + tasks.pop(0) + + except PoolTaskTimeoutError as e: + task = tasks.pop(0) + tasks.append(task) + continue except KeyboardInterrupt as e: current().context.cluster.terminating = True @@ -133,6 +143,23 @@ def role(node, role): for role in roles: with Finally("I drop the role"): node.query(f"DROP ROLE IF EXISTS {role}") + +@TestStep(Given) +def row_policy(self, name, table, node=None): + """Create a row policy with a given name on a given table. + """ + if node is None: + node = self.context.node + + try: + with Given(f"I create row policy {name}"): + node.query(f"CREATE ROW POLICY {name} ON {table}") + yield + + finally: + with Finally(f"I delete row policy {name}"): + node.query(f"DROP ROW POLICY IF EXISTS {name} ON {table}") + tables = { "table0" : 1 << 0, "table1" : 1 << 1, diff --git a/tests/testflows/rbac/regression.py b/tests/testflows/rbac/regression.py index e89be3bab20..a07cb8da805 100755 --- a/tests/testflows/rbac/regression.py +++ b/tests/testflows/rbac/regression.py @@ -27,6 +27,8 @@ issue_17655 = "https://github.com/ClickHouse/ClickHouse/issues/17655" issue_17766 = "https://github.com/ClickHouse/ClickHouse/issues/17766" issue_18110 = "https://github.com/ClickHouse/ClickHouse/issues/18110" issue_18206 = "https://github.com/ClickHouse/ClickHouse/issues/18206" +issue_21083 = "https://github.com/ClickHouse/ClickHouse/issues/21083" +issue_21084 = "https://github.com/ClickHouse/ClickHouse/issues/21084" xfails = { "syntax/show create quota/I show create quota current": @@ -131,6 +133,10 @@ xfails = { [(Fail, issue_18206)], "privileges/system replication queues/:/:/:/:/SYSTEM:": [(Fail, issue_18206)], + "privileges/: row policy/nested live:": + [(Fail, issue_21083)], + "privileges/: row policy/nested mat:": + [(Fail, issue_21084)], } xflags = { @@ -160,9 +166,9 @@ def regression(self, local, clickhouse_binary_path, stress=None, parallel=None): if parallel is not None: self.context.parallel = parallel - Feature(run=load("rbac.tests.syntax.feature", "feature"), flags=TE) - Feature(run=load("rbac.tests.privileges.feature", "feature"), flags=TE) - Feature(run=load("rbac.tests.views.feature", "feature"), flags=TE) + Feature(run=load("rbac.tests.syntax.feature", "feature")) + Feature(run=load("rbac.tests.privileges.feature", "feature")) + Feature(run=load("rbac.tests.views.feature", "feature")) if main(): regression() diff --git a/tests/testflows/rbac/requirements/requirements.md b/tests/testflows/rbac/requirements/requirements.md index ae6a038c15e..163417e1617 100644 --- a/tests/testflows/rbac/requirements/requirements.md +++ b/tests/testflows/rbac/requirements/requirements.md @@ -9,556 +9,588 @@ * 5 [Requirements](#requirements) * 5.1 [Generic](#generic) * 5.1.1 [RQ.SRS-006.RBAC](#rqsrs-006rbac) - * 5.1.2 [Login](#login) - * 5.1.2.1 [RQ.SRS-006.RBAC.Login](#rqsrs-006rbaclogin) - * 5.1.2.2 [RQ.SRS-006.RBAC.Login.DefaultUser](#rqsrs-006rbaclogindefaultuser) - * 5.1.3 [User](#user) - * 5.1.3.1 [RQ.SRS-006.RBAC.User](#rqsrs-006rbacuser) - * 5.1.3.2 [RQ.SRS-006.RBAC.User.Roles](#rqsrs-006rbacuserroles) - * 5.1.3.3 [RQ.SRS-006.RBAC.User.Privileges](#rqsrs-006rbacuserprivileges) - * 5.1.3.4 [RQ.SRS-006.RBAC.User.Variables](#rqsrs-006rbacuservariables) - * 5.1.3.5 [RQ.SRS-006.RBAC.User.Variables.Constraints](#rqsrs-006rbacuservariablesconstraints) - * 5.1.3.6 [RQ.SRS-006.RBAC.User.SettingsProfile](#rqsrs-006rbacusersettingsprofile) - * 5.1.3.7 [RQ.SRS-006.RBAC.User.Quotas](#rqsrs-006rbacuserquotas) - * 5.1.3.8 [RQ.SRS-006.RBAC.User.RowPolicies](#rqsrs-006rbacuserrowpolicies) - * 5.1.3.9 [RQ.SRS-006.RBAC.User.AccountLock](#rqsrs-006rbacuseraccountlock) - * 5.1.3.10 [RQ.SRS-006.RBAC.User.AccountLock.DenyAccess](#rqsrs-006rbacuseraccountlockdenyaccess) - * 5.1.3.11 [RQ.SRS-006.RBAC.User.DefaultRole](#rqsrs-006rbacuserdefaultrole) - * 5.1.3.12 [RQ.SRS-006.RBAC.User.RoleSelection](#rqsrs-006rbacuserroleselection) - * 5.1.3.13 [RQ.SRS-006.RBAC.User.ShowCreate](#rqsrs-006rbacusershowcreate) - * 5.1.3.14 [RQ.SRS-006.RBAC.User.ShowPrivileges](#rqsrs-006rbacusershowprivileges) - * 5.1.4 [Role](#role) - * 5.1.4.1 [RQ.SRS-006.RBAC.Role](#rqsrs-006rbacrole) - * 5.1.4.2 [RQ.SRS-006.RBAC.Role.Privileges](#rqsrs-006rbacroleprivileges) - * 5.1.4.3 [RQ.SRS-006.RBAC.Role.Variables](#rqsrs-006rbacrolevariables) - * 5.1.4.4 [RQ.SRS-006.RBAC.Role.SettingsProfile](#rqsrs-006rbacrolesettingsprofile) - * 5.1.4.5 [RQ.SRS-006.RBAC.Role.Quotas](#rqsrs-006rbacrolequotas) - * 5.1.4.6 [RQ.SRS-006.RBAC.Role.RowPolicies](#rqsrs-006rbacrolerowpolicies) - * 5.1.5 [Partial Revokes](#partial-revokes) - * 5.1.5.1 [RQ.SRS-006.RBAC.PartialRevokes](#rqsrs-006rbacpartialrevokes) - * 5.1.6 [Settings Profile](#settings-profile) - * 5.1.6.1 [RQ.SRS-006.RBAC.SettingsProfile](#rqsrs-006rbacsettingsprofile) - * 5.1.6.2 [RQ.SRS-006.RBAC.SettingsProfile.Constraints](#rqsrs-006rbacsettingsprofileconstraints) - * 5.1.6.3 [RQ.SRS-006.RBAC.SettingsProfile.ShowCreate](#rqsrs-006rbacsettingsprofileshowcreate) - * 5.1.7 [Quotas](#quotas) - * 5.1.7.1 [RQ.SRS-006.RBAC.Quotas](#rqsrs-006rbacquotas) - * 5.1.7.2 [RQ.SRS-006.RBAC.Quotas.Keyed](#rqsrs-006rbacquotaskeyed) - * 5.1.7.3 [RQ.SRS-006.RBAC.Quotas.Queries](#rqsrs-006rbacquotasqueries) - * 5.1.7.4 [RQ.SRS-006.RBAC.Quotas.Errors](#rqsrs-006rbacquotaserrors) - * 5.1.7.5 [RQ.SRS-006.RBAC.Quotas.ResultRows](#rqsrs-006rbacquotasresultrows) - * 5.1.7.6 [RQ.SRS-006.RBAC.Quotas.ReadRows](#rqsrs-006rbacquotasreadrows) - * 5.1.7.7 [RQ.SRS-006.RBAC.Quotas.ResultBytes](#rqsrs-006rbacquotasresultbytes) - * 5.1.7.8 [RQ.SRS-006.RBAC.Quotas.ReadBytes](#rqsrs-006rbacquotasreadbytes) - * 5.1.7.9 [RQ.SRS-006.RBAC.Quotas.ExecutionTime](#rqsrs-006rbacquotasexecutiontime) - * 5.1.7.10 [RQ.SRS-006.RBAC.Quotas.ShowCreate](#rqsrs-006rbacquotasshowcreate) - * 5.1.8 [Row Policy](#row-policy) - * 5.1.8.1 [RQ.SRS-006.RBAC.RowPolicy](#rqsrs-006rbacrowpolicy) - * 5.1.8.2 [RQ.SRS-006.RBAC.RowPolicy.Condition](#rqsrs-006rbacrowpolicycondition) - * 5.1.8.3 [RQ.SRS-006.RBAC.RowPolicy.ShowCreate](#rqsrs-006rbacrowpolicyshowcreate) - * 5.2 [Specific](#specific) - * 5.2.8.1 [RQ.SRS-006.RBAC.User.Use.DefaultRole](#rqsrs-006rbacuserusedefaultrole) - * 5.2.8.2 [RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole](#rqsrs-006rbacuseruseallroleswhennodefaultrole) - * 5.2.8.3 [RQ.SRS-006.RBAC.User.Create](#rqsrs-006rbacusercreate) - * 5.2.8.4 [RQ.SRS-006.RBAC.User.Create.IfNotExists](#rqsrs-006rbacusercreateifnotexists) - * 5.2.8.5 [RQ.SRS-006.RBAC.User.Create.Replace](#rqsrs-006rbacusercreatereplace) - * 5.2.8.6 [RQ.SRS-006.RBAC.User.Create.Password.NoPassword](#rqsrs-006rbacusercreatepasswordnopassword) - * 5.2.8.7 [RQ.SRS-006.RBAC.User.Create.Password.NoPassword.Login](#rqsrs-006rbacusercreatepasswordnopasswordlogin) - * 5.2.8.8 [RQ.SRS-006.RBAC.User.Create.Password.PlainText](#rqsrs-006rbacusercreatepasswordplaintext) - * 5.2.8.9 [RQ.SRS-006.RBAC.User.Create.Password.PlainText.Login](#rqsrs-006rbacusercreatepasswordplaintextlogin) - * 5.2.8.10 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Password](#rqsrs-006rbacusercreatepasswordsha256password) - * 5.2.8.11 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Password.Login](#rqsrs-006rbacusercreatepasswordsha256passwordlogin) - * 5.2.8.12 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash](#rqsrs-006rbacusercreatepasswordsha256hash) - * 5.2.8.13 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash.Login](#rqsrs-006rbacusercreatepasswordsha256hashlogin) - * 5.2.8.14 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password](#rqsrs-006rbacusercreatepassworddoublesha1password) - * 5.2.8.15 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password.Login](#rqsrs-006rbacusercreatepassworddoublesha1passwordlogin) - * 5.2.8.16 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash](#rqsrs-006rbacusercreatepassworddoublesha1hash) - * 5.2.8.17 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash.Login](#rqsrs-006rbacusercreatepassworddoublesha1hashlogin) - * 5.2.8.18 [RQ.SRS-006.RBAC.User.Create.Host.Name](#rqsrs-006rbacusercreatehostname) - * 5.2.8.19 [RQ.SRS-006.RBAC.User.Create.Host.Regexp](#rqsrs-006rbacusercreatehostregexp) - * 5.2.8.20 [RQ.SRS-006.RBAC.User.Create.Host.IP](#rqsrs-006rbacusercreatehostip) - * 5.2.8.21 [RQ.SRS-006.RBAC.User.Create.Host.Any](#rqsrs-006rbacusercreatehostany) - * 5.2.8.22 [RQ.SRS-006.RBAC.User.Create.Host.None](#rqsrs-006rbacusercreatehostnone) - * 5.2.8.23 [RQ.SRS-006.RBAC.User.Create.Host.Local](#rqsrs-006rbacusercreatehostlocal) - * 5.2.8.24 [RQ.SRS-006.RBAC.User.Create.Host.Like](#rqsrs-006rbacusercreatehostlike) - * 5.2.8.25 [RQ.SRS-006.RBAC.User.Create.Host.Default](#rqsrs-006rbacusercreatehostdefault) - * 5.2.8.26 [RQ.SRS-006.RBAC.User.Create.DefaultRole](#rqsrs-006rbacusercreatedefaultrole) - * 5.2.8.27 [RQ.SRS-006.RBAC.User.Create.DefaultRole.None](#rqsrs-006rbacusercreatedefaultrolenone) - * 5.2.8.28 [RQ.SRS-006.RBAC.User.Create.DefaultRole.All](#rqsrs-006rbacusercreatedefaultroleall) - * 5.2.8.29 [RQ.SRS-006.RBAC.User.Create.Settings](#rqsrs-006rbacusercreatesettings) - * 5.2.8.30 [RQ.SRS-006.RBAC.User.Create.OnCluster](#rqsrs-006rbacusercreateoncluster) - * 5.2.8.31 [RQ.SRS-006.RBAC.User.Create.Syntax](#rqsrs-006rbacusercreatesyntax) - * 5.2.8.32 [RQ.SRS-006.RBAC.User.Alter](#rqsrs-006rbacuseralter) - * 5.2.8.33 [RQ.SRS-006.RBAC.User.Alter.OrderOfEvaluation](#rqsrs-006rbacuseralterorderofevaluation) - * 5.2.8.34 [RQ.SRS-006.RBAC.User.Alter.IfExists](#rqsrs-006rbacuseralterifexists) - * 5.2.8.35 [RQ.SRS-006.RBAC.User.Alter.Cluster](#rqsrs-006rbacuseraltercluster) - * 5.2.8.36 [RQ.SRS-006.RBAC.User.Alter.Rename](#rqsrs-006rbacuseralterrename) - * 5.2.8.37 [RQ.SRS-006.RBAC.User.Alter.Password.PlainText](#rqsrs-006rbacuseralterpasswordplaintext) - * 5.2.8.38 [RQ.SRS-006.RBAC.User.Alter.Password.Sha256Password](#rqsrs-006rbacuseralterpasswordsha256password) - * 5.2.8.39 [RQ.SRS-006.RBAC.User.Alter.Password.DoubleSha1Password](#rqsrs-006rbacuseralterpassworddoublesha1password) - * 5.2.8.40 [RQ.SRS-006.RBAC.User.Alter.Host.AddDrop](#rqsrs-006rbacuseralterhostadddrop) - * 5.2.8.41 [RQ.SRS-006.RBAC.User.Alter.Host.Local](#rqsrs-006rbacuseralterhostlocal) - * 5.2.8.42 [RQ.SRS-006.RBAC.User.Alter.Host.Name](#rqsrs-006rbacuseralterhostname) - * 5.2.8.43 [RQ.SRS-006.RBAC.User.Alter.Host.Regexp](#rqsrs-006rbacuseralterhostregexp) - * 5.2.8.44 [RQ.SRS-006.RBAC.User.Alter.Host.IP](#rqsrs-006rbacuseralterhostip) - * 5.2.8.45 [RQ.SRS-006.RBAC.User.Alter.Host.Like](#rqsrs-006rbacuseralterhostlike) - * 5.2.8.46 [RQ.SRS-006.RBAC.User.Alter.Host.Any](#rqsrs-006rbacuseralterhostany) - * 5.2.8.47 [RQ.SRS-006.RBAC.User.Alter.Host.None](#rqsrs-006rbacuseralterhostnone) - * 5.2.8.48 [RQ.SRS-006.RBAC.User.Alter.DefaultRole](#rqsrs-006rbacuseralterdefaultrole) - * 5.2.8.49 [RQ.SRS-006.RBAC.User.Alter.DefaultRole.All](#rqsrs-006rbacuseralterdefaultroleall) - * 5.2.8.50 [RQ.SRS-006.RBAC.User.Alter.DefaultRole.AllExcept](#rqsrs-006rbacuseralterdefaultroleallexcept) - * 5.2.8.51 [RQ.SRS-006.RBAC.User.Alter.Settings](#rqsrs-006rbacuseraltersettings) - * 5.2.8.52 [RQ.SRS-006.RBAC.User.Alter.Settings.Min](#rqsrs-006rbacuseraltersettingsmin) - * 5.2.8.53 [RQ.SRS-006.RBAC.User.Alter.Settings.Max](#rqsrs-006rbacuseraltersettingsmax) - * 5.2.8.54 [RQ.SRS-006.RBAC.User.Alter.Settings.Profile](#rqsrs-006rbacuseraltersettingsprofile) - * 5.2.8.55 [RQ.SRS-006.RBAC.User.Alter.Syntax](#rqsrs-006rbacuseraltersyntax) - * 5.2.8.56 [RQ.SRS-006.RBAC.SetDefaultRole](#rqsrs-006rbacsetdefaultrole) - * 5.2.8.57 [RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser](#rqsrs-006rbacsetdefaultrolecurrentuser) - * 5.2.8.58 [RQ.SRS-006.RBAC.SetDefaultRole.All](#rqsrs-006rbacsetdefaultroleall) - * 5.2.8.59 [RQ.SRS-006.RBAC.SetDefaultRole.AllExcept](#rqsrs-006rbacsetdefaultroleallexcept) - * 5.2.8.60 [RQ.SRS-006.RBAC.SetDefaultRole.None](#rqsrs-006rbacsetdefaultrolenone) - * 5.2.8.61 [RQ.SRS-006.RBAC.SetDefaultRole.Syntax](#rqsrs-006rbacsetdefaultrolesyntax) - * 5.2.8.62 [RQ.SRS-006.RBAC.SetRole](#rqsrs-006rbacsetrole) - * 5.2.8.63 [RQ.SRS-006.RBAC.SetRole.Default](#rqsrs-006rbacsetroledefault) - * 5.2.8.64 [RQ.SRS-006.RBAC.SetRole.None](#rqsrs-006rbacsetrolenone) - * 5.2.8.65 [RQ.SRS-006.RBAC.SetRole.All](#rqsrs-006rbacsetroleall) - * 5.2.8.66 [RQ.SRS-006.RBAC.SetRole.AllExcept](#rqsrs-006rbacsetroleallexcept) - * 5.2.8.67 [RQ.SRS-006.RBAC.SetRole.Syntax](#rqsrs-006rbacsetrolesyntax) - * 5.2.8.68 [RQ.SRS-006.RBAC.User.ShowCreateUser](#rqsrs-006rbacusershowcreateuser) - * 5.2.8.69 [RQ.SRS-006.RBAC.User.ShowCreateUser.For](#rqsrs-006rbacusershowcreateuserfor) - * 5.2.8.70 [RQ.SRS-006.RBAC.User.ShowCreateUser.Syntax](#rqsrs-006rbacusershowcreateusersyntax) - * 5.2.8.71 [RQ.SRS-006.RBAC.User.Drop](#rqsrs-006rbacuserdrop) - * 5.2.8.72 [RQ.SRS-006.RBAC.User.Drop.IfExists](#rqsrs-006rbacuserdropifexists) - * 5.2.8.73 [RQ.SRS-006.RBAC.User.Drop.OnCluster](#rqsrs-006rbacuserdroponcluster) - * 5.2.8.74 [RQ.SRS-006.RBAC.User.Drop.Syntax](#rqsrs-006rbacuserdropsyntax) - * 5.2.8.75 [RQ.SRS-006.RBAC.Role.Create](#rqsrs-006rbacrolecreate) - * 5.2.8.76 [RQ.SRS-006.RBAC.Role.Create.IfNotExists](#rqsrs-006rbacrolecreateifnotexists) - * 5.2.8.77 [RQ.SRS-006.RBAC.Role.Create.Replace](#rqsrs-006rbacrolecreatereplace) - * 5.2.8.78 [RQ.SRS-006.RBAC.Role.Create.Settings](#rqsrs-006rbacrolecreatesettings) - * 5.2.8.79 [RQ.SRS-006.RBAC.Role.Create.Syntax](#rqsrs-006rbacrolecreatesyntax) - * 5.2.8.80 [RQ.SRS-006.RBAC.Role.Alter](#rqsrs-006rbacrolealter) - * 5.2.8.81 [RQ.SRS-006.RBAC.Role.Alter.IfExists](#rqsrs-006rbacrolealterifexists) - * 5.2.8.82 [RQ.SRS-006.RBAC.Role.Alter.Cluster](#rqsrs-006rbacrolealtercluster) - * 5.2.8.83 [RQ.SRS-006.RBAC.Role.Alter.Rename](#rqsrs-006rbacrolealterrename) - * 5.2.8.84 [RQ.SRS-006.RBAC.Role.Alter.Settings](#rqsrs-006rbacrolealtersettings) - * 5.2.8.85 [RQ.SRS-006.RBAC.Role.Alter.Syntax](#rqsrs-006rbacrolealtersyntax) - * 5.2.8.86 [RQ.SRS-006.RBAC.Role.Drop](#rqsrs-006rbacroledrop) - * 5.2.8.87 [RQ.SRS-006.RBAC.Role.Drop.IfExists](#rqsrs-006rbacroledropifexists) - * 5.2.8.88 [RQ.SRS-006.RBAC.Role.Drop.Cluster](#rqsrs-006rbacroledropcluster) - * 5.2.8.89 [RQ.SRS-006.RBAC.Role.Drop.Syntax](#rqsrs-006rbacroledropsyntax) - * 5.2.8.90 [RQ.SRS-006.RBAC.Role.ShowCreate](#rqsrs-006rbacroleshowcreate) - * 5.2.8.91 [RQ.SRS-006.RBAC.Role.ShowCreate.Syntax](#rqsrs-006rbacroleshowcreatesyntax) - * 5.2.8.92 [RQ.SRS-006.RBAC.Grant.Privilege.To](#rqsrs-006rbacgrantprivilegeto) - * 5.2.8.93 [RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser](#rqsrs-006rbacgrantprivilegetocurrentuser) - * 5.2.8.94 [RQ.SRS-006.RBAC.Grant.Privilege.Select](#rqsrs-006rbacgrantprivilegeselect) - * 5.2.8.95 [RQ.SRS-006.RBAC.Grant.Privilege.Insert](#rqsrs-006rbacgrantprivilegeinsert) - * 5.2.8.96 [RQ.SRS-006.RBAC.Grant.Privilege.Alter](#rqsrs-006rbacgrantprivilegealter) - * 5.2.8.97 [RQ.SRS-006.RBAC.Grant.Privilege.Create](#rqsrs-006rbacgrantprivilegecreate) - * 5.2.8.98 [RQ.SRS-006.RBAC.Grant.Privilege.Drop](#rqsrs-006rbacgrantprivilegedrop) - * 5.2.8.99 [RQ.SRS-006.RBAC.Grant.Privilege.Truncate](#rqsrs-006rbacgrantprivilegetruncate) - * 5.2.8.100 [RQ.SRS-006.RBAC.Grant.Privilege.Optimize](#rqsrs-006rbacgrantprivilegeoptimize) - * 5.2.8.101 [RQ.SRS-006.RBAC.Grant.Privilege.Show](#rqsrs-006rbacgrantprivilegeshow) - * 5.2.8.102 [RQ.SRS-006.RBAC.Grant.Privilege.KillQuery](#rqsrs-006rbacgrantprivilegekillquery) - * 5.2.8.103 [RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement](#rqsrs-006rbacgrantprivilegeaccessmanagement) - * 5.2.8.104 [RQ.SRS-006.RBAC.Grant.Privilege.System](#rqsrs-006rbacgrantprivilegesystem) - * 5.2.8.105 [RQ.SRS-006.RBAC.Grant.Privilege.Introspection](#rqsrs-006rbacgrantprivilegeintrospection) - * 5.2.8.106 [RQ.SRS-006.RBAC.Grant.Privilege.Sources](#rqsrs-006rbacgrantprivilegesources) - * 5.2.8.107 [RQ.SRS-006.RBAC.Grant.Privilege.DictGet](#rqsrs-006rbacgrantprivilegedictget) - * 5.2.8.108 [RQ.SRS-006.RBAC.Grant.Privilege.None](#rqsrs-006rbacgrantprivilegenone) - * 5.2.8.109 [RQ.SRS-006.RBAC.Grant.Privilege.All](#rqsrs-006rbacgrantprivilegeall) - * 5.2.8.110 [RQ.SRS-006.RBAC.Grant.Privilege.GrantOption](#rqsrs-006rbacgrantprivilegegrantoption) - * 5.2.8.111 [RQ.SRS-006.RBAC.Grant.Privilege.On](#rqsrs-006rbacgrantprivilegeon) - * 5.2.8.112 [RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns](#rqsrs-006rbacgrantprivilegeprivilegecolumns) - * 5.2.8.113 [RQ.SRS-006.RBAC.Grant.Privilege.OnCluster](#rqsrs-006rbacgrantprivilegeoncluster) - * 5.2.8.114 [RQ.SRS-006.RBAC.Grant.Privilege.Syntax](#rqsrs-006rbacgrantprivilegesyntax) - * 5.2.8.115 [RQ.SRS-006.RBAC.Revoke.Privilege.Cluster](#rqsrs-006rbacrevokeprivilegecluster) - * 5.2.8.116 [RQ.SRS-006.RBAC.Revoke.Privilege.Any](#rqsrs-006rbacrevokeprivilegeany) - * 5.2.8.117 [RQ.SRS-006.RBAC.Revoke.Privilege.Select](#rqsrs-006rbacrevokeprivilegeselect) - * 5.2.8.118 [RQ.SRS-006.RBAC.Revoke.Privilege.Insert](#rqsrs-006rbacrevokeprivilegeinsert) - * 5.2.8.119 [RQ.SRS-006.RBAC.Revoke.Privilege.Alter](#rqsrs-006rbacrevokeprivilegealter) - * 5.2.8.120 [RQ.SRS-006.RBAC.Revoke.Privilege.Create](#rqsrs-006rbacrevokeprivilegecreate) - * 5.2.8.121 [RQ.SRS-006.RBAC.Revoke.Privilege.Drop](#rqsrs-006rbacrevokeprivilegedrop) - * 5.2.8.122 [RQ.SRS-006.RBAC.Revoke.Privilege.Truncate](#rqsrs-006rbacrevokeprivilegetruncate) - * 5.2.8.123 [RQ.SRS-006.RBAC.Revoke.Privilege.Optimize](#rqsrs-006rbacrevokeprivilegeoptimize) - * 5.2.8.124 [RQ.SRS-006.RBAC.Revoke.Privilege.Show](#rqsrs-006rbacrevokeprivilegeshow) - * 5.2.8.125 [RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery](#rqsrs-006rbacrevokeprivilegekillquery) - * 5.2.8.126 [RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement](#rqsrs-006rbacrevokeprivilegeaccessmanagement) - * 5.2.8.127 [RQ.SRS-006.RBAC.Revoke.Privilege.System](#rqsrs-006rbacrevokeprivilegesystem) - * 5.2.8.128 [RQ.SRS-006.RBAC.Revoke.Privilege.Introspection](#rqsrs-006rbacrevokeprivilegeintrospection) - * 5.2.8.129 [RQ.SRS-006.RBAC.Revoke.Privilege.Sources](#rqsrs-006rbacrevokeprivilegesources) - * 5.2.8.130 [RQ.SRS-006.RBAC.Revoke.Privilege.DictGet](#rqsrs-006rbacrevokeprivilegedictget) - * 5.2.8.131 [RQ.SRS-006.RBAC.Revoke.Privilege.PrivelegeColumns](#rqsrs-006rbacrevokeprivilegeprivelegecolumns) - * 5.2.8.132 [RQ.SRS-006.RBAC.Revoke.Privilege.Multiple](#rqsrs-006rbacrevokeprivilegemultiple) - * 5.2.8.133 [RQ.SRS-006.RBAC.Revoke.Privilege.All](#rqsrs-006rbacrevokeprivilegeall) - * 5.2.8.134 [RQ.SRS-006.RBAC.Revoke.Privilege.None](#rqsrs-006rbacrevokeprivilegenone) - * 5.2.8.135 [RQ.SRS-006.RBAC.Revoke.Privilege.On](#rqsrs-006rbacrevokeprivilegeon) - * 5.2.8.136 [RQ.SRS-006.RBAC.Revoke.Privilege.From](#rqsrs-006rbacrevokeprivilegefrom) - * 5.2.8.137 [RQ.SRS-006.RBAC.Revoke.Privilege.Syntax](#rqsrs-006rbacrevokeprivilegesyntax) - * 5.2.8.138 [RQ.SRS-006.RBAC.PartialRevoke.Syntax](#rqsrs-006rbacpartialrevokesyntax) - * 5.2.8.139 [RQ.SRS-006.RBAC.Grant.Role](#rqsrs-006rbacgrantrole) - * 5.2.8.140 [RQ.SRS-006.RBAC.Grant.Role.CurrentUser](#rqsrs-006rbacgrantrolecurrentuser) - * 5.2.8.141 [RQ.SRS-006.RBAC.Grant.Role.AdminOption](#rqsrs-006rbacgrantroleadminoption) - * 5.2.8.142 [RQ.SRS-006.RBAC.Grant.Role.OnCluster](#rqsrs-006rbacgrantroleoncluster) - * 5.2.8.143 [RQ.SRS-006.RBAC.Grant.Role.Syntax](#rqsrs-006rbacgrantrolesyntax) - * 5.2.8.144 [RQ.SRS-006.RBAC.Revoke.Role](#rqsrs-006rbacrevokerole) - * 5.2.8.145 [RQ.SRS-006.RBAC.Revoke.Role.Keywords](#rqsrs-006rbacrevokerolekeywords) - * 5.2.8.146 [RQ.SRS-006.RBAC.Revoke.Role.Cluster](#rqsrs-006rbacrevokerolecluster) - * 5.2.8.147 [RQ.SRS-006.RBAC.Revoke.AdminOption](#rqsrs-006rbacrevokeadminoption) - * 5.2.8.148 [RQ.SRS-006.RBAC.Revoke.Role.Syntax](#rqsrs-006rbacrevokerolesyntax) - * 5.2.8.149 [RQ.SRS-006.RBAC.Show.Grants](#rqsrs-006rbacshowgrants) - * 5.2.8.150 [RQ.SRS-006.RBAC.Show.Grants.For](#rqsrs-006rbacshowgrantsfor) - * 5.2.8.151 [RQ.SRS-006.RBAC.Show.Grants.Syntax](#rqsrs-006rbacshowgrantssyntax) - * 5.2.8.152 [RQ.SRS-006.RBAC.SettingsProfile.Create](#rqsrs-006rbacsettingsprofilecreate) - * 5.2.8.153 [RQ.SRS-006.RBAC.SettingsProfile.Create.IfNotExists](#rqsrs-006rbacsettingsprofilecreateifnotexists) - * 5.2.8.154 [RQ.SRS-006.RBAC.SettingsProfile.Create.Replace](#rqsrs-006rbacsettingsprofilecreatereplace) - * 5.2.8.155 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables](#rqsrs-006rbacsettingsprofilecreatevariables) - * 5.2.8.156 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Value](#rqsrs-006rbacsettingsprofilecreatevariablesvalue) - * 5.2.8.157 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Constraints](#rqsrs-006rbacsettingsprofilecreatevariablesconstraints) - * 5.2.8.158 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment](#rqsrs-006rbacsettingsprofilecreateassignment) - * 5.2.8.159 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.None](#rqsrs-006rbacsettingsprofilecreateassignmentnone) - * 5.2.8.160 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.All](#rqsrs-006rbacsettingsprofilecreateassignmentall) - * 5.2.8.161 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.AllExcept](#rqsrs-006rbacsettingsprofilecreateassignmentallexcept) - * 5.2.8.162 [RQ.SRS-006.RBAC.SettingsProfile.Create.Inherit](#rqsrs-006rbacsettingsprofilecreateinherit) - * 5.2.8.163 [RQ.SRS-006.RBAC.SettingsProfile.Create.OnCluster](#rqsrs-006rbacsettingsprofilecreateoncluster) - * 5.2.8.164 [RQ.SRS-006.RBAC.SettingsProfile.Create.Syntax](#rqsrs-006rbacsettingsprofilecreatesyntax) - * 5.2.8.165 [RQ.SRS-006.RBAC.SettingsProfile.Alter](#rqsrs-006rbacsettingsprofilealter) - * 5.2.8.166 [RQ.SRS-006.RBAC.SettingsProfile.Alter.IfExists](#rqsrs-006rbacsettingsprofilealterifexists) - * 5.2.8.167 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Rename](#rqsrs-006rbacsettingsprofilealterrename) - * 5.2.8.168 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables](#rqsrs-006rbacsettingsprofilealtervariables) - * 5.2.8.169 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Value](#rqsrs-006rbacsettingsprofilealtervariablesvalue) - * 5.2.8.170 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Constraints](#rqsrs-006rbacsettingsprofilealtervariablesconstraints) - * 5.2.8.171 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment](#rqsrs-006rbacsettingsprofilealterassignment) - * 5.2.8.172 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.None](#rqsrs-006rbacsettingsprofilealterassignmentnone) - * 5.2.8.173 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.All](#rqsrs-006rbacsettingsprofilealterassignmentall) - * 5.2.8.174 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.AllExcept](#rqsrs-006rbacsettingsprofilealterassignmentallexcept) - * 5.2.8.175 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.Inherit](#rqsrs-006rbacsettingsprofilealterassignmentinherit) - * 5.2.8.176 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.OnCluster](#rqsrs-006rbacsettingsprofilealterassignmentoncluster) - * 5.2.8.177 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Syntax](#rqsrs-006rbacsettingsprofilealtersyntax) - * 5.2.8.178 [RQ.SRS-006.RBAC.SettingsProfile.Drop](#rqsrs-006rbacsettingsprofiledrop) - * 5.2.8.179 [RQ.SRS-006.RBAC.SettingsProfile.Drop.IfExists](#rqsrs-006rbacsettingsprofiledropifexists) - * 5.2.8.180 [RQ.SRS-006.RBAC.SettingsProfile.Drop.OnCluster](#rqsrs-006rbacsettingsprofiledroponcluster) - * 5.2.8.181 [RQ.SRS-006.RBAC.SettingsProfile.Drop.Syntax](#rqsrs-006rbacsettingsprofiledropsyntax) - * 5.2.8.182 [RQ.SRS-006.RBAC.SettingsProfile.ShowCreateSettingsProfile](#rqsrs-006rbacsettingsprofileshowcreatesettingsprofile) - * 5.2.8.183 [RQ.SRS-006.RBAC.Quota.Create](#rqsrs-006rbacquotacreate) - * 5.2.8.184 [RQ.SRS-006.RBAC.Quota.Create.IfNotExists](#rqsrs-006rbacquotacreateifnotexists) - * 5.2.8.185 [RQ.SRS-006.RBAC.Quota.Create.Replace](#rqsrs-006rbacquotacreatereplace) - * 5.2.8.186 [RQ.SRS-006.RBAC.Quota.Create.Cluster](#rqsrs-006rbacquotacreatecluster) - * 5.2.8.187 [RQ.SRS-006.RBAC.Quota.Create.Interval](#rqsrs-006rbacquotacreateinterval) - * 5.2.8.188 [RQ.SRS-006.RBAC.Quota.Create.Interval.Randomized](#rqsrs-006rbacquotacreateintervalrandomized) - * 5.2.8.189 [RQ.SRS-006.RBAC.Quota.Create.Queries](#rqsrs-006rbacquotacreatequeries) - * 5.2.8.190 [RQ.SRS-006.RBAC.Quota.Create.Errors](#rqsrs-006rbacquotacreateerrors) - * 5.2.8.191 [RQ.SRS-006.RBAC.Quota.Create.ResultRows](#rqsrs-006rbacquotacreateresultrows) - * 5.2.8.192 [RQ.SRS-006.RBAC.Quota.Create.ReadRows](#rqsrs-006rbacquotacreatereadrows) - * 5.2.8.193 [RQ.SRS-006.RBAC.Quota.Create.ResultBytes](#rqsrs-006rbacquotacreateresultbytes) - * 5.2.8.194 [RQ.SRS-006.RBAC.Quota.Create.ReadBytes](#rqsrs-006rbacquotacreatereadbytes) - * 5.2.8.195 [RQ.SRS-006.RBAC.Quota.Create.ExecutionTime](#rqsrs-006rbacquotacreateexecutiontime) - * 5.2.8.196 [RQ.SRS-006.RBAC.Quota.Create.NoLimits](#rqsrs-006rbacquotacreatenolimits) - * 5.2.8.197 [RQ.SRS-006.RBAC.Quota.Create.TrackingOnly](#rqsrs-006rbacquotacreatetrackingonly) - * 5.2.8.198 [RQ.SRS-006.RBAC.Quota.Create.KeyedBy](#rqsrs-006rbacquotacreatekeyedby) - * 5.2.8.199 [RQ.SRS-006.RBAC.Quota.Create.KeyedByOptions](#rqsrs-006rbacquotacreatekeyedbyoptions) - * 5.2.8.200 [RQ.SRS-006.RBAC.Quota.Create.Assignment](#rqsrs-006rbacquotacreateassignment) - * 5.2.8.201 [RQ.SRS-006.RBAC.Quota.Create.Assignment.None](#rqsrs-006rbacquotacreateassignmentnone) - * 5.2.8.202 [RQ.SRS-006.RBAC.Quota.Create.Assignment.All](#rqsrs-006rbacquotacreateassignmentall) - * 5.2.8.203 [RQ.SRS-006.RBAC.Quota.Create.Assignment.Except](#rqsrs-006rbacquotacreateassignmentexcept) - * 5.2.8.204 [RQ.SRS-006.RBAC.Quota.Create.Syntax](#rqsrs-006rbacquotacreatesyntax) - * 5.2.8.205 [RQ.SRS-006.RBAC.Quota.Alter](#rqsrs-006rbacquotaalter) - * 5.2.8.206 [RQ.SRS-006.RBAC.Quota.Alter.IfExists](#rqsrs-006rbacquotaalterifexists) - * 5.2.8.207 [RQ.SRS-006.RBAC.Quota.Alter.Rename](#rqsrs-006rbacquotaalterrename) - * 5.2.8.208 [RQ.SRS-006.RBAC.Quota.Alter.Cluster](#rqsrs-006rbacquotaaltercluster) - * 5.2.8.209 [RQ.SRS-006.RBAC.Quota.Alter.Interval](#rqsrs-006rbacquotaalterinterval) - * 5.2.8.210 [RQ.SRS-006.RBAC.Quota.Alter.Interval.Randomized](#rqsrs-006rbacquotaalterintervalrandomized) - * 5.2.8.211 [RQ.SRS-006.RBAC.Quota.Alter.Queries](#rqsrs-006rbacquotaalterqueries) - * 5.2.8.212 [RQ.SRS-006.RBAC.Quota.Alter.Errors](#rqsrs-006rbacquotaaltererrors) - * 5.2.8.213 [RQ.SRS-006.RBAC.Quota.Alter.ResultRows](#rqsrs-006rbacquotaalterresultrows) - * 5.2.8.214 [RQ.SRS-006.RBAC.Quota.Alter.ReadRows](#rqsrs-006rbacquotaalterreadrows) - * 5.2.8.215 [RQ.SRS-006.RBAC.Quota.ALter.ResultBytes](#rqsrs-006rbacquotaalterresultbytes) - * 5.2.8.216 [RQ.SRS-006.RBAC.Quota.Alter.ReadBytes](#rqsrs-006rbacquotaalterreadbytes) - * 5.2.8.217 [RQ.SRS-006.RBAC.Quota.Alter.ExecutionTime](#rqsrs-006rbacquotaalterexecutiontime) - * 5.2.8.218 [RQ.SRS-006.RBAC.Quota.Alter.NoLimits](#rqsrs-006rbacquotaalternolimits) - * 5.2.8.219 [RQ.SRS-006.RBAC.Quota.Alter.TrackingOnly](#rqsrs-006rbacquotaaltertrackingonly) - * 5.2.8.220 [RQ.SRS-006.RBAC.Quota.Alter.KeyedBy](#rqsrs-006rbacquotaalterkeyedby) - * 5.2.8.221 [RQ.SRS-006.RBAC.Quota.Alter.KeyedByOptions](#rqsrs-006rbacquotaalterkeyedbyoptions) - * 5.2.8.222 [RQ.SRS-006.RBAC.Quota.Alter.Assignment](#rqsrs-006rbacquotaalterassignment) - * 5.2.8.223 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.None](#rqsrs-006rbacquotaalterassignmentnone) - * 5.2.8.224 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.All](#rqsrs-006rbacquotaalterassignmentall) - * 5.2.8.225 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.Except](#rqsrs-006rbacquotaalterassignmentexcept) - * 5.2.8.226 [RQ.SRS-006.RBAC.Quota.Alter.Syntax](#rqsrs-006rbacquotaaltersyntax) - * 5.2.8.227 [RQ.SRS-006.RBAC.Quota.Drop](#rqsrs-006rbacquotadrop) - * 5.2.8.228 [RQ.SRS-006.RBAC.Quota.Drop.IfExists](#rqsrs-006rbacquotadropifexists) - * 5.2.8.229 [RQ.SRS-006.RBAC.Quota.Drop.Cluster](#rqsrs-006rbacquotadropcluster) - * 5.2.8.230 [RQ.SRS-006.RBAC.Quota.Drop.Syntax](#rqsrs-006rbacquotadropsyntax) - * 5.2.8.231 [RQ.SRS-006.RBAC.Quota.ShowQuotas](#rqsrs-006rbacquotashowquotas) - * 5.2.8.232 [RQ.SRS-006.RBAC.Quota.ShowQuotas.IntoOutfile](#rqsrs-006rbacquotashowquotasintooutfile) - * 5.2.8.233 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Format](#rqsrs-006rbacquotashowquotasformat) - * 5.2.8.234 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Settings](#rqsrs-006rbacquotashowquotassettings) - * 5.2.8.235 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Syntax](#rqsrs-006rbacquotashowquotassyntax) - * 5.2.8.236 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Name](#rqsrs-006rbacquotashowcreatequotaname) - * 5.2.8.237 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Current](#rqsrs-006rbacquotashowcreatequotacurrent) - * 5.2.8.238 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Syntax](#rqsrs-006rbacquotashowcreatequotasyntax) - * 5.2.8.239 [RQ.SRS-006.RBAC.RowPolicy.Create](#rqsrs-006rbacrowpolicycreate) - * 5.2.8.240 [RQ.SRS-006.RBAC.RowPolicy.Create.IfNotExists](#rqsrs-006rbacrowpolicycreateifnotexists) - * 5.2.8.241 [RQ.SRS-006.RBAC.RowPolicy.Create.Replace](#rqsrs-006rbacrowpolicycreatereplace) - * 5.2.8.242 [RQ.SRS-006.RBAC.RowPolicy.Create.OnCluster](#rqsrs-006rbacrowpolicycreateoncluster) - * 5.2.8.243 [RQ.SRS-006.RBAC.RowPolicy.Create.On](#rqsrs-006rbacrowpolicycreateon) - * 5.2.8.244 [RQ.SRS-006.RBAC.RowPolicy.Create.Access](#rqsrs-006rbacrowpolicycreateaccess) - * 5.2.8.245 [RQ.SRS-006.RBAC.RowPolicy.Create.Access.Permissive](#rqsrs-006rbacrowpolicycreateaccesspermissive) - * 5.2.8.246 [RQ.SRS-006.RBAC.RowPolicy.Create.Access.Restrictive](#rqsrs-006rbacrowpolicycreateaccessrestrictive) - * 5.2.8.247 [RQ.SRS-006.RBAC.RowPolicy.Create.ForSelect](#rqsrs-006rbacrowpolicycreateforselect) - * 5.2.8.248 [RQ.SRS-006.RBAC.RowPolicy.Create.Condition](#rqsrs-006rbacrowpolicycreatecondition) - * 5.2.8.249 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment](#rqsrs-006rbacrowpolicycreateassignment) - * 5.2.8.250 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.None](#rqsrs-006rbacrowpolicycreateassignmentnone) - * 5.2.8.251 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.All](#rqsrs-006rbacrowpolicycreateassignmentall) - * 5.2.8.252 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.AllExcept](#rqsrs-006rbacrowpolicycreateassignmentallexcept) - * 5.2.8.253 [RQ.SRS-006.RBAC.RowPolicy.Create.Syntax](#rqsrs-006rbacrowpolicycreatesyntax) - * 5.2.8.254 [RQ.SRS-006.RBAC.RowPolicy.Alter](#rqsrs-006rbacrowpolicyalter) - * 5.2.8.255 [RQ.SRS-006.RBAC.RowPolicy.Alter.IfExists](#rqsrs-006rbacrowpolicyalterifexists) - * 5.2.8.256 [RQ.SRS-006.RBAC.RowPolicy.Alter.ForSelect](#rqsrs-006rbacrowpolicyalterforselect) - * 5.2.8.257 [RQ.SRS-006.RBAC.RowPolicy.Alter.OnCluster](#rqsrs-006rbacrowpolicyalteroncluster) - * 5.2.8.258 [RQ.SRS-006.RBAC.RowPolicy.Alter.On](#rqsrs-006rbacrowpolicyalteron) - * 5.2.8.259 [RQ.SRS-006.RBAC.RowPolicy.Alter.Rename](#rqsrs-006rbacrowpolicyalterrename) - * 5.2.8.260 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access](#rqsrs-006rbacrowpolicyalteraccess) - * 5.2.8.261 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Permissive](#rqsrs-006rbacrowpolicyalteraccesspermissive) - * 5.2.8.262 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Restrictive](#rqsrs-006rbacrowpolicyalteraccessrestrictive) - * 5.2.8.263 [RQ.SRS-006.RBAC.RowPolicy.Alter.Condition](#rqsrs-006rbacrowpolicyaltercondition) - * 5.2.8.264 [RQ.SRS-006.RBAC.RowPolicy.Alter.Condition.None](#rqsrs-006rbacrowpolicyalterconditionnone) - * 5.2.8.265 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment](#rqsrs-006rbacrowpolicyalterassignment) - * 5.2.8.266 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.None](#rqsrs-006rbacrowpolicyalterassignmentnone) - * 5.2.8.267 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.All](#rqsrs-006rbacrowpolicyalterassignmentall) - * 5.2.8.268 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.AllExcept](#rqsrs-006rbacrowpolicyalterassignmentallexcept) - * 5.2.8.269 [RQ.SRS-006.RBAC.RowPolicy.Alter.Syntax](#rqsrs-006rbacrowpolicyaltersyntax) - * 5.2.8.270 [RQ.SRS-006.RBAC.RowPolicy.Drop](#rqsrs-006rbacrowpolicydrop) - * 5.2.8.271 [RQ.SRS-006.RBAC.RowPolicy.Drop.IfExists](#rqsrs-006rbacrowpolicydropifexists) - * 5.2.8.272 [RQ.SRS-006.RBAC.RowPolicy.Drop.On](#rqsrs-006rbacrowpolicydropon) - * 5.2.8.273 [RQ.SRS-006.RBAC.RowPolicy.Drop.OnCluster](#rqsrs-006rbacrowpolicydroponcluster) - * 5.2.8.274 [RQ.SRS-006.RBAC.RowPolicy.Drop.Syntax](#rqsrs-006rbacrowpolicydropsyntax) - * 5.2.8.275 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy](#rqsrs-006rbacrowpolicyshowcreaterowpolicy) - * 5.2.8.276 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.On](#rqsrs-006rbacrowpolicyshowcreaterowpolicyon) - * 5.2.8.277 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.Syntax](#rqsrs-006rbacrowpolicyshowcreaterowpolicysyntax) - * 5.2.8.278 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies](#rqsrs-006rbacrowpolicyshowrowpolicies) - * 5.2.8.279 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.On](#rqsrs-006rbacrowpolicyshowrowpolicieson) - * 5.2.8.280 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.Syntax](#rqsrs-006rbacrowpolicyshowrowpoliciessyntax) - * 5.2.9 [Table Privileges](#table-privileges) - * 5.2.9.1 [RQ.SRS-006.RBAC.Table.PublicTables](#rqsrs-006rbactablepublictables) - * 5.2.9.2 [RQ.SRS-006.RBAC.Table.SensitiveTables](#rqsrs-006rbactablesensitivetables) - * 5.2.10 [Distributed Tables](#distributed-tables) - * 5.2.10.1 [RQ.SRS-006.RBAC.DistributedTable.Create](#rqsrs-006rbacdistributedtablecreate) - * 5.2.10.2 [RQ.SRS-006.RBAC.DistributedTable.Select](#rqsrs-006rbacdistributedtableselect) - * 5.2.10.3 [RQ.SRS-006.RBAC.DistributedTable.Insert](#rqsrs-006rbacdistributedtableinsert) - * 5.2.10.4 [RQ.SRS-006.RBAC.DistributedTable.SpecialTables](#rqsrs-006rbacdistributedtablespecialtables) - * 5.2.10.5 [RQ.SRS-006.RBAC.DistributedTable.LocalUser](#rqsrs-006rbacdistributedtablelocaluser) - * 5.2.10.6 [RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges](#rqsrs-006rbacdistributedtablesameuserdifferentnodesdifferentprivileges) - * 5.2.11 [Views](#views) - * 5.2.11.1 [View](#view) - * 5.2.11.1.1 [RQ.SRS-006.RBAC.View](#rqsrs-006rbacview) - * 5.2.11.1.2 [RQ.SRS-006.RBAC.View.Create](#rqsrs-006rbacviewcreate) - * 5.2.11.1.3 [RQ.SRS-006.RBAC.View.Select](#rqsrs-006rbacviewselect) - * 5.2.11.1.4 [RQ.SRS-006.RBAC.View.Drop](#rqsrs-006rbacviewdrop) - * 5.2.11.2 [Materialized View](#materialized-view) - * 5.2.11.2.1 [RQ.SRS-006.RBAC.MaterializedView](#rqsrs-006rbacmaterializedview) - * 5.2.11.2.2 [RQ.SRS-006.RBAC.MaterializedView.Create](#rqsrs-006rbacmaterializedviewcreate) - * 5.2.11.2.3 [RQ.SRS-006.RBAC.MaterializedView.Select](#rqsrs-006rbacmaterializedviewselect) - * 5.2.11.2.4 [RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable](#rqsrs-006rbacmaterializedviewselecttargettable) - * 5.2.11.2.5 [RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable](#rqsrs-006rbacmaterializedviewselectsourcetable) - * 5.2.11.2.6 [RQ.SRS-006.RBAC.MaterializedView.Drop](#rqsrs-006rbacmaterializedviewdrop) - * 5.2.11.2.7 [RQ.SRS-006.RBAC.MaterializedView.ModifyQuery](#rqsrs-006rbacmaterializedviewmodifyquery) - * 5.2.11.2.8 [RQ.SRS-006.RBAC.MaterializedView.Insert](#rqsrs-006rbacmaterializedviewinsert) - * 5.2.11.2.9 [RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable](#rqsrs-006rbacmaterializedviewinsertsourcetable) - * 5.2.11.2.10 [RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable](#rqsrs-006rbacmaterializedviewinserttargettable) - * 5.2.11.3 [Live View](#live-view) - * 5.2.11.3.1 [RQ.SRS-006.RBAC.LiveView](#rqsrs-006rbacliveview) - * 5.2.11.3.2 [RQ.SRS-006.RBAC.LiveView.Create](#rqsrs-006rbacliveviewcreate) - * 5.2.11.3.3 [RQ.SRS-006.RBAC.LiveView.Select](#rqsrs-006rbacliveviewselect) - * 5.2.11.3.4 [RQ.SRS-006.RBAC.LiveView.Drop](#rqsrs-006rbacliveviewdrop) - * 5.2.11.3.5 [RQ.SRS-006.RBAC.LiveView.Refresh](#rqsrs-006rbacliveviewrefresh) - * 5.2.12 [Select](#select) - * 5.2.12.1 [RQ.SRS-006.RBAC.Select](#rqsrs-006rbacselect) - * 5.2.12.2 [RQ.SRS-006.RBAC.Select.Column](#rqsrs-006rbacselectcolumn) - * 5.2.12.3 [RQ.SRS-006.RBAC.Select.Cluster](#rqsrs-006rbacselectcluster) - * 5.2.12.4 [RQ.SRS-006.RBAC.Select.TableEngines](#rqsrs-006rbacselecttableengines) - * 5.2.13 [Insert](#insert) - * 5.2.13.1 [RQ.SRS-006.RBAC.Insert](#rqsrs-006rbacinsert) - * 5.2.13.2 [RQ.SRS-006.RBAC.Insert.Column](#rqsrs-006rbacinsertcolumn) - * 5.2.13.3 [RQ.SRS-006.RBAC.Insert.Cluster](#rqsrs-006rbacinsertcluster) - * 5.2.13.4 [RQ.SRS-006.RBAC.Insert.TableEngines](#rqsrs-006rbacinserttableengines) - * 5.2.14 [Alter](#alter) - * 5.2.14.1 [Alter Column](#alter-column) - * 5.2.14.1.1 [RQ.SRS-006.RBAC.Privileges.AlterColumn](#rqsrs-006rbacprivilegesaltercolumn) - * 5.2.14.1.2 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant](#rqsrs-006rbacprivilegesaltercolumngrant) - * 5.2.14.1.3 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke](#rqsrs-006rbacprivilegesaltercolumnrevoke) - * 5.2.14.1.4 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Column](#rqsrs-006rbacprivilegesaltercolumncolumn) - * 5.2.14.1.5 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster](#rqsrs-006rbacprivilegesaltercolumncluster) - * 5.2.14.1.6 [RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines](#rqsrs-006rbacprivilegesaltercolumntableengines) - * 5.2.14.2 [Alter Index](#alter-index) - * 5.2.14.2.1 [RQ.SRS-006.RBAC.Privileges.AlterIndex](#rqsrs-006rbacprivilegesalterindex) - * 5.2.14.2.2 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant](#rqsrs-006rbacprivilegesalterindexgrant) - * 5.2.14.2.3 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke](#rqsrs-006rbacprivilegesalterindexrevoke) - * 5.2.14.2.4 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster](#rqsrs-006rbacprivilegesalterindexcluster) - * 5.2.14.2.5 [RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines](#rqsrs-006rbacprivilegesalterindextableengines) - * 5.2.14.3 [Alter Constraint](#alter-constraint) - * 5.2.14.3.1 [RQ.SRS-006.RBAC.Privileges.AlterConstraint](#rqsrs-006rbacprivilegesalterconstraint) - * 5.2.14.3.2 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant](#rqsrs-006rbacprivilegesalterconstraintgrant) - * 5.2.14.3.3 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke](#rqsrs-006rbacprivilegesalterconstraintrevoke) - * 5.2.14.3.4 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster](#rqsrs-006rbacprivilegesalterconstraintcluster) - * 5.2.14.3.5 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines](#rqsrs-006rbacprivilegesalterconstrainttableengines) - * 5.2.14.4 [Alter TTL](#alter-ttl) - * 5.2.14.4.1 [RQ.SRS-006.RBAC.Privileges.AlterTTL](#rqsrs-006rbacprivilegesalterttl) - * 5.2.14.4.2 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant](#rqsrs-006rbacprivilegesalterttlgrant) - * 5.2.14.4.3 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke](#rqsrs-006rbacprivilegesalterttlrevoke) - * 5.2.14.4.4 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster](#rqsrs-006rbacprivilegesalterttlcluster) - * 5.2.14.4.5 [RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines](#rqsrs-006rbacprivilegesalterttltableengines) - * 5.2.14.5 [Alter Settings](#alter-settings) - * 5.2.14.5.1 [RQ.SRS-006.RBAC.Privileges.AlterSettings](#rqsrs-006rbacprivilegesaltersettings) - * 5.2.14.5.2 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant](#rqsrs-006rbacprivilegesaltersettingsgrant) - * 5.2.14.5.3 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke](#rqsrs-006rbacprivilegesaltersettingsrevoke) - * 5.2.14.5.4 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster](#rqsrs-006rbacprivilegesaltersettingscluster) - * 5.2.14.5.5 [RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines](#rqsrs-006rbacprivilegesaltersettingstableengines) - * 5.2.14.6 [Alter Update](#alter-update) - * 5.2.14.6.1 [RQ.SRS-006.RBAC.Privileges.AlterUpdate](#rqsrs-006rbacprivilegesalterupdate) - * 5.2.14.6.2 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant](#rqsrs-006rbacprivilegesalterupdategrant) - * 5.2.14.6.3 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke](#rqsrs-006rbacprivilegesalterupdaterevoke) - * 5.2.14.6.4 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines](#rqsrs-006rbacprivilegesalterupdatetableengines) - * 5.2.14.7 [Alter Delete](#alter-delete) - * 5.2.14.7.1 [RQ.SRS-006.RBAC.Privileges.AlterDelete](#rqsrs-006rbacprivilegesalterdelete) - * 5.2.14.7.2 [RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant](#rqsrs-006rbacprivilegesalterdeletegrant) - * 5.2.14.7.3 [RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke](#rqsrs-006rbacprivilegesalterdeleterevoke) - * 5.2.14.7.4 [RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines](#rqsrs-006rbacprivilegesalterdeletetableengines) - * 5.2.14.8 [Alter Freeze Partition](#alter-freeze-partition) - * 5.2.14.8.1 [RQ.SRS-006.RBAC.Privileges.AlterFreeze](#rqsrs-006rbacprivilegesalterfreeze) - * 5.2.14.8.2 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant](#rqsrs-006rbacprivilegesalterfreezegrant) - * 5.2.14.8.3 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke](#rqsrs-006rbacprivilegesalterfreezerevoke) - * 5.2.14.8.4 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines](#rqsrs-006rbacprivilegesalterfreezetableengines) - * 5.2.14.9 [Alter Fetch Partition](#alter-fetch-partition) - * 5.2.14.9.1 [RQ.SRS-006.RBAC.Privileges.AlterFetch](#rqsrs-006rbacprivilegesalterfetch) - * 5.2.14.9.2 [RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant](#rqsrs-006rbacprivilegesalterfetchgrant) - * 5.2.14.9.3 [RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke](#rqsrs-006rbacprivilegesalterfetchrevoke) - * 5.2.14.9.4 [RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines](#rqsrs-006rbacprivilegesalterfetchtableengines) - * 5.2.14.10 [Alter Move Partition](#alter-move-partition) - * 5.2.14.10.1 [RQ.SRS-006.RBAC.Privileges.AlterMove](#rqsrs-006rbacprivilegesaltermove) - * 5.2.14.10.2 [RQ.SRS-006.RBAC.Privileges.AlterMove.Grant](#rqsrs-006rbacprivilegesaltermovegrant) - * 5.2.14.10.3 [RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke](#rqsrs-006rbacprivilegesaltermoverevoke) - * 5.2.14.10.4 [RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines](#rqsrs-006rbacprivilegesaltermovetableengines) - * 5.2.15 [RQ.SRS-006.RBAC.Privileges.CreateTable](#rqsrs-006rbacprivilegescreatetable) - * 5.2.16 [RQ.SRS-006.RBAC.Privileges.CreateDatabase](#rqsrs-006rbacprivilegescreatedatabase) - * 5.2.17 [RQ.SRS-006.RBAC.Privileges.CreateDictionary](#rqsrs-006rbacprivilegescreatedictionary) - * 5.2.18 [RQ.SRS-006.RBAC.Privileges.CreateTemporaryTable](#rqsrs-006rbacprivilegescreatetemporarytable) - * 5.2.19 [RQ.SRS-006.RBAC.Privileges.AttachDatabase](#rqsrs-006rbacprivilegesattachdatabase) - * 5.2.20 [RQ.SRS-006.RBAC.Privileges.AttachDictionary](#rqsrs-006rbacprivilegesattachdictionary) - * 5.2.21 [RQ.SRS-006.RBAC.Privileges.AttachTemporaryTable](#rqsrs-006rbacprivilegesattachtemporarytable) - * 5.2.22 [RQ.SRS-006.RBAC.Privileges.AttachTable](#rqsrs-006rbacprivilegesattachtable) - * 5.2.23 [RQ.SRS-006.RBAC.Privileges.DropTable](#rqsrs-006rbacprivilegesdroptable) - * 5.2.24 [RQ.SRS-006.RBAC.Privileges.DropDatabase](#rqsrs-006rbacprivilegesdropdatabase) - * 5.2.25 [RQ.SRS-006.RBAC.Privileges.DropDictionary](#rqsrs-006rbacprivilegesdropdictionary) - * 5.2.26 [RQ.SRS-006.RBAC.Privileges.DetachTable](#rqsrs-006rbacprivilegesdetachtable) - * 5.2.27 [RQ.SRS-006.RBAC.Privileges.DetachView](#rqsrs-006rbacprivilegesdetachview) - * 5.2.28 [RQ.SRS-006.RBAC.Privileges.DetachDatabase](#rqsrs-006rbacprivilegesdetachdatabase) - * 5.2.29 [RQ.SRS-006.RBAC.Privileges.DetachDictionary](#rqsrs-006rbacprivilegesdetachdictionary) - * 5.2.30 [RQ.SRS-006.RBAC.Privileges.Truncate](#rqsrs-006rbacprivilegestruncate) - * 5.2.31 [RQ.SRS-006.RBAC.Privileges.Optimize](#rqsrs-006rbacprivilegesoptimize) - * 5.2.32 [RQ.SRS-006.RBAC.Privileges.KillQuery](#rqsrs-006rbacprivilegeskillquery) - * 5.2.33 [Kill Mutation](#kill-mutation) - * 5.2.33.1 [RQ.SRS-006.RBAC.Privileges.KillMutation](#rqsrs-006rbacprivilegeskillmutation) - * 5.2.33.2 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate](#rqsrs-006rbacprivilegeskillmutationalterupdate) - * 5.2.33.3 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete](#rqsrs-006rbacprivilegeskillmutationalterdelete) - * 5.2.33.4 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn](#rqsrs-006rbacprivilegeskillmutationalterdropcolumn) - * 5.2.34 [Show](#show) - * 5.2.34.1 [RQ.SRS-006.RBAC.ShowTables.Privilege](#rqsrs-006rbacshowtablesprivilege) - * 5.2.34.2 [RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege](#rqsrs-006rbacshowtablesrequiredprivilege) - * 5.2.34.3 [RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege](#rqsrs-006rbacexiststablerequiredprivilege) - * 5.2.34.4 [RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege](#rqsrs-006rbacchecktablerequiredprivilege) - * 5.2.34.5 [RQ.SRS-006.RBAC.ShowDatabases.Privilege](#rqsrs-006rbacshowdatabasesprivilege) - * 5.2.34.6 [RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege](#rqsrs-006rbacshowdatabasesrequiredprivilege) - * 5.2.34.7 [RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege](#rqsrs-006rbacshowcreatedatabaserequiredprivilege) - * 5.2.34.8 [RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege](#rqsrs-006rbacusedatabaserequiredprivilege) - * 5.2.34.9 [RQ.SRS-006.RBAC.ShowColumns.Privilege](#rqsrs-006rbacshowcolumnsprivilege) - * 5.2.34.10 [RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege](#rqsrs-006rbacshowcreatetablerequiredprivilege) - * 5.2.34.11 [RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege](#rqsrs-006rbacdescribetablerequiredprivilege) - * 5.2.34.12 [RQ.SRS-006.RBAC.ShowDictionaries.Privilege](#rqsrs-006rbacshowdictionariesprivilege) - * 5.2.34.13 [RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege](#rqsrs-006rbacshowdictionariesrequiredprivilege) - * 5.2.34.14 [RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege](#rqsrs-006rbacshowcreatedictionaryrequiredprivilege) - * 5.2.34.15 [RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege](#rqsrs-006rbacexistsdictionaryrequiredprivilege) - * 5.2.35 [Access Management](#access-management) - * 5.2.35.1 [RQ.SRS-006.RBAC.Privileges.CreateUser](#rqsrs-006rbacprivilegescreateuser) - * 5.2.35.2 [RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole](#rqsrs-006rbacprivilegescreateuserdefaultrole) - * 5.2.35.3 [RQ.SRS-006.RBAC.Privileges.AlterUser](#rqsrs-006rbacprivilegesalteruser) - * 5.2.35.4 [RQ.SRS-006.RBAC.Privileges.DropUser](#rqsrs-006rbacprivilegesdropuser) - * 5.2.35.5 [RQ.SRS-006.RBAC.Privileges.CreateRole](#rqsrs-006rbacprivilegescreaterole) - * 5.2.35.6 [RQ.SRS-006.RBAC.Privileges.AlterRole](#rqsrs-006rbacprivilegesalterrole) - * 5.2.35.7 [RQ.SRS-006.RBAC.Privileges.DropRole](#rqsrs-006rbacprivilegesdroprole) - * 5.2.35.8 [RQ.SRS-006.RBAC.Privileges.CreateRowPolicy](#rqsrs-006rbacprivilegescreaterowpolicy) - * 5.2.35.9 [RQ.SRS-006.RBAC.Privileges.AlterRowPolicy](#rqsrs-006rbacprivilegesalterrowpolicy) - * 5.2.35.10 [RQ.SRS-006.RBAC.Privileges.DropRowPolicy](#rqsrs-006rbacprivilegesdroprowpolicy) - * 5.2.35.11 [RQ.SRS-006.RBAC.Privileges.CreateQuota](#rqsrs-006rbacprivilegescreatequota) - * 5.2.35.12 [RQ.SRS-006.RBAC.Privileges.AlterQuota](#rqsrs-006rbacprivilegesalterquota) - * 5.2.35.13 [RQ.SRS-006.RBAC.Privileges.DropQuota](#rqsrs-006rbacprivilegesdropquota) - * 5.2.35.14 [RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile](#rqsrs-006rbacprivilegescreatesettingsprofile) - * 5.2.35.15 [RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile](#rqsrs-006rbacprivilegesaltersettingsprofile) - * 5.2.35.16 [RQ.SRS-006.RBAC.Privileges.DropSettingsProfile](#rqsrs-006rbacprivilegesdropsettingsprofile) - * 5.2.35.17 [RQ.SRS-006.RBAC.Privileges.RoleAdmin](#rqsrs-006rbacprivilegesroleadmin) - * 5.2.35.18 [Show Access](#show-access) - * 5.2.35.18.1 [RQ.SRS-006.RBAC.ShowUsers.Privilege](#rqsrs-006rbacshowusersprivilege) - * 5.2.35.18.2 [RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege](#rqsrs-006rbacshowusersrequiredprivilege) - * 5.2.35.18.3 [RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege](#rqsrs-006rbacshowcreateuserrequiredprivilege) - * 5.2.35.18.4 [RQ.SRS-006.RBAC.ShowRoles.Privilege](#rqsrs-006rbacshowrolesprivilege) - * 5.2.35.18.5 [RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege](#rqsrs-006rbacshowrolesrequiredprivilege) - * 5.2.35.18.6 [RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege](#rqsrs-006rbacshowcreaterolerequiredprivilege) - * 5.2.35.18.7 [RQ.SRS-006.RBAC.ShowRowPolicies.Privilege](#rqsrs-006rbacshowrowpoliciesprivilege) - * 5.2.35.18.8 [RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege](#rqsrs-006rbacshowrowpoliciesrequiredprivilege) - * 5.2.35.18.9 [RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege](#rqsrs-006rbacshowcreaterowpolicyrequiredprivilege) - * 5.2.35.18.10 [RQ.SRS-006.RBAC.ShowQuotas.Privilege](#rqsrs-006rbacshowquotasprivilege) - * 5.2.35.18.11 [RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege](#rqsrs-006rbacshowquotasrequiredprivilege) - * 5.2.35.18.12 [RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege](#rqsrs-006rbacshowcreatequotarequiredprivilege) - * 5.2.35.18.13 [RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege](#rqsrs-006rbacshowsettingsprofilesprivilege) - * 5.2.35.18.14 [RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege](#rqsrs-006rbacshowsettingsprofilesrequiredprivilege) - * 5.2.35.18.15 [RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege](#rqsrs-006rbacshowcreatesettingsprofilerequiredprivilege) - * 5.2.36 [dictGet](#dictget) - * 5.2.36.1 [RQ.SRS-006.RBAC.dictGet.Privilege](#rqsrs-006rbacdictgetprivilege) - * 5.2.36.2 [RQ.SRS-006.RBAC.dictGet.RequiredPrivilege](#rqsrs-006rbacdictgetrequiredprivilege) - * 5.2.36.3 [RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege](#rqsrs-006rbacdictgettyperequiredprivilege) - * 5.2.36.4 [RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege](#rqsrs-006rbacdictgetordefaultrequiredprivilege) - * 5.2.36.5 [RQ.SRS-006.RBAC.dictHas.RequiredPrivilege](#rqsrs-006rbacdicthasrequiredprivilege) - * 5.2.36.6 [RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege](#rqsrs-006rbacdictgethierarchyrequiredprivilege) - * 5.2.36.7 [RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege](#rqsrs-006rbacdictisinrequiredprivilege) - * 5.2.37 [Introspection](#introspection) - * 5.2.37.1 [RQ.SRS-006.RBAC.Privileges.Introspection](#rqsrs-006rbacprivilegesintrospection) - * 5.2.37.2 [RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine](#rqsrs-006rbacprivilegesintrospectionaddresstoline) - * 5.2.37.3 [RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol](#rqsrs-006rbacprivilegesintrospectionaddresstosymbol) - * 5.2.37.4 [RQ.SRS-006.RBAC.Privileges.Introspection.demangle](#rqsrs-006rbacprivilegesintrospectiondemangle) - * 5.2.38 [System](#system) - * 5.2.38.1 [RQ.SRS-006.RBAC.Privileges.System.Shutdown](#rqsrs-006rbacprivilegessystemshutdown) - * 5.2.38.2 [RQ.SRS-006.RBAC.Privileges.System.DropCache](#rqsrs-006rbacprivilegessystemdropcache) - * 5.2.38.3 [RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS](#rqsrs-006rbacprivilegessystemdropcachedns) - * 5.2.38.4 [RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark](#rqsrs-006rbacprivilegessystemdropcachemark) - * 5.2.38.5 [RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed](#rqsrs-006rbacprivilegessystemdropcacheuncompressed) - * 5.2.38.6 [RQ.SRS-006.RBAC.Privileges.System.Reload](#rqsrs-006rbacprivilegessystemreload) - * 5.2.38.7 [RQ.SRS-006.RBAC.Privileges.System.Reload.Config](#rqsrs-006rbacprivilegessystemreloadconfig) - * 5.2.38.8 [RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary](#rqsrs-006rbacprivilegessystemreloaddictionary) - * 5.2.38.9 [RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries](#rqsrs-006rbacprivilegessystemreloaddictionaries) - * 5.2.38.10 [RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries](#rqsrs-006rbacprivilegessystemreloadembeddeddictionaries) - * 5.2.38.11 [RQ.SRS-006.RBAC.Privileges.System.Merges](#rqsrs-006rbacprivilegessystemmerges) - * 5.2.38.12 [RQ.SRS-006.RBAC.Privileges.System.TTLMerges](#rqsrs-006rbacprivilegessystemttlmerges) - * 5.2.38.13 [RQ.SRS-006.RBAC.Privileges.System.Fetches](#rqsrs-006rbacprivilegessystemfetches) - * 5.2.38.14 [RQ.SRS-006.RBAC.Privileges.System.Moves](#rqsrs-006rbacprivilegessystemmoves) - * 5.2.38.15 [RQ.SRS-006.RBAC.Privileges.System.Sends](#rqsrs-006rbacprivilegessystemsends) - * 5.2.38.16 [RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed](#rqsrs-006rbacprivilegessystemsendsdistributed) - * 5.2.38.17 [RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated](#rqsrs-006rbacprivilegessystemsendsreplicated) - * 5.2.38.18 [RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues](#rqsrs-006rbacprivilegessystemreplicationqueues) - * 5.2.38.19 [RQ.SRS-006.RBAC.Privileges.System.SyncReplica](#rqsrs-006rbacprivilegessystemsyncreplica) - * 5.2.38.20 [RQ.SRS-006.RBAC.Privileges.System.RestartReplica](#rqsrs-006rbacprivilegessystemrestartreplica) - * 5.2.38.21 [RQ.SRS-006.RBAC.Privileges.System.Flush](#rqsrs-006rbacprivilegessystemflush) - * 5.2.38.22 [RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed](#rqsrs-006rbacprivilegessystemflushdistributed) - * 5.2.38.23 [RQ.SRS-006.RBAC.Privileges.System.Flush.Logs](#rqsrs-006rbacprivilegessystemflushlogs) - * 5.2.39 [Sources](#sources) - * 5.2.39.1 [RQ.SRS-006.RBAC.Privileges.Sources](#rqsrs-006rbacprivilegessources) - * 5.2.39.2 [RQ.SRS-006.RBAC.Privileges.Sources.File](#rqsrs-006rbacprivilegessourcesfile) - * 5.2.39.3 [RQ.SRS-006.RBAC.Privileges.Sources.URL](#rqsrs-006rbacprivilegessourcesurl) - * 5.2.39.4 [RQ.SRS-006.RBAC.Privileges.Sources.Remote](#rqsrs-006rbacprivilegessourcesremote) - * 5.2.39.5 [RQ.SRS-006.RBAC.Privileges.Sources.MySQL](#rqsrs-006rbacprivilegessourcesmysql) - * 5.2.39.6 [RQ.SRS-006.RBAC.Privileges.Sources.ODBC](#rqsrs-006rbacprivilegessourcesodbc) - * 5.2.39.7 [RQ.SRS-006.RBAC.Privileges.Sources.JDBC](#rqsrs-006rbacprivilegessourcesjdbc) - * 5.2.39.8 [RQ.SRS-006.RBAC.Privileges.Sources.HDFS](#rqsrs-006rbacprivilegessourceshdfs) - * 5.2.39.9 [RQ.SRS-006.RBAC.Privileges.Sources.S3](#rqsrs-006rbacprivilegessourcess3) - * 5.2.40 [RQ.SRS-006.RBAC.Privileges.GrantOption](#rqsrs-006rbacprivilegesgrantoption) - * 5.2.41 [RQ.SRS-006.RBAC.Privileges.All](#rqsrs-006rbacprivilegesall) - * 5.2.42 [RQ.SRS-006.RBAC.Privileges.AdminOption](#rqsrs-006rbacprivilegesadminoption) + * 5.2 [Login](#login) + * 5.2.1 [RQ.SRS-006.RBAC.Login](#rqsrs-006rbaclogin) + * 5.2.2 [RQ.SRS-006.RBAC.Login.DefaultUser](#rqsrs-006rbaclogindefaultuser) + * 5.3 [User](#user) + * 5.3.1 [RQ.SRS-006.RBAC.User](#rqsrs-006rbacuser) + * 5.3.2 [RQ.SRS-006.RBAC.User.Roles](#rqsrs-006rbacuserroles) + * 5.3.3 [RQ.SRS-006.RBAC.User.Privileges](#rqsrs-006rbacuserprivileges) + * 5.3.4 [RQ.SRS-006.RBAC.User.Variables](#rqsrs-006rbacuservariables) + * 5.3.5 [RQ.SRS-006.RBAC.User.Variables.Constraints](#rqsrs-006rbacuservariablesconstraints) + * 5.3.6 [RQ.SRS-006.RBAC.User.SettingsProfile](#rqsrs-006rbacusersettingsprofile) + * 5.3.7 [RQ.SRS-006.RBAC.User.Quotas](#rqsrs-006rbacuserquotas) + * 5.3.8 [RQ.SRS-006.RBAC.User.RowPolicies](#rqsrs-006rbacuserrowpolicies) + * 5.3.9 [RQ.SRS-006.RBAC.User.DefaultRole](#rqsrs-006rbacuserdefaultrole) + * 5.3.10 [RQ.SRS-006.RBAC.User.RoleSelection](#rqsrs-006rbacuserroleselection) + * 5.3.11 [RQ.SRS-006.RBAC.User.ShowCreate](#rqsrs-006rbacusershowcreate) + * 5.3.12 [RQ.SRS-006.RBAC.User.ShowPrivileges](#rqsrs-006rbacusershowprivileges) + * 5.3.13 [RQ.SRS-006.RBAC.User.Use.DefaultRole](#rqsrs-006rbacuserusedefaultrole) + * 5.3.14 [RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole](#rqsrs-006rbacuseruseallroleswhennodefaultrole) + * 5.3.15 [Create User](#create-user) + * 5.3.15.1 [RQ.SRS-006.RBAC.User.Create](#rqsrs-006rbacusercreate) + * 5.3.15.2 [RQ.SRS-006.RBAC.User.Create.IfNotExists](#rqsrs-006rbacusercreateifnotexists) + * 5.3.15.3 [RQ.SRS-006.RBAC.User.Create.Replace](#rqsrs-006rbacusercreatereplace) + * 5.3.15.4 [RQ.SRS-006.RBAC.User.Create.Password.NoPassword](#rqsrs-006rbacusercreatepasswordnopassword) + * 5.3.15.5 [RQ.SRS-006.RBAC.User.Create.Password.NoPassword.Login](#rqsrs-006rbacusercreatepasswordnopasswordlogin) + * 5.3.15.6 [RQ.SRS-006.RBAC.User.Create.Password.PlainText](#rqsrs-006rbacusercreatepasswordplaintext) + * 5.3.15.7 [RQ.SRS-006.RBAC.User.Create.Password.PlainText.Login](#rqsrs-006rbacusercreatepasswordplaintextlogin) + * 5.3.15.8 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Password](#rqsrs-006rbacusercreatepasswordsha256password) + * 5.3.15.9 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Password.Login](#rqsrs-006rbacusercreatepasswordsha256passwordlogin) + * 5.3.15.10 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash](#rqsrs-006rbacusercreatepasswordsha256hash) + * 5.3.15.11 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash.Login](#rqsrs-006rbacusercreatepasswordsha256hashlogin) + * 5.3.15.12 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password](#rqsrs-006rbacusercreatepassworddoublesha1password) + * 5.3.15.13 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password.Login](#rqsrs-006rbacusercreatepassworddoublesha1passwordlogin) + * 5.3.15.14 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash](#rqsrs-006rbacusercreatepassworddoublesha1hash) + * 5.3.15.15 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash.Login](#rqsrs-006rbacusercreatepassworddoublesha1hashlogin) + * 5.3.15.16 [RQ.SRS-006.RBAC.User.Create.Host.Name](#rqsrs-006rbacusercreatehostname) + * 5.3.15.17 [RQ.SRS-006.RBAC.User.Create.Host.Regexp](#rqsrs-006rbacusercreatehostregexp) + * 5.3.15.18 [RQ.SRS-006.RBAC.User.Create.Host.IP](#rqsrs-006rbacusercreatehostip) + * 5.3.15.19 [RQ.SRS-006.RBAC.User.Create.Host.Any](#rqsrs-006rbacusercreatehostany) + * 5.3.15.20 [RQ.SRS-006.RBAC.User.Create.Host.None](#rqsrs-006rbacusercreatehostnone) + * 5.3.15.21 [RQ.SRS-006.RBAC.User.Create.Host.Local](#rqsrs-006rbacusercreatehostlocal) + * 5.3.15.22 [RQ.SRS-006.RBAC.User.Create.Host.Like](#rqsrs-006rbacusercreatehostlike) + * 5.3.15.23 [RQ.SRS-006.RBAC.User.Create.Host.Default](#rqsrs-006rbacusercreatehostdefault) + * 5.3.15.24 [RQ.SRS-006.RBAC.User.Create.DefaultRole](#rqsrs-006rbacusercreatedefaultrole) + * 5.3.15.25 [RQ.SRS-006.RBAC.User.Create.DefaultRole.None](#rqsrs-006rbacusercreatedefaultrolenone) + * 5.3.15.26 [RQ.SRS-006.RBAC.User.Create.DefaultRole.All](#rqsrs-006rbacusercreatedefaultroleall) + * 5.3.15.27 [RQ.SRS-006.RBAC.User.Create.Settings](#rqsrs-006rbacusercreatesettings) + * 5.3.15.28 [RQ.SRS-006.RBAC.User.Create.OnCluster](#rqsrs-006rbacusercreateoncluster) + * 5.3.15.29 [RQ.SRS-006.RBAC.User.Create.Syntax](#rqsrs-006rbacusercreatesyntax) + * 5.3.16 [Alter User](#alter-user) + * 5.3.16.1 [RQ.SRS-006.RBAC.User.Alter](#rqsrs-006rbacuseralter) + * 5.3.16.2 [RQ.SRS-006.RBAC.User.Alter.OrderOfEvaluation](#rqsrs-006rbacuseralterorderofevaluation) + * 5.3.16.3 [RQ.SRS-006.RBAC.User.Alter.IfExists](#rqsrs-006rbacuseralterifexists) + * 5.3.16.4 [RQ.SRS-006.RBAC.User.Alter.Cluster](#rqsrs-006rbacuseraltercluster) + * 5.3.16.5 [RQ.SRS-006.RBAC.User.Alter.Rename](#rqsrs-006rbacuseralterrename) + * 5.3.16.6 [RQ.SRS-006.RBAC.User.Alter.Password.PlainText](#rqsrs-006rbacuseralterpasswordplaintext) + * 5.3.16.7 [RQ.SRS-006.RBAC.User.Alter.Password.Sha256Password](#rqsrs-006rbacuseralterpasswordsha256password) + * 5.3.16.8 [RQ.SRS-006.RBAC.User.Alter.Password.DoubleSha1Password](#rqsrs-006rbacuseralterpassworddoublesha1password) + * 5.3.16.9 [RQ.SRS-006.RBAC.User.Alter.Host.AddDrop](#rqsrs-006rbacuseralterhostadddrop) + * 5.3.16.10 [RQ.SRS-006.RBAC.User.Alter.Host.Local](#rqsrs-006rbacuseralterhostlocal) + * 5.3.16.11 [RQ.SRS-006.RBAC.User.Alter.Host.Name](#rqsrs-006rbacuseralterhostname) + * 5.3.16.12 [RQ.SRS-006.RBAC.User.Alter.Host.Regexp](#rqsrs-006rbacuseralterhostregexp) + * 5.3.16.13 [RQ.SRS-006.RBAC.User.Alter.Host.IP](#rqsrs-006rbacuseralterhostip) + * 5.3.16.14 [RQ.SRS-006.RBAC.User.Alter.Host.Like](#rqsrs-006rbacuseralterhostlike) + * 5.3.16.15 [RQ.SRS-006.RBAC.User.Alter.Host.Any](#rqsrs-006rbacuseralterhostany) + * 5.3.16.16 [RQ.SRS-006.RBAC.User.Alter.Host.None](#rqsrs-006rbacuseralterhostnone) + * 5.3.16.17 [RQ.SRS-006.RBAC.User.Alter.DefaultRole](#rqsrs-006rbacuseralterdefaultrole) + * 5.3.16.18 [RQ.SRS-006.RBAC.User.Alter.DefaultRole.All](#rqsrs-006rbacuseralterdefaultroleall) + * 5.3.16.19 [RQ.SRS-006.RBAC.User.Alter.DefaultRole.AllExcept](#rqsrs-006rbacuseralterdefaultroleallexcept) + * 5.3.16.20 [RQ.SRS-006.RBAC.User.Alter.Settings](#rqsrs-006rbacuseraltersettings) + * 5.3.16.21 [RQ.SRS-006.RBAC.User.Alter.Settings.Min](#rqsrs-006rbacuseraltersettingsmin) + * 5.3.16.22 [RQ.SRS-006.RBAC.User.Alter.Settings.Max](#rqsrs-006rbacuseraltersettingsmax) + * 5.3.16.23 [RQ.SRS-006.RBAC.User.Alter.Settings.Profile](#rqsrs-006rbacuseraltersettingsprofile) + * 5.3.16.24 [RQ.SRS-006.RBAC.User.Alter.Syntax](#rqsrs-006rbacuseraltersyntax) + * 5.3.17 [Show Create User](#show-create-user) + * 5.3.17.1 [RQ.SRS-006.RBAC.User.ShowCreateUser](#rqsrs-006rbacusershowcreateuser) + * 5.3.17.2 [RQ.SRS-006.RBAC.User.ShowCreateUser.For](#rqsrs-006rbacusershowcreateuserfor) + * 5.3.17.3 [RQ.SRS-006.RBAC.User.ShowCreateUser.Syntax](#rqsrs-006rbacusershowcreateusersyntax) + * 5.3.18 [Drop User](#drop-user) + * 5.3.18.1 [RQ.SRS-006.RBAC.User.Drop](#rqsrs-006rbacuserdrop) + * 5.3.18.2 [RQ.SRS-006.RBAC.User.Drop.IfExists](#rqsrs-006rbacuserdropifexists) + * 5.3.18.3 [RQ.SRS-006.RBAC.User.Drop.OnCluster](#rqsrs-006rbacuserdroponcluster) + * 5.3.18.4 [RQ.SRS-006.RBAC.User.Drop.Syntax](#rqsrs-006rbacuserdropsyntax) + * 5.4 [Role](#role) + * 5.4.1 [RQ.SRS-006.RBAC.Role](#rqsrs-006rbacrole) + * 5.4.2 [RQ.SRS-006.RBAC.Role.Privileges](#rqsrs-006rbacroleprivileges) + * 5.4.3 [RQ.SRS-006.RBAC.Role.Variables](#rqsrs-006rbacrolevariables) + * 5.4.4 [RQ.SRS-006.RBAC.Role.SettingsProfile](#rqsrs-006rbacrolesettingsprofile) + * 5.4.5 [RQ.SRS-006.RBAC.Role.Quotas](#rqsrs-006rbacrolequotas) + * 5.4.6 [RQ.SRS-006.RBAC.Role.RowPolicies](#rqsrs-006rbacrolerowpolicies) + * 5.4.7 [Create Role](#create-role) + * 5.4.7.1 [RQ.SRS-006.RBAC.Role.Create](#rqsrs-006rbacrolecreate) + * 5.4.7.2 [RQ.SRS-006.RBAC.Role.Create.IfNotExists](#rqsrs-006rbacrolecreateifnotexists) + * 5.4.7.3 [RQ.SRS-006.RBAC.Role.Create.Replace](#rqsrs-006rbacrolecreatereplace) + * 5.4.7.4 [RQ.SRS-006.RBAC.Role.Create.Settings](#rqsrs-006rbacrolecreatesettings) + * 5.4.7.5 [RQ.SRS-006.RBAC.Role.Create.Syntax](#rqsrs-006rbacrolecreatesyntax) + * 5.4.8 [Alter Role](#alter-role) + * 5.4.8.1 [RQ.SRS-006.RBAC.Role.Alter](#rqsrs-006rbacrolealter) + * 5.4.8.2 [RQ.SRS-006.RBAC.Role.Alter.IfExists](#rqsrs-006rbacrolealterifexists) + * 5.4.8.3 [RQ.SRS-006.RBAC.Role.Alter.Cluster](#rqsrs-006rbacrolealtercluster) + * 5.4.8.4 [RQ.SRS-006.RBAC.Role.Alter.Rename](#rqsrs-006rbacrolealterrename) + * 5.4.8.5 [RQ.SRS-006.RBAC.Role.Alter.Settings](#rqsrs-006rbacrolealtersettings) + * 5.4.8.6 [RQ.SRS-006.RBAC.Role.Alter.Syntax](#rqsrs-006rbacrolealtersyntax) + * 5.4.9 [Drop Role](#drop-role) + * 5.4.9.1 [RQ.SRS-006.RBAC.Role.Drop](#rqsrs-006rbacroledrop) + * 5.4.9.2 [RQ.SRS-006.RBAC.Role.Drop.IfExists](#rqsrs-006rbacroledropifexists) + * 5.4.9.3 [RQ.SRS-006.RBAC.Role.Drop.Cluster](#rqsrs-006rbacroledropcluster) + * 5.4.9.4 [RQ.SRS-006.RBAC.Role.Drop.Syntax](#rqsrs-006rbacroledropsyntax) + * 5.4.10 [Show Create Role](#show-create-role) + * 5.4.10.1 [RQ.SRS-006.RBAC.Role.ShowCreate](#rqsrs-006rbacroleshowcreate) + * 5.4.10.2 [RQ.SRS-006.RBAC.Role.ShowCreate.Syntax](#rqsrs-006rbacroleshowcreatesyntax) + * 5.5 [Partial Revokes](#partial-revokes) + * 5.5.1 [RQ.SRS-006.RBAC.PartialRevokes](#rqsrs-006rbacpartialrevokes) + * 5.5.2 [RQ.SRS-006.RBAC.PartialRevoke.Syntax](#rqsrs-006rbacpartialrevokesyntax) + * 5.6 [Settings Profile](#settings-profile) + * 5.6.1 [RQ.SRS-006.RBAC.SettingsProfile](#rqsrs-006rbacsettingsprofile) + * 5.6.2 [RQ.SRS-006.RBAC.SettingsProfile.Constraints](#rqsrs-006rbacsettingsprofileconstraints) + * 5.6.3 [Create Settings Profile](#create-settings-profile) + * 5.6.3.1 [RQ.SRS-006.RBAC.SettingsProfile.Create](#rqsrs-006rbacsettingsprofilecreate) + * 5.6.3.2 [RQ.SRS-006.RBAC.SettingsProfile.Create.IfNotExists](#rqsrs-006rbacsettingsprofilecreateifnotexists) + * 5.6.3.3 [RQ.SRS-006.RBAC.SettingsProfile.Create.Replace](#rqsrs-006rbacsettingsprofilecreatereplace) + * 5.6.3.4 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables](#rqsrs-006rbacsettingsprofilecreatevariables) + * 5.6.3.5 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Value](#rqsrs-006rbacsettingsprofilecreatevariablesvalue) + * 5.6.3.6 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Constraints](#rqsrs-006rbacsettingsprofilecreatevariablesconstraints) + * 5.6.3.7 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment](#rqsrs-006rbacsettingsprofilecreateassignment) + * 5.6.3.8 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.None](#rqsrs-006rbacsettingsprofilecreateassignmentnone) + * 5.6.3.9 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.All](#rqsrs-006rbacsettingsprofilecreateassignmentall) + * 5.6.3.10 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.AllExcept](#rqsrs-006rbacsettingsprofilecreateassignmentallexcept) + * 5.6.3.11 [RQ.SRS-006.RBAC.SettingsProfile.Create.Inherit](#rqsrs-006rbacsettingsprofilecreateinherit) + * 5.6.3.12 [RQ.SRS-006.RBAC.SettingsProfile.Create.OnCluster](#rqsrs-006rbacsettingsprofilecreateoncluster) + * 5.6.3.13 [RQ.SRS-006.RBAC.SettingsProfile.Create.Syntax](#rqsrs-006rbacsettingsprofilecreatesyntax) + * 5.6.4 [Alter Settings Profile](#alter-settings-profile) + * 5.6.4.1 [RQ.SRS-006.RBAC.SettingsProfile.Alter](#rqsrs-006rbacsettingsprofilealter) + * 5.6.4.2 [RQ.SRS-006.RBAC.SettingsProfile.Alter.IfExists](#rqsrs-006rbacsettingsprofilealterifexists) + * 5.6.4.3 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Rename](#rqsrs-006rbacsettingsprofilealterrename) + * 5.6.4.4 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables](#rqsrs-006rbacsettingsprofilealtervariables) + * 5.6.4.5 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Value](#rqsrs-006rbacsettingsprofilealtervariablesvalue) + * 5.6.4.6 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Constraints](#rqsrs-006rbacsettingsprofilealtervariablesconstraints) + * 5.6.4.7 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment](#rqsrs-006rbacsettingsprofilealterassignment) + * 5.6.4.8 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.None](#rqsrs-006rbacsettingsprofilealterassignmentnone) + * 5.6.4.9 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.All](#rqsrs-006rbacsettingsprofilealterassignmentall) + * 5.6.4.10 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.AllExcept](#rqsrs-006rbacsettingsprofilealterassignmentallexcept) + * 5.6.4.11 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.Inherit](#rqsrs-006rbacsettingsprofilealterassignmentinherit) + * 5.6.4.12 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.OnCluster](#rqsrs-006rbacsettingsprofilealterassignmentoncluster) + * 5.6.4.13 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Syntax](#rqsrs-006rbacsettingsprofilealtersyntax) + * 5.6.5 [Drop Settings Profile](#drop-settings-profile) + * 5.6.5.1 [RQ.SRS-006.RBAC.SettingsProfile.Drop](#rqsrs-006rbacsettingsprofiledrop) + * 5.6.5.2 [RQ.SRS-006.RBAC.SettingsProfile.Drop.IfExists](#rqsrs-006rbacsettingsprofiledropifexists) + * 5.6.5.3 [RQ.SRS-006.RBAC.SettingsProfile.Drop.OnCluster](#rqsrs-006rbacsettingsprofiledroponcluster) + * 5.6.5.4 [RQ.SRS-006.RBAC.SettingsProfile.Drop.Syntax](#rqsrs-006rbacsettingsprofiledropsyntax) + * 5.6.6 [Show Create Settings Profile](#show-create-settings-profile) + * 5.6.6.1 [RQ.SRS-006.RBAC.SettingsProfile.ShowCreateSettingsProfile](#rqsrs-006rbacsettingsprofileshowcreatesettingsprofile) + * 5.7 [Quotas](#quotas) + * 5.7.1 [RQ.SRS-006.RBAC.Quotas](#rqsrs-006rbacquotas) + * 5.7.2 [RQ.SRS-006.RBAC.Quotas.Keyed](#rqsrs-006rbacquotaskeyed) + * 5.7.3 [RQ.SRS-006.RBAC.Quotas.Queries](#rqsrs-006rbacquotasqueries) + * 5.7.4 [RQ.SRS-006.RBAC.Quotas.Errors](#rqsrs-006rbacquotaserrors) + * 5.7.5 [RQ.SRS-006.RBAC.Quotas.ResultRows](#rqsrs-006rbacquotasresultrows) + * 5.7.6 [RQ.SRS-006.RBAC.Quotas.ReadRows](#rqsrs-006rbacquotasreadrows) + * 5.7.7 [RQ.SRS-006.RBAC.Quotas.ResultBytes](#rqsrs-006rbacquotasresultbytes) + * 5.7.8 [RQ.SRS-006.RBAC.Quotas.ReadBytes](#rqsrs-006rbacquotasreadbytes) + * 5.7.9 [RQ.SRS-006.RBAC.Quotas.ExecutionTime](#rqsrs-006rbacquotasexecutiontime) + * 5.7.10 [Create Quotas](#create-quotas) + * 5.7.10.1 [RQ.SRS-006.RBAC.Quota.Create](#rqsrs-006rbacquotacreate) + * 5.7.10.2 [RQ.SRS-006.RBAC.Quota.Create.IfNotExists](#rqsrs-006rbacquotacreateifnotexists) + * 5.7.10.3 [RQ.SRS-006.RBAC.Quota.Create.Replace](#rqsrs-006rbacquotacreatereplace) + * 5.7.10.4 [RQ.SRS-006.RBAC.Quota.Create.Cluster](#rqsrs-006rbacquotacreatecluster) + * 5.7.10.5 [RQ.SRS-006.RBAC.Quota.Create.Interval](#rqsrs-006rbacquotacreateinterval) + * 5.7.10.6 [RQ.SRS-006.RBAC.Quota.Create.Interval.Randomized](#rqsrs-006rbacquotacreateintervalrandomized) + * 5.7.10.7 [RQ.SRS-006.RBAC.Quota.Create.Queries](#rqsrs-006rbacquotacreatequeries) + * 5.7.10.8 [RQ.SRS-006.RBAC.Quota.Create.Errors](#rqsrs-006rbacquotacreateerrors) + * 5.7.10.9 [RQ.SRS-006.RBAC.Quota.Create.ResultRows](#rqsrs-006rbacquotacreateresultrows) + * 5.7.10.10 [RQ.SRS-006.RBAC.Quota.Create.ReadRows](#rqsrs-006rbacquotacreatereadrows) + * 5.7.10.11 [RQ.SRS-006.RBAC.Quota.Create.ResultBytes](#rqsrs-006rbacquotacreateresultbytes) + * 5.7.10.12 [RQ.SRS-006.RBAC.Quota.Create.ReadBytes](#rqsrs-006rbacquotacreatereadbytes) + * 5.7.10.13 [RQ.SRS-006.RBAC.Quota.Create.ExecutionTime](#rqsrs-006rbacquotacreateexecutiontime) + * 5.7.10.14 [RQ.SRS-006.RBAC.Quota.Create.NoLimits](#rqsrs-006rbacquotacreatenolimits) + * 5.7.10.15 [RQ.SRS-006.RBAC.Quota.Create.TrackingOnly](#rqsrs-006rbacquotacreatetrackingonly) + * 5.7.10.16 [RQ.SRS-006.RBAC.Quota.Create.KeyedBy](#rqsrs-006rbacquotacreatekeyedby) + * 5.7.10.17 [RQ.SRS-006.RBAC.Quota.Create.KeyedByOptions](#rqsrs-006rbacquotacreatekeyedbyoptions) + * 5.7.10.18 [RQ.SRS-006.RBAC.Quota.Create.Assignment](#rqsrs-006rbacquotacreateassignment) + * 5.7.10.19 [RQ.SRS-006.RBAC.Quota.Create.Assignment.None](#rqsrs-006rbacquotacreateassignmentnone) + * 5.7.10.20 [RQ.SRS-006.RBAC.Quota.Create.Assignment.All](#rqsrs-006rbacquotacreateassignmentall) + * 5.7.10.21 [RQ.SRS-006.RBAC.Quota.Create.Assignment.Except](#rqsrs-006rbacquotacreateassignmentexcept) + * 5.7.10.22 [RQ.SRS-006.RBAC.Quota.Create.Syntax](#rqsrs-006rbacquotacreatesyntax) + * 5.7.11 [Alter Quota](#alter-quota) + * 5.7.11.1 [RQ.SRS-006.RBAC.Quota.Alter](#rqsrs-006rbacquotaalter) + * 5.7.11.2 [RQ.SRS-006.RBAC.Quota.Alter.IfExists](#rqsrs-006rbacquotaalterifexists) + * 5.7.11.3 [RQ.SRS-006.RBAC.Quota.Alter.Rename](#rqsrs-006rbacquotaalterrename) + * 5.7.11.4 [RQ.SRS-006.RBAC.Quota.Alter.Cluster](#rqsrs-006rbacquotaaltercluster) + * 5.7.11.5 [RQ.SRS-006.RBAC.Quota.Alter.Interval](#rqsrs-006rbacquotaalterinterval) + * 5.7.11.6 [RQ.SRS-006.RBAC.Quota.Alter.Interval.Randomized](#rqsrs-006rbacquotaalterintervalrandomized) + * 5.7.11.7 [RQ.SRS-006.RBAC.Quota.Alter.Queries](#rqsrs-006rbacquotaalterqueries) + * 5.7.11.8 [RQ.SRS-006.RBAC.Quota.Alter.Errors](#rqsrs-006rbacquotaaltererrors) + * 5.7.11.9 [RQ.SRS-006.RBAC.Quota.Alter.ResultRows](#rqsrs-006rbacquotaalterresultrows) + * 5.7.11.10 [RQ.SRS-006.RBAC.Quota.Alter.ReadRows](#rqsrs-006rbacquotaalterreadrows) + * 5.7.11.11 [RQ.SRS-006.RBAC.Quota.ALter.ResultBytes](#rqsrs-006rbacquotaalterresultbytes) + * 5.7.11.12 [RQ.SRS-006.RBAC.Quota.Alter.ReadBytes](#rqsrs-006rbacquotaalterreadbytes) + * 5.7.11.13 [RQ.SRS-006.RBAC.Quota.Alter.ExecutionTime](#rqsrs-006rbacquotaalterexecutiontime) + * 5.7.11.14 [RQ.SRS-006.RBAC.Quota.Alter.NoLimits](#rqsrs-006rbacquotaalternolimits) + * 5.7.11.15 [RQ.SRS-006.RBAC.Quota.Alter.TrackingOnly](#rqsrs-006rbacquotaaltertrackingonly) + * 5.7.11.16 [RQ.SRS-006.RBAC.Quota.Alter.KeyedBy](#rqsrs-006rbacquotaalterkeyedby) + * 5.7.11.17 [RQ.SRS-006.RBAC.Quota.Alter.KeyedByOptions](#rqsrs-006rbacquotaalterkeyedbyoptions) + * 5.7.11.18 [RQ.SRS-006.RBAC.Quota.Alter.Assignment](#rqsrs-006rbacquotaalterassignment) + * 5.7.11.19 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.None](#rqsrs-006rbacquotaalterassignmentnone) + * 5.7.11.20 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.All](#rqsrs-006rbacquotaalterassignmentall) + * 5.7.11.21 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.Except](#rqsrs-006rbacquotaalterassignmentexcept) + * 5.7.11.22 [RQ.SRS-006.RBAC.Quota.Alter.Syntax](#rqsrs-006rbacquotaaltersyntax) + * 5.7.12 [Drop Quota](#drop-quota) + * 5.7.12.1 [RQ.SRS-006.RBAC.Quota.Drop](#rqsrs-006rbacquotadrop) + * 5.7.12.2 [RQ.SRS-006.RBAC.Quota.Drop.IfExists](#rqsrs-006rbacquotadropifexists) + * 5.7.12.3 [RQ.SRS-006.RBAC.Quota.Drop.Cluster](#rqsrs-006rbacquotadropcluster) + * 5.7.12.4 [RQ.SRS-006.RBAC.Quota.Drop.Syntax](#rqsrs-006rbacquotadropsyntax) + * 5.7.13 [Show Quotas](#show-quotas) + * 5.7.13.1 [RQ.SRS-006.RBAC.Quota.ShowQuotas](#rqsrs-006rbacquotashowquotas) + * 5.7.13.2 [RQ.SRS-006.RBAC.Quota.ShowQuotas.IntoOutfile](#rqsrs-006rbacquotashowquotasintooutfile) + * 5.7.13.3 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Format](#rqsrs-006rbacquotashowquotasformat) + * 5.7.13.4 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Settings](#rqsrs-006rbacquotashowquotassettings) + * 5.7.13.5 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Syntax](#rqsrs-006rbacquotashowquotassyntax) + * 5.7.14 [Show Create Quota](#show-create-quota) + * 5.7.14.1 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Name](#rqsrs-006rbacquotashowcreatequotaname) + * 5.7.14.2 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Current](#rqsrs-006rbacquotashowcreatequotacurrent) + * 5.7.14.3 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Syntax](#rqsrs-006rbacquotashowcreatequotasyntax) + * 5.8 [Row Policy](#row-policy) + * 5.8.1 [RQ.SRS-006.RBAC.RowPolicy](#rqsrs-006rbacrowpolicy) + * 5.8.2 [RQ.SRS-006.RBAC.RowPolicy.Condition](#rqsrs-006rbacrowpolicycondition) + * 5.8.3 [RQ.SRS-006.RBAC.RowPolicy.Restriction](#rqsrs-006rbacrowpolicyrestriction) + * 5.8.4 [RQ.SRS-006.RBAC.RowPolicy.Nesting](#rqsrs-006rbacrowpolicynesting) + * 5.8.5 [Create Row Policy](#create-row-policy) + * 5.8.5.1 [RQ.SRS-006.RBAC.RowPolicy.Create](#rqsrs-006rbacrowpolicycreate) + * 5.8.5.2 [RQ.SRS-006.RBAC.RowPolicy.Create.IfNotExists](#rqsrs-006rbacrowpolicycreateifnotexists) + * 5.8.5.3 [RQ.SRS-006.RBAC.RowPolicy.Create.Replace](#rqsrs-006rbacrowpolicycreatereplace) + * 5.8.5.4 [RQ.SRS-006.RBAC.RowPolicy.Create.OnCluster](#rqsrs-006rbacrowpolicycreateoncluster) + * 5.8.5.5 [RQ.SRS-006.RBAC.RowPolicy.Create.On](#rqsrs-006rbacrowpolicycreateon) + * 5.8.5.6 [RQ.SRS-006.RBAC.RowPolicy.Create.Access](#rqsrs-006rbacrowpolicycreateaccess) + * 5.8.5.7 [RQ.SRS-006.RBAC.RowPolicy.Create.Access.Permissive](#rqsrs-006rbacrowpolicycreateaccesspermissive) + * 5.8.5.8 [RQ.SRS-006.RBAC.RowPolicy.Create.Access.Restrictive](#rqsrs-006rbacrowpolicycreateaccessrestrictive) + * 5.8.5.9 [RQ.SRS-006.RBAC.RowPolicy.Create.ForSelect](#rqsrs-006rbacrowpolicycreateforselect) + * 5.8.5.10 [RQ.SRS-006.RBAC.RowPolicy.Create.Condition](#rqsrs-006rbacrowpolicycreatecondition) + * 5.8.5.11 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment](#rqsrs-006rbacrowpolicycreateassignment) + * 5.8.5.12 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.None](#rqsrs-006rbacrowpolicycreateassignmentnone) + * 5.8.5.13 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.All](#rqsrs-006rbacrowpolicycreateassignmentall) + * 5.8.5.14 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.AllExcept](#rqsrs-006rbacrowpolicycreateassignmentallexcept) + * 5.8.5.15 [RQ.SRS-006.RBAC.RowPolicy.Create.Syntax](#rqsrs-006rbacrowpolicycreatesyntax) + * 5.8.6 [Alter Row Policy](#alter-row-policy) + * 5.8.6.1 [RQ.SRS-006.RBAC.RowPolicy.Alter](#rqsrs-006rbacrowpolicyalter) + * 5.8.6.2 [RQ.SRS-006.RBAC.RowPolicy.Alter.IfExists](#rqsrs-006rbacrowpolicyalterifexists) + * 5.8.6.3 [RQ.SRS-006.RBAC.RowPolicy.Alter.ForSelect](#rqsrs-006rbacrowpolicyalterforselect) + * 5.8.6.4 [RQ.SRS-006.RBAC.RowPolicy.Alter.OnCluster](#rqsrs-006rbacrowpolicyalteroncluster) + * 5.8.6.5 [RQ.SRS-006.RBAC.RowPolicy.Alter.On](#rqsrs-006rbacrowpolicyalteron) + * 5.8.6.6 [RQ.SRS-006.RBAC.RowPolicy.Alter.Rename](#rqsrs-006rbacrowpolicyalterrename) + * 5.8.6.7 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access](#rqsrs-006rbacrowpolicyalteraccess) + * 5.8.6.8 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Permissive](#rqsrs-006rbacrowpolicyalteraccesspermissive) + * 5.8.6.9 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Restrictive](#rqsrs-006rbacrowpolicyalteraccessrestrictive) + * 5.8.6.10 [RQ.SRS-006.RBAC.RowPolicy.Alter.Condition](#rqsrs-006rbacrowpolicyaltercondition) + * 5.8.6.11 [RQ.SRS-006.RBAC.RowPolicy.Alter.Condition.None](#rqsrs-006rbacrowpolicyalterconditionnone) + * 5.8.6.12 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment](#rqsrs-006rbacrowpolicyalterassignment) + * 5.8.6.13 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.None](#rqsrs-006rbacrowpolicyalterassignmentnone) + * 5.8.6.14 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.All](#rqsrs-006rbacrowpolicyalterassignmentall) + * 5.8.6.15 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.AllExcept](#rqsrs-006rbacrowpolicyalterassignmentallexcept) + * 5.8.6.16 [RQ.SRS-006.RBAC.RowPolicy.Alter.Syntax](#rqsrs-006rbacrowpolicyaltersyntax) + * 5.8.7 [Drop Row Policy](#drop-row-policy) + * 5.8.7.1 [RQ.SRS-006.RBAC.RowPolicy.Drop](#rqsrs-006rbacrowpolicydrop) + * 5.8.7.2 [RQ.SRS-006.RBAC.RowPolicy.Drop.IfExists](#rqsrs-006rbacrowpolicydropifexists) + * 5.8.7.3 [RQ.SRS-006.RBAC.RowPolicy.Drop.On](#rqsrs-006rbacrowpolicydropon) + * 5.8.7.4 [RQ.SRS-006.RBAC.RowPolicy.Drop.OnCluster](#rqsrs-006rbacrowpolicydroponcluster) + * 5.8.7.5 [RQ.SRS-006.RBAC.RowPolicy.Drop.Syntax](#rqsrs-006rbacrowpolicydropsyntax) + * 5.8.8 [Show Create Row Policy](#show-create-row-policy) + * 5.8.8.1 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy](#rqsrs-006rbacrowpolicyshowcreaterowpolicy) + * 5.8.8.2 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.On](#rqsrs-006rbacrowpolicyshowcreaterowpolicyon) + * 5.8.8.3 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.Syntax](#rqsrs-006rbacrowpolicyshowcreaterowpolicysyntax) + * 5.8.8.4 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies](#rqsrs-006rbacrowpolicyshowrowpolicies) + * 5.8.8.5 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.On](#rqsrs-006rbacrowpolicyshowrowpolicieson) + * 5.8.8.6 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.Syntax](#rqsrs-006rbacrowpolicyshowrowpoliciessyntax) + * 5.9 [Set Default Role](#set-default-role) + * 5.9.1 [RQ.SRS-006.RBAC.SetDefaultRole](#rqsrs-006rbacsetdefaultrole) + * 5.9.2 [RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser](#rqsrs-006rbacsetdefaultrolecurrentuser) + * 5.9.3 [RQ.SRS-006.RBAC.SetDefaultRole.All](#rqsrs-006rbacsetdefaultroleall) + * 5.9.4 [RQ.SRS-006.RBAC.SetDefaultRole.AllExcept](#rqsrs-006rbacsetdefaultroleallexcept) + * 5.9.5 [RQ.SRS-006.RBAC.SetDefaultRole.None](#rqsrs-006rbacsetdefaultrolenone) + * 5.9.6 [RQ.SRS-006.RBAC.SetDefaultRole.Syntax](#rqsrs-006rbacsetdefaultrolesyntax) + * 5.10 [Set Role](#set-role) + * 5.10.1 [RQ.SRS-006.RBAC.SetRole](#rqsrs-006rbacsetrole) + * 5.10.2 [RQ.SRS-006.RBAC.SetRole.Default](#rqsrs-006rbacsetroledefault) + * 5.10.3 [RQ.SRS-006.RBAC.SetRole.None](#rqsrs-006rbacsetrolenone) + * 5.10.4 [RQ.SRS-006.RBAC.SetRole.All](#rqsrs-006rbacsetroleall) + * 5.10.5 [RQ.SRS-006.RBAC.SetRole.AllExcept](#rqsrs-006rbacsetroleallexcept) + * 5.10.6 [RQ.SRS-006.RBAC.SetRole.Syntax](#rqsrs-006rbacsetrolesyntax) + * 5.11 [Grant](#grant) + * 5.11.1 [RQ.SRS-006.RBAC.Grant.Privilege.To](#rqsrs-006rbacgrantprivilegeto) + * 5.11.2 [RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser](#rqsrs-006rbacgrantprivilegetocurrentuser) + * 5.11.3 [RQ.SRS-006.RBAC.Grant.Privilege.Select](#rqsrs-006rbacgrantprivilegeselect) + * 5.11.4 [RQ.SRS-006.RBAC.Grant.Privilege.Insert](#rqsrs-006rbacgrantprivilegeinsert) + * 5.11.5 [RQ.SRS-006.RBAC.Grant.Privilege.Alter](#rqsrs-006rbacgrantprivilegealter) + * 5.11.6 [RQ.SRS-006.RBAC.Grant.Privilege.Create](#rqsrs-006rbacgrantprivilegecreate) + * 5.11.7 [RQ.SRS-006.RBAC.Grant.Privilege.Drop](#rqsrs-006rbacgrantprivilegedrop) + * 5.11.8 [RQ.SRS-006.RBAC.Grant.Privilege.Truncate](#rqsrs-006rbacgrantprivilegetruncate) + * 5.11.9 [RQ.SRS-006.RBAC.Grant.Privilege.Optimize](#rqsrs-006rbacgrantprivilegeoptimize) + * 5.11.10 [RQ.SRS-006.RBAC.Grant.Privilege.Show](#rqsrs-006rbacgrantprivilegeshow) + * 5.11.11 [RQ.SRS-006.RBAC.Grant.Privilege.KillQuery](#rqsrs-006rbacgrantprivilegekillquery) + * 5.11.12 [RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement](#rqsrs-006rbacgrantprivilegeaccessmanagement) + * 5.11.13 [RQ.SRS-006.RBAC.Grant.Privilege.System](#rqsrs-006rbacgrantprivilegesystem) + * 5.11.14 [RQ.SRS-006.RBAC.Grant.Privilege.Introspection](#rqsrs-006rbacgrantprivilegeintrospection) + * 5.11.15 [RQ.SRS-006.RBAC.Grant.Privilege.Sources](#rqsrs-006rbacgrantprivilegesources) + * 5.11.16 [RQ.SRS-006.RBAC.Grant.Privilege.DictGet](#rqsrs-006rbacgrantprivilegedictget) + * 5.11.17 [RQ.SRS-006.RBAC.Grant.Privilege.None](#rqsrs-006rbacgrantprivilegenone) + * 5.11.18 [RQ.SRS-006.RBAC.Grant.Privilege.All](#rqsrs-006rbacgrantprivilegeall) + * 5.11.19 [RQ.SRS-006.RBAC.Grant.Privilege.GrantOption](#rqsrs-006rbacgrantprivilegegrantoption) + * 5.11.20 [RQ.SRS-006.RBAC.Grant.Privilege.On](#rqsrs-006rbacgrantprivilegeon) + * 5.11.21 [RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns](#rqsrs-006rbacgrantprivilegeprivilegecolumns) + * 5.11.22 [RQ.SRS-006.RBAC.Grant.Privilege.OnCluster](#rqsrs-006rbacgrantprivilegeoncluster) + * 5.11.23 [RQ.SRS-006.RBAC.Grant.Privilege.Syntax](#rqsrs-006rbacgrantprivilegesyntax) + * 5.12 [Revoke](#revoke) + * 5.12.1 [RQ.SRS-006.RBAC.Revoke.Privilege.Cluster](#rqsrs-006rbacrevokeprivilegecluster) + * 5.12.2 [RQ.SRS-006.RBAC.Revoke.Privilege.Select](#rqsrs-006rbacrevokeprivilegeselect) + * 5.12.3 [RQ.SRS-006.RBAC.Revoke.Privilege.Insert](#rqsrs-006rbacrevokeprivilegeinsert) + * 5.12.4 [RQ.SRS-006.RBAC.Revoke.Privilege.Alter](#rqsrs-006rbacrevokeprivilegealter) + * 5.12.5 [RQ.SRS-006.RBAC.Revoke.Privilege.Create](#rqsrs-006rbacrevokeprivilegecreate) + * 5.12.6 [RQ.SRS-006.RBAC.Revoke.Privilege.Drop](#rqsrs-006rbacrevokeprivilegedrop) + * 5.12.7 [RQ.SRS-006.RBAC.Revoke.Privilege.Truncate](#rqsrs-006rbacrevokeprivilegetruncate) + * 5.12.8 [RQ.SRS-006.RBAC.Revoke.Privilege.Optimize](#rqsrs-006rbacrevokeprivilegeoptimize) + * 5.12.9 [RQ.SRS-006.RBAC.Revoke.Privilege.Show](#rqsrs-006rbacrevokeprivilegeshow) + * 5.12.10 [RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery](#rqsrs-006rbacrevokeprivilegekillquery) + * 5.12.11 [RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement](#rqsrs-006rbacrevokeprivilegeaccessmanagement) + * 5.12.12 [RQ.SRS-006.RBAC.Revoke.Privilege.System](#rqsrs-006rbacrevokeprivilegesystem) + * 5.12.13 [RQ.SRS-006.RBAC.Revoke.Privilege.Introspection](#rqsrs-006rbacrevokeprivilegeintrospection) + * 5.12.14 [RQ.SRS-006.RBAC.Revoke.Privilege.Sources](#rqsrs-006rbacrevokeprivilegesources) + * 5.12.15 [RQ.SRS-006.RBAC.Revoke.Privilege.DictGet](#rqsrs-006rbacrevokeprivilegedictget) + * 5.12.16 [RQ.SRS-006.RBAC.Revoke.Privilege.PrivilegeColumns](#rqsrs-006rbacrevokeprivilegeprivilegecolumns) + * 5.12.17 [RQ.SRS-006.RBAC.Revoke.Privilege.Multiple](#rqsrs-006rbacrevokeprivilegemultiple) + * 5.12.18 [RQ.SRS-006.RBAC.Revoke.Privilege.All](#rqsrs-006rbacrevokeprivilegeall) + * 5.12.19 [RQ.SRS-006.RBAC.Revoke.Privilege.None](#rqsrs-006rbacrevokeprivilegenone) + * 5.12.20 [RQ.SRS-006.RBAC.Revoke.Privilege.On](#rqsrs-006rbacrevokeprivilegeon) + * 5.12.21 [RQ.SRS-006.RBAC.Revoke.Privilege.From](#rqsrs-006rbacrevokeprivilegefrom) + * 5.12.22 [RQ.SRS-006.RBAC.Revoke.Privilege.Syntax](#rqsrs-006rbacrevokeprivilegesyntax) + * 5.13 [Grant Role](#grant-role) + * 5.13.1 [RQ.SRS-006.RBAC.Grant.Role](#rqsrs-006rbacgrantrole) + * 5.13.2 [RQ.SRS-006.RBAC.Grant.Role.CurrentUser](#rqsrs-006rbacgrantrolecurrentuser) + * 5.13.3 [RQ.SRS-006.RBAC.Grant.Role.AdminOption](#rqsrs-006rbacgrantroleadminoption) + * 5.13.4 [RQ.SRS-006.RBAC.Grant.Role.OnCluster](#rqsrs-006rbacgrantroleoncluster) + * 5.13.5 [RQ.SRS-006.RBAC.Grant.Role.Syntax](#rqsrs-006rbacgrantrolesyntax) + * 5.14 [Revoke Role](#revoke-role) + * 5.14.1 [RQ.SRS-006.RBAC.Revoke.Role](#rqsrs-006rbacrevokerole) + * 5.14.2 [RQ.SRS-006.RBAC.Revoke.Role.Keywords](#rqsrs-006rbacrevokerolekeywords) + * 5.14.3 [RQ.SRS-006.RBAC.Revoke.Role.Cluster](#rqsrs-006rbacrevokerolecluster) + * 5.14.4 [RQ.SRS-006.RBAC.Revoke.AdminOption](#rqsrs-006rbacrevokeadminoption) + * 5.14.5 [RQ.SRS-006.RBAC.Revoke.Role.Syntax](#rqsrs-006rbacrevokerolesyntax) + * 5.15 [Show Grants](#show-grants) + * 5.15.1 [RQ.SRS-006.RBAC.Show.Grants](#rqsrs-006rbacshowgrants) + * 5.15.2 [RQ.SRS-006.RBAC.Show.Grants.For](#rqsrs-006rbacshowgrantsfor) + * 5.15.3 [RQ.SRS-006.RBAC.Show.Grants.Syntax](#rqsrs-006rbacshowgrantssyntax) + * 5.16 [Table Privileges](#table-privileges) + * 5.16.1 [RQ.SRS-006.RBAC.Table.PublicTables](#rqsrs-006rbactablepublictables) + * 5.16.2 [RQ.SRS-006.RBAC.Table.SensitiveTables](#rqsrs-006rbactablesensitivetables) + * 5.17 [Distributed Tables](#distributed-tables) + * 5.17.1 [RQ.SRS-006.RBAC.DistributedTable.Create](#rqsrs-006rbacdistributedtablecreate) + * 5.17.2 [RQ.SRS-006.RBAC.DistributedTable.Select](#rqsrs-006rbacdistributedtableselect) + * 5.17.3 [RQ.SRS-006.RBAC.DistributedTable.Insert](#rqsrs-006rbacdistributedtableinsert) + * 5.17.4 [RQ.SRS-006.RBAC.DistributedTable.SpecialTables](#rqsrs-006rbacdistributedtablespecialtables) + * 5.17.5 [RQ.SRS-006.RBAC.DistributedTable.LocalUser](#rqsrs-006rbacdistributedtablelocaluser) + * 5.17.6 [RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges](#rqsrs-006rbacdistributedtablesameuserdifferentnodesdifferentprivileges) + * 5.18 [Views](#views) + * 5.18.1 [View](#view) + * 5.18.1.1 [RQ.SRS-006.RBAC.View](#rqsrs-006rbacview) + * 5.18.1.2 [RQ.SRS-006.RBAC.View.Create](#rqsrs-006rbacviewcreate) + * 5.18.1.3 [RQ.SRS-006.RBAC.View.Select](#rqsrs-006rbacviewselect) + * 5.18.1.4 [RQ.SRS-006.RBAC.View.Drop](#rqsrs-006rbacviewdrop) + * 5.18.2 [Materialized View](#materialized-view) + * 5.18.2.1 [RQ.SRS-006.RBAC.MaterializedView](#rqsrs-006rbacmaterializedview) + * 5.18.2.2 [RQ.SRS-006.RBAC.MaterializedView.Create](#rqsrs-006rbacmaterializedviewcreate) + * 5.18.2.3 [RQ.SRS-006.RBAC.MaterializedView.Select](#rqsrs-006rbacmaterializedviewselect) + * 5.18.2.4 [RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable](#rqsrs-006rbacmaterializedviewselecttargettable) + * 5.18.2.5 [RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable](#rqsrs-006rbacmaterializedviewselectsourcetable) + * 5.18.2.6 [RQ.SRS-006.RBAC.MaterializedView.Drop](#rqsrs-006rbacmaterializedviewdrop) + * 5.18.2.7 [RQ.SRS-006.RBAC.MaterializedView.ModifyQuery](#rqsrs-006rbacmaterializedviewmodifyquery) + * 5.18.2.8 [RQ.SRS-006.RBAC.MaterializedView.Insert](#rqsrs-006rbacmaterializedviewinsert) + * 5.18.2.9 [RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable](#rqsrs-006rbacmaterializedviewinsertsourcetable) + * 5.18.2.10 [RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable](#rqsrs-006rbacmaterializedviewinserttargettable) + * 5.18.3 [Live View](#live-view) + * 5.18.3.1 [RQ.SRS-006.RBAC.LiveView](#rqsrs-006rbacliveview) + * 5.18.3.2 [RQ.SRS-006.RBAC.LiveView.Create](#rqsrs-006rbacliveviewcreate) + * 5.18.3.3 [RQ.SRS-006.RBAC.LiveView.Select](#rqsrs-006rbacliveviewselect) + * 5.18.3.4 [RQ.SRS-006.RBAC.LiveView.Drop](#rqsrs-006rbacliveviewdrop) + * 5.18.3.5 [RQ.SRS-006.RBAC.LiveView.Refresh](#rqsrs-006rbacliveviewrefresh) + * 5.19 [Select](#select) + * 5.19.1 [RQ.SRS-006.RBAC.Select](#rqsrs-006rbacselect) + * 5.19.2 [RQ.SRS-006.RBAC.Select.Column](#rqsrs-006rbacselectcolumn) + * 5.19.3 [RQ.SRS-006.RBAC.Select.Cluster](#rqsrs-006rbacselectcluster) + * 5.19.4 [RQ.SRS-006.RBAC.Select.TableEngines](#rqsrs-006rbacselecttableengines) + * 5.20 [Insert](#insert) + * 5.20.1 [RQ.SRS-006.RBAC.Insert](#rqsrs-006rbacinsert) + * 5.20.2 [RQ.SRS-006.RBAC.Insert.Column](#rqsrs-006rbacinsertcolumn) + * 5.20.3 [RQ.SRS-006.RBAC.Insert.Cluster](#rqsrs-006rbacinsertcluster) + * 5.20.4 [RQ.SRS-006.RBAC.Insert.TableEngines](#rqsrs-006rbacinserttableengines) + * 5.21 [Alter](#alter) + * 5.21.1 [Alter Column](#alter-column) + * 5.21.1.1 [RQ.SRS-006.RBAC.Privileges.AlterColumn](#rqsrs-006rbacprivilegesaltercolumn) + * 5.21.1.2 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant](#rqsrs-006rbacprivilegesaltercolumngrant) + * 5.21.1.3 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke](#rqsrs-006rbacprivilegesaltercolumnrevoke) + * 5.21.1.4 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Column](#rqsrs-006rbacprivilegesaltercolumncolumn) + * 5.21.1.5 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster](#rqsrs-006rbacprivilegesaltercolumncluster) + * 5.21.1.6 [RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines](#rqsrs-006rbacprivilegesaltercolumntableengines) + * 5.21.2 [Alter Index](#alter-index) + * 5.21.2.1 [RQ.SRS-006.RBAC.Privileges.AlterIndex](#rqsrs-006rbacprivilegesalterindex) + * 5.21.2.2 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant](#rqsrs-006rbacprivilegesalterindexgrant) + * 5.21.2.3 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke](#rqsrs-006rbacprivilegesalterindexrevoke) + * 5.21.2.4 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster](#rqsrs-006rbacprivilegesalterindexcluster) + * 5.21.2.5 [RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines](#rqsrs-006rbacprivilegesalterindextableengines) + * 5.21.3 [Alter Constraint](#alter-constraint) + * 5.21.3.1 [RQ.SRS-006.RBAC.Privileges.AlterConstraint](#rqsrs-006rbacprivilegesalterconstraint) + * 5.21.3.2 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant](#rqsrs-006rbacprivilegesalterconstraintgrant) + * 5.21.3.3 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke](#rqsrs-006rbacprivilegesalterconstraintrevoke) + * 5.21.3.4 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster](#rqsrs-006rbacprivilegesalterconstraintcluster) + * 5.21.3.5 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines](#rqsrs-006rbacprivilegesalterconstrainttableengines) + * 5.21.4 [Alter TTL](#alter-ttl) + * 5.21.4.1 [RQ.SRS-006.RBAC.Privileges.AlterTTL](#rqsrs-006rbacprivilegesalterttl) + * 5.21.4.2 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant](#rqsrs-006rbacprivilegesalterttlgrant) + * 5.21.4.3 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke](#rqsrs-006rbacprivilegesalterttlrevoke) + * 5.21.4.4 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster](#rqsrs-006rbacprivilegesalterttlcluster) + * 5.21.4.5 [RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines](#rqsrs-006rbacprivilegesalterttltableengines) + * 5.21.5 [Alter Settings](#alter-settings) + * 5.21.5.1 [RQ.SRS-006.RBAC.Privileges.AlterSettings](#rqsrs-006rbacprivilegesaltersettings) + * 5.21.5.2 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant](#rqsrs-006rbacprivilegesaltersettingsgrant) + * 5.21.5.3 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke](#rqsrs-006rbacprivilegesaltersettingsrevoke) + * 5.21.5.4 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster](#rqsrs-006rbacprivilegesaltersettingscluster) + * 5.21.5.5 [RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines](#rqsrs-006rbacprivilegesaltersettingstableengines) + * 5.21.6 [Alter Update](#alter-update) + * 5.21.6.1 [RQ.SRS-006.RBAC.Privileges.AlterUpdate](#rqsrs-006rbacprivilegesalterupdate) + * 5.21.6.2 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant](#rqsrs-006rbacprivilegesalterupdategrant) + * 5.21.6.3 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke](#rqsrs-006rbacprivilegesalterupdaterevoke) + * 5.21.6.4 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines](#rqsrs-006rbacprivilegesalterupdatetableengines) + * 5.21.7 [Alter Delete](#alter-delete) + * 5.21.7.1 [RQ.SRS-006.RBAC.Privileges.AlterDelete](#rqsrs-006rbacprivilegesalterdelete) + * 5.21.7.2 [RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant](#rqsrs-006rbacprivilegesalterdeletegrant) + * 5.21.7.3 [RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke](#rqsrs-006rbacprivilegesalterdeleterevoke) + * 5.21.7.4 [RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines](#rqsrs-006rbacprivilegesalterdeletetableengines) + * 5.21.8 [Alter Freeze Partition](#alter-freeze-partition) + * 5.21.8.1 [RQ.SRS-006.RBAC.Privileges.AlterFreeze](#rqsrs-006rbacprivilegesalterfreeze) + * 5.21.8.2 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant](#rqsrs-006rbacprivilegesalterfreezegrant) + * 5.21.8.3 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke](#rqsrs-006rbacprivilegesalterfreezerevoke) + * 5.21.8.4 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines](#rqsrs-006rbacprivilegesalterfreezetableengines) + * 5.21.9 [Alter Fetch Partition](#alter-fetch-partition) + * 5.21.9.1 [RQ.SRS-006.RBAC.Privileges.AlterFetch](#rqsrs-006rbacprivilegesalterfetch) + * 5.21.9.2 [RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant](#rqsrs-006rbacprivilegesalterfetchgrant) + * 5.21.9.3 [RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke](#rqsrs-006rbacprivilegesalterfetchrevoke) + * 5.21.9.4 [RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines](#rqsrs-006rbacprivilegesalterfetchtableengines) + * 5.21.10 [Alter Move Partition](#alter-move-partition) + * 5.21.10.1 [RQ.SRS-006.RBAC.Privileges.AlterMove](#rqsrs-006rbacprivilegesaltermove) + * 5.21.10.2 [RQ.SRS-006.RBAC.Privileges.AlterMove.Grant](#rqsrs-006rbacprivilegesaltermovegrant) + * 5.21.10.3 [RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke](#rqsrs-006rbacprivilegesaltermoverevoke) + * 5.21.10.4 [RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines](#rqsrs-006rbacprivilegesaltermovetableengines) + * 5.22 [Create](#create) + * 5.22.1 [RQ.SRS-006.RBAC.Privileges.CreateTable](#rqsrs-006rbacprivilegescreatetable) + * 5.22.2 [RQ.SRS-006.RBAC.Privileges.CreateDatabase](#rqsrs-006rbacprivilegescreatedatabase) + * 5.22.3 [RQ.SRS-006.RBAC.Privileges.CreateDictionary](#rqsrs-006rbacprivilegescreatedictionary) + * 5.22.4 [RQ.SRS-006.RBAC.Privileges.CreateTemporaryTable](#rqsrs-006rbacprivilegescreatetemporarytable) + * 5.23 [Attach](#attach) + * 5.23.1 [RQ.SRS-006.RBAC.Privileges.AttachDatabase](#rqsrs-006rbacprivilegesattachdatabase) + * 5.23.2 [RQ.SRS-006.RBAC.Privileges.AttachDictionary](#rqsrs-006rbacprivilegesattachdictionary) + * 5.23.3 [RQ.SRS-006.RBAC.Privileges.AttachTemporaryTable](#rqsrs-006rbacprivilegesattachtemporarytable) + * 5.23.4 [RQ.SRS-006.RBAC.Privileges.AttachTable](#rqsrs-006rbacprivilegesattachtable) + * 5.24 [Drop](#drop) + * 5.24.1 [RQ.SRS-006.RBAC.Privileges.DropTable](#rqsrs-006rbacprivilegesdroptable) + * 5.24.2 [RQ.SRS-006.RBAC.Privileges.DropDatabase](#rqsrs-006rbacprivilegesdropdatabase) + * 5.24.3 [RQ.SRS-006.RBAC.Privileges.DropDictionary](#rqsrs-006rbacprivilegesdropdictionary) + * 5.25 [Detach](#detach) + * 5.25.1 [RQ.SRS-006.RBAC.Privileges.DetachTable](#rqsrs-006rbacprivilegesdetachtable) + * 5.25.2 [RQ.SRS-006.RBAC.Privileges.DetachView](#rqsrs-006rbacprivilegesdetachview) + * 5.25.3 [RQ.SRS-006.RBAC.Privileges.DetachDatabase](#rqsrs-006rbacprivilegesdetachdatabase) + * 5.25.4 [RQ.SRS-006.RBAC.Privileges.DetachDictionary](#rqsrs-006rbacprivilegesdetachdictionary) + * 5.26 [Truncate](#truncate) + * 5.26.1 [RQ.SRS-006.RBAC.Privileges.Truncate](#rqsrs-006rbacprivilegestruncate) + * 5.27 [Optimize](#optimize) + * 5.27.1 [RQ.SRS-006.RBAC.Privileges.Optimize](#rqsrs-006rbacprivilegesoptimize) + * 5.28 [Kill Query](#kill-query) + * 5.28.1 [RQ.SRS-006.RBAC.Privileges.KillQuery](#rqsrs-006rbacprivilegeskillquery) + * 5.29 [Kill Mutation](#kill-mutation) + * 5.29.1 [RQ.SRS-006.RBAC.Privileges.KillMutation](#rqsrs-006rbacprivilegeskillmutation) + * 5.29.2 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate](#rqsrs-006rbacprivilegeskillmutationalterupdate) + * 5.29.3 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete](#rqsrs-006rbacprivilegeskillmutationalterdelete) + * 5.29.4 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn](#rqsrs-006rbacprivilegeskillmutationalterdropcolumn) + * 5.30 [Show](#show) + * 5.30.1 [RQ.SRS-006.RBAC.ShowTables.Privilege](#rqsrs-006rbacshowtablesprivilege) + * 5.30.2 [RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege](#rqsrs-006rbacshowtablesrequiredprivilege) + * 5.30.3 [RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege](#rqsrs-006rbacexiststablerequiredprivilege) + * 5.30.4 [RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege](#rqsrs-006rbacchecktablerequiredprivilege) + * 5.30.5 [RQ.SRS-006.RBAC.ShowDatabases.Privilege](#rqsrs-006rbacshowdatabasesprivilege) + * 5.30.6 [RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege](#rqsrs-006rbacshowdatabasesrequiredprivilege) + * 5.30.7 [RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege](#rqsrs-006rbacshowcreatedatabaserequiredprivilege) + * 5.30.8 [RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege](#rqsrs-006rbacusedatabaserequiredprivilege) + * 5.30.9 [RQ.SRS-006.RBAC.ShowColumns.Privilege](#rqsrs-006rbacshowcolumnsprivilege) + * 5.30.10 [RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege](#rqsrs-006rbacshowcreatetablerequiredprivilege) + * 5.30.11 [RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege](#rqsrs-006rbacdescribetablerequiredprivilege) + * 5.30.12 [RQ.SRS-006.RBAC.ShowDictionaries.Privilege](#rqsrs-006rbacshowdictionariesprivilege) + * 5.30.13 [RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege](#rqsrs-006rbacshowdictionariesrequiredprivilege) + * 5.30.14 [RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege](#rqsrs-006rbacshowcreatedictionaryrequiredprivilege) + * 5.30.15 [RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege](#rqsrs-006rbacexistsdictionaryrequiredprivilege) + * 5.31 [Access Management](#access-management) + * 5.31.1 [RQ.SRS-006.RBAC.Privileges.CreateUser](#rqsrs-006rbacprivilegescreateuser) + * 5.31.2 [RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole](#rqsrs-006rbacprivilegescreateuserdefaultrole) + * 5.31.3 [RQ.SRS-006.RBAC.Privileges.AlterUser](#rqsrs-006rbacprivilegesalteruser) + * 5.31.4 [RQ.SRS-006.RBAC.Privileges.DropUser](#rqsrs-006rbacprivilegesdropuser) + * 5.31.5 [RQ.SRS-006.RBAC.Privileges.CreateRole](#rqsrs-006rbacprivilegescreaterole) + * 5.31.6 [RQ.SRS-006.RBAC.Privileges.AlterRole](#rqsrs-006rbacprivilegesalterrole) + * 5.31.7 [RQ.SRS-006.RBAC.Privileges.DropRole](#rqsrs-006rbacprivilegesdroprole) + * 5.31.8 [RQ.SRS-006.RBAC.Privileges.CreateRowPolicy](#rqsrs-006rbacprivilegescreaterowpolicy) + * 5.31.9 [RQ.SRS-006.RBAC.Privileges.AlterRowPolicy](#rqsrs-006rbacprivilegesalterrowpolicy) + * 5.31.10 [RQ.SRS-006.RBAC.Privileges.DropRowPolicy](#rqsrs-006rbacprivilegesdroprowpolicy) + * 5.31.11 [RQ.SRS-006.RBAC.Privileges.CreateQuota](#rqsrs-006rbacprivilegescreatequota) + * 5.31.12 [RQ.SRS-006.RBAC.Privileges.AlterQuota](#rqsrs-006rbacprivilegesalterquota) + * 5.31.13 [RQ.SRS-006.RBAC.Privileges.DropQuota](#rqsrs-006rbacprivilegesdropquota) + * 5.31.14 [RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile](#rqsrs-006rbacprivilegescreatesettingsprofile) + * 5.31.15 [RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile](#rqsrs-006rbacprivilegesaltersettingsprofile) + * 5.31.16 [RQ.SRS-006.RBAC.Privileges.DropSettingsProfile](#rqsrs-006rbacprivilegesdropsettingsprofile) + * 5.31.17 [RQ.SRS-006.RBAC.Privileges.RoleAdmin](#rqsrs-006rbacprivilegesroleadmin) + * 5.31.18 [Show Access](#show-access) + * 5.31.18.1 [RQ.SRS-006.RBAC.ShowUsers.Privilege](#rqsrs-006rbacshowusersprivilege) + * 5.31.18.2 [RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege](#rqsrs-006rbacshowusersrequiredprivilege) + * 5.31.18.3 [RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege](#rqsrs-006rbacshowcreateuserrequiredprivilege) + * 5.31.18.4 [RQ.SRS-006.RBAC.ShowRoles.Privilege](#rqsrs-006rbacshowrolesprivilege) + * 5.31.18.5 [RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege](#rqsrs-006rbacshowrolesrequiredprivilege) + * 5.31.18.6 [RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege](#rqsrs-006rbacshowcreaterolerequiredprivilege) + * 5.31.18.7 [RQ.SRS-006.RBAC.ShowRowPolicies.Privilege](#rqsrs-006rbacshowrowpoliciesprivilege) + * 5.31.18.8 [RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege](#rqsrs-006rbacshowrowpoliciesrequiredprivilege) + * 5.31.18.9 [RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege](#rqsrs-006rbacshowcreaterowpolicyrequiredprivilege) + * 5.31.18.10 [RQ.SRS-006.RBAC.ShowQuotas.Privilege](#rqsrs-006rbacshowquotasprivilege) + * 5.31.18.11 [RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege](#rqsrs-006rbacshowquotasrequiredprivilege) + * 5.31.18.12 [RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege](#rqsrs-006rbacshowcreatequotarequiredprivilege) + * 5.31.18.13 [RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege](#rqsrs-006rbacshowsettingsprofilesprivilege) + * 5.31.18.14 [RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege](#rqsrs-006rbacshowsettingsprofilesrequiredprivilege) + * 5.31.18.15 [RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege](#rqsrs-006rbacshowcreatesettingsprofilerequiredprivilege) + * 5.32 [dictGet](#dictget) + * 5.32.1 [RQ.SRS-006.RBAC.dictGet.Privilege](#rqsrs-006rbacdictgetprivilege) + * 5.32.2 [RQ.SRS-006.RBAC.dictGet.RequiredPrivilege](#rqsrs-006rbacdictgetrequiredprivilege) + * 5.32.3 [RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege](#rqsrs-006rbacdictgettyperequiredprivilege) + * 5.32.4 [RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege](#rqsrs-006rbacdictgetordefaultrequiredprivilege) + * 5.32.5 [RQ.SRS-006.RBAC.dictHas.RequiredPrivilege](#rqsrs-006rbacdicthasrequiredprivilege) + * 5.32.6 [RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege](#rqsrs-006rbacdictgethierarchyrequiredprivilege) + * 5.32.7 [RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege](#rqsrs-006rbacdictisinrequiredprivilege) + * 5.33 [Introspection](#introspection) + * 5.33.1 [RQ.SRS-006.RBAC.Privileges.Introspection](#rqsrs-006rbacprivilegesintrospection) + * 5.33.2 [RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine](#rqsrs-006rbacprivilegesintrospectionaddresstoline) + * 5.33.3 [RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol](#rqsrs-006rbacprivilegesintrospectionaddresstosymbol) + * 5.33.4 [RQ.SRS-006.RBAC.Privileges.Introspection.demangle](#rqsrs-006rbacprivilegesintrospectiondemangle) + * 5.34 [System](#system) + * 5.34.1 [RQ.SRS-006.RBAC.Privileges.System.Shutdown](#rqsrs-006rbacprivilegessystemshutdown) + * 5.34.2 [RQ.SRS-006.RBAC.Privileges.System.DropCache](#rqsrs-006rbacprivilegessystemdropcache) + * 5.34.3 [RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS](#rqsrs-006rbacprivilegessystemdropcachedns) + * 5.34.4 [RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark](#rqsrs-006rbacprivilegessystemdropcachemark) + * 5.34.5 [RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed](#rqsrs-006rbacprivilegessystemdropcacheuncompressed) + * 5.34.6 [RQ.SRS-006.RBAC.Privileges.System.Reload](#rqsrs-006rbacprivilegessystemreload) + * 5.34.7 [RQ.SRS-006.RBAC.Privileges.System.Reload.Config](#rqsrs-006rbacprivilegessystemreloadconfig) + * 5.34.8 [RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary](#rqsrs-006rbacprivilegessystemreloaddictionary) + * 5.34.9 [RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries](#rqsrs-006rbacprivilegessystemreloaddictionaries) + * 5.34.10 [RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries](#rqsrs-006rbacprivilegessystemreloadembeddeddictionaries) + * 5.34.11 [RQ.SRS-006.RBAC.Privileges.System.Merges](#rqsrs-006rbacprivilegessystemmerges) + * 5.34.12 [RQ.SRS-006.RBAC.Privileges.System.TTLMerges](#rqsrs-006rbacprivilegessystemttlmerges) + * 5.34.13 [RQ.SRS-006.RBAC.Privileges.System.Fetches](#rqsrs-006rbacprivilegessystemfetches) + * 5.34.14 [RQ.SRS-006.RBAC.Privileges.System.Moves](#rqsrs-006rbacprivilegessystemmoves) + * 5.34.15 [RQ.SRS-006.RBAC.Privileges.System.Sends](#rqsrs-006rbacprivilegessystemsends) + * 5.34.16 [RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed](#rqsrs-006rbacprivilegessystemsendsdistributed) + * 5.34.17 [RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated](#rqsrs-006rbacprivilegessystemsendsreplicated) + * 5.34.18 [RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues](#rqsrs-006rbacprivilegessystemreplicationqueues) + * 5.34.19 [RQ.SRS-006.RBAC.Privileges.System.SyncReplica](#rqsrs-006rbacprivilegessystemsyncreplica) + * 5.34.20 [RQ.SRS-006.RBAC.Privileges.System.RestartReplica](#rqsrs-006rbacprivilegessystemrestartreplica) + * 5.34.21 [RQ.SRS-006.RBAC.Privileges.System.Flush](#rqsrs-006rbacprivilegessystemflush) + * 5.34.22 [RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed](#rqsrs-006rbacprivilegessystemflushdistributed) + * 5.34.23 [RQ.SRS-006.RBAC.Privileges.System.Flush.Logs](#rqsrs-006rbacprivilegessystemflushlogs) + * 5.35 [Sources](#sources) + * 5.35.1 [RQ.SRS-006.RBAC.Privileges.Sources](#rqsrs-006rbacprivilegessources) + * 5.35.2 [RQ.SRS-006.RBAC.Privileges.Sources.File](#rqsrs-006rbacprivilegessourcesfile) + * 5.35.3 [RQ.SRS-006.RBAC.Privileges.Sources.URL](#rqsrs-006rbacprivilegessourcesurl) + * 5.35.4 [RQ.SRS-006.RBAC.Privileges.Sources.Remote](#rqsrs-006rbacprivilegessourcesremote) + * 5.35.5 [RQ.SRS-006.RBAC.Privileges.Sources.MySQL](#rqsrs-006rbacprivilegessourcesmysql) + * 5.35.6 [RQ.SRS-006.RBAC.Privileges.Sources.ODBC](#rqsrs-006rbacprivilegessourcesodbc) + * 5.35.7 [RQ.SRS-006.RBAC.Privileges.Sources.JDBC](#rqsrs-006rbacprivilegessourcesjdbc) + * 5.35.8 [RQ.SRS-006.RBAC.Privileges.Sources.HDFS](#rqsrs-006rbacprivilegessourceshdfs) + * 5.35.9 [RQ.SRS-006.RBAC.Privileges.Sources.S3](#rqsrs-006rbacprivilegessourcess3) + * 5.36 [RQ.SRS-006.RBAC.Privileges.GrantOption](#rqsrs-006rbacprivilegesgrantoption) + * 5.37 [RQ.SRS-006.RBAC.Privileges.All](#rqsrs-006rbacprivilegesall) + * 5.38 [RQ.SRS-006.RBAC.Privileges.RoleAll](#rqsrs-006rbacprivilegesroleall) + * 5.39 [RQ.SRS-006.RBAC.Privileges.None](#rqsrs-006rbacprivilegesnone) + * 5.40 [RQ.SRS-006.RBAC.Privileges.AdminOption](#rqsrs-006rbacprivilegesadminoption) * 6 [References](#references) ## Revision History @@ -631,256 +663,103 @@ version: 1.0 [ClickHouse] SHALL support role based access control. -#### Login +### Login -##### RQ.SRS-006.RBAC.Login +#### RQ.SRS-006.RBAC.Login version: 1.0 [ClickHouse] SHALL only allow access to the server for a given user only when correct username and password are used during the connection to the server. -##### RQ.SRS-006.RBAC.Login.DefaultUser +#### RQ.SRS-006.RBAC.Login.DefaultUser version: 1.0 [ClickHouse] SHALL use the **default user** when no username and password are specified during the connection to the server. -#### User +### User -##### RQ.SRS-006.RBAC.User +#### RQ.SRS-006.RBAC.User version: 1.0 [ClickHouse] SHALL support creation and manipulation of one or more **user** accounts to which roles, privileges, settings profile, quotas and row policies can be assigned. -##### RQ.SRS-006.RBAC.User.Roles +#### RQ.SRS-006.RBAC.User.Roles version: 1.0 [ClickHouse] SHALL support assigning one or more **roles** to a **user**. -##### RQ.SRS-006.RBAC.User.Privileges +#### RQ.SRS-006.RBAC.User.Privileges version: 1.0 [ClickHouse] SHALL support assigning one or more privileges to a **user**. -##### RQ.SRS-006.RBAC.User.Variables +#### RQ.SRS-006.RBAC.User.Variables version: 1.0 [ClickHouse] SHALL support assigning one or more variables to a **user**. -##### RQ.SRS-006.RBAC.User.Variables.Constraints +#### RQ.SRS-006.RBAC.User.Variables.Constraints version: 1.0 [ClickHouse] SHALL support assigning min, max and read-only constraints for the variables that can be set and read by the **user**. -##### RQ.SRS-006.RBAC.User.SettingsProfile +#### RQ.SRS-006.RBAC.User.SettingsProfile version: 1.0 [ClickHouse] SHALL support assigning one or more **settings profiles** to a **user**. -##### RQ.SRS-006.RBAC.User.Quotas +#### RQ.SRS-006.RBAC.User.Quotas version: 1.0 [ClickHouse] SHALL support assigning one or more **quotas** to a **user**. -##### RQ.SRS-006.RBAC.User.RowPolicies +#### RQ.SRS-006.RBAC.User.RowPolicies version: 1.0 [ClickHouse] SHALL support assigning one or more **row policies** to a **user**. -##### RQ.SRS-006.RBAC.User.AccountLock -version: 1.0 - -[ClickHouse] SHALL support locking and unlocking of **user** accounts. - -##### RQ.SRS-006.RBAC.User.AccountLock.DenyAccess -version: 1.0 - -[ClickHouse] SHALL deny access to the user whose account is locked. - -##### RQ.SRS-006.RBAC.User.DefaultRole +#### RQ.SRS-006.RBAC.User.DefaultRole version: 1.0 [ClickHouse] SHALL support assigning a default role to a **user**. -##### RQ.SRS-006.RBAC.User.RoleSelection +#### RQ.SRS-006.RBAC.User.RoleSelection version: 1.0 [ClickHouse] SHALL support selection of one or more **roles** from the available roles -that are assigned to a **user**. +that are assigned to a **user** using `SET ROLE` statement. -##### RQ.SRS-006.RBAC.User.ShowCreate +#### RQ.SRS-006.RBAC.User.ShowCreate version: 1.0 [ClickHouse] SHALL support showing the command of how **user** account was created. -##### RQ.SRS-006.RBAC.User.ShowPrivileges +#### RQ.SRS-006.RBAC.User.ShowPrivileges version: 1.0 [ClickHouse] SHALL support listing the privileges of the **user**. -#### Role - -##### RQ.SRS-006.RBAC.Role -version: 1.0 - -[ClikHouse] SHALL support creation and manipulation of **roles** -to which privileges, settings profile, quotas and row policies can be -assigned. - -##### RQ.SRS-006.RBAC.Role.Privileges -version: 1.0 - -[ClickHouse] SHALL support assigning one or more privileges to a **role**. - -##### RQ.SRS-006.RBAC.Role.Variables -version: 1.0 - -[ClickHouse] SHALL support assigning one or more variables to a **role**. - -##### RQ.SRS-006.RBAC.Role.SettingsProfile -version: 1.0 - -[ClickHouse] SHALL support assigning one or more **settings profiles** -to a **role**. - -##### RQ.SRS-006.RBAC.Role.Quotas -version: 1.0 - -[ClickHouse] SHALL support assigning one or more **quotas** to a **role**. - -##### RQ.SRS-006.RBAC.Role.RowPolicies -version: 1.0 - -[ClickHouse] SHALL support assigning one or more **row policies** to a **role**. - -#### Partial Revokes - -##### RQ.SRS-006.RBAC.PartialRevokes -version: 1.0 - -[ClickHouse] SHALL support partial revoking of privileges granted -to a **user** or a **role**. - -#### Settings Profile - -##### RQ.SRS-006.RBAC.SettingsProfile -version: 1.0 - -[ClickHouse] SHALL support creation and manipulation of **settings profiles** -that can include value definition for one or more variables and can -can be assigned to one or more **users** or **roles**. - -##### RQ.SRS-006.RBAC.SettingsProfile.Constraints -version: 1.0 - -[ClickHouse] SHALL support assigning min, max and read-only constraints -for the variables specified in the **settings profile**. - -##### RQ.SRS-006.RBAC.SettingsProfile.ShowCreate -version: 1.0 - -[ClickHouse] SHALL support showing the command of how **setting profile** was created. - -#### Quotas - -##### RQ.SRS-006.RBAC.Quotas -version: 1.0 - -[ClickHouse] SHALL support creation and manipulation of **quotas** -that can be used to limit resource usage by a **user** or a **role** -over a period of time. - -##### RQ.SRS-006.RBAC.Quotas.Keyed -version: 1.0 - -[ClickHouse] SHALL support creating **quotas** that are keyed -so that a quota is tracked separately for each key value. - -##### RQ.SRS-006.RBAC.Quotas.Queries -version: 1.0 - -[ClickHouse] SHALL support setting **queries** quota to limit the total number of requests. - -##### RQ.SRS-006.RBAC.Quotas.Errors -version: 1.0 - -[ClickHouse] SHALL support setting **errors** quota to limit the number of queries that threw an exception. - -##### RQ.SRS-006.RBAC.Quotas.ResultRows -version: 1.0 - -[ClickHouse] SHALL support setting **result rows** quota to limit the -the total number of rows given as the result. - -##### RQ.SRS-006.RBAC.Quotas.ReadRows -version: 1.0 - -[ClickHouse] SHALL support setting **read rows** quota to limit the total -number of source rows read from tables for running the query on all remote servers. - -##### RQ.SRS-006.RBAC.Quotas.ResultBytes -version: 1.0 - -[ClickHouse] SHALL support setting **result bytes** quota to limit the total number -of bytes that can be returned as the result. - -##### RQ.SRS-006.RBAC.Quotas.ReadBytes -version: 1.0 - -[ClickHouse] SHALL support setting **read bytes** quota to limit the total number -of source bytes read from tables for running the query on all remote servers. - -##### RQ.SRS-006.RBAC.Quotas.ExecutionTime -version: 1.0 - -[ClickHouse] SHALL support setting **execution time** quota to limit the maximum -query execution time. - -##### RQ.SRS-006.RBAC.Quotas.ShowCreate -version: 1.0 - -[ClickHouse] SHALL support showing the command of how **quota** was created. - -#### Row Policy - -##### RQ.SRS-006.RBAC.RowPolicy -version: 1.0 - -[ClickHouse] SHALL support creation and manipulation of table **row policies** -that can be used to limit access to the table contents for a **user** or a **role** -using a specified **condition**. - -##### RQ.SRS-006.RBAC.RowPolicy.Condition -version: 1.0 - -[ClickHouse] SHALL support row policy **conditions** that can be any SQL -expression that returns a boolean. - -##### RQ.SRS-006.RBAC.RowPolicy.ShowCreate -version: 1.0 - -[ClickHouse] SHALL support showing the command of how **row policy** was created. - -### Specific - -##### RQ.SRS-006.RBAC.User.Use.DefaultRole +#### RQ.SRS-006.RBAC.User.Use.DefaultRole version: 1.0 [ClickHouse] SHALL by default use default role or roles assigned to the user if specified. -##### RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole +#### RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole version: 1.0 [ClickHouse] SHALL by default use all the roles assigned to the user if no default role or roles are specified for the user. +#### Create User + ##### RQ.SRS-006.RBAC.User.Create version: 1.0 @@ -1078,6 +957,8 @@ CREATE USER [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name] [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] ``` +#### Alter User + ##### RQ.SRS-006.RBAC.User.Alter version: 1.0 @@ -1094,7 +975,8 @@ the left. version: 1.0 [ClickHouse] SHALL support `IF EXISTS` clause in the `ALTER USER` statement -to skip raising an exception (producing a warning instead) if a user with the specified **name** does not exist. If the `IF EXISTS` clause is not specified then an exception SHALL be raised if a user with the **name** does not exist. +to skip raising an exception (producing a warning instead) if a user with the specified **name** does not exist. +If the `IF EXISTS` clause is not specified then an exception SHALL be raised if a user with the **name** does not exist. ##### RQ.SRS-006.RBAC.User.Alter.Cluster version: 1.0 @@ -1132,7 +1014,8 @@ to some password as identification when altering user account using ##### RQ.SRS-006.RBAC.User.Alter.Host.AddDrop version: 1.0 -[ClickHouse] SHALL support altering user by adding and dropping access to hosts with the `ADD HOST` or the `DROP HOST`in the `ALTER USER` statement. +[ClickHouse] SHALL support altering user by adding and dropping access to hosts +with the `ADD HOST` or the `DROP HOST` in the `ALTER USER` statement. ##### RQ.SRS-006.RBAC.User.Alter.Host.Local version: 1.0 @@ -1164,7 +1047,8 @@ which user can access the server using the `HOST IP` clause in the ##### RQ.SRS-006.RBAC.User.Alter.Host.Like version: 1.0 -[ClickHouse] SHALL support specifying sone or more similar hosts using `LIKE` command syntax using the `HOST LIKE` clause in the `ALTER USER` statement. +[ClickHouse] SHALL support specifying one or more similar hosts using `LIKE` command syntax +using the `HOST LIKE` clause in the `ALTER USER` statement. ##### RQ.SRS-006.RBAC.User.Alter.Host.Any version: 1.0 @@ -1207,7 +1091,6 @@ version: 1.0 [ClickHouse] SHALL support specifying a minimum value for the variable specifed using `SETTINGS` with `MIN` clause in the `ALTER USER` statement. - ##### RQ.SRS-006.RBAC.User.Alter.Settings.Max version: 1.0 @@ -1232,85 +1115,7 @@ ALTER USER [IF EXISTS] name [ON CLUSTER cluster_name] [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] ``` -##### RQ.SRS-006.RBAC.SetDefaultRole -version: 1.0 - -[ClickHouse] SHALL support setting or changing granted roles to default for one or more -users using `SET DEFAULT ROLE` statement which -SHALL permanently change the default roles for the user or users if successful. - -##### RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser -version: 1.0 - -[ClickHouse] SHALL support setting or changing granted roles to default for -the current user using `CURRENT_USER` clause in the `SET DEFAULT ROLE` statement. - -##### RQ.SRS-006.RBAC.SetDefaultRole.All -version: 1.0 - -[ClickHouse] SHALL support setting or changing all granted roles to default -for one or more users using `ALL` clause in the `SET DEFAULT ROLE` statement. - -##### RQ.SRS-006.RBAC.SetDefaultRole.AllExcept -version: 1.0 - -[ClickHouse] SHALL support setting or changing all granted roles except those specified -to default for one or more users using `ALL EXCEPT` clause in the `SET DEFAULT ROLE` statement. - -##### RQ.SRS-006.RBAC.SetDefaultRole.None -version: 1.0 - -[ClickHouse] SHALL support removing all granted roles from default -for one or more users using `NONE` clause in the `SET DEFAULT ROLE` statement. - -##### RQ.SRS-006.RBAC.SetDefaultRole.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for the `SET DEFAULT ROLE` statement. - -```sql -SET DEFAULT ROLE - {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} - TO {user|CURRENT_USER} [,...] - -``` - -##### RQ.SRS-006.RBAC.SetRole -version: 1.0 - -[ClickHouse] SHALL support activating role or roles for the current user -using `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.Default -version: 1.0 - -[ClickHouse] SHALL support activating default roles for the current user -using `DEFAULT` clause in the `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.None -version: 1.0 - -[ClickHouse] SHALL support activating no roles for the current user -using `NONE` clause in the `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.All -version: 1.0 - -[ClickHouse] SHALL support activating all roles for the current user -using `ALL` clause in the `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.AllExcept -version: 1.0 - -[ClickHouse] SHALL support activating all roles except those specified -for the current user using `ALL EXCEPT` clause in the `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.Syntax -version: 1.0 - -```sql -SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]} -``` +#### Show Create User ##### RQ.SRS-006.RBAC.User.ShowCreateUser version: 1.0 @@ -1333,6 +1138,8 @@ version: 1.0 SHOW CREATE USER [name | CURRENT_USER] ``` +#### Drop User + ##### RQ.SRS-006.RBAC.User.Drop version: 1.0 @@ -1361,6 +1168,43 @@ version: 1.0 DROP USER [IF EXISTS] name [,...] [ON CLUSTER cluster_name] ``` +### Role + +#### RQ.SRS-006.RBAC.Role +version: 1.0 + +[ClikHouse] SHALL support creation and manipulation of **roles** +to which privileges, settings profile, quotas and row policies can be +assigned. + +#### RQ.SRS-006.RBAC.Role.Privileges +version: 1.0 + +[ClickHouse] SHALL support assigning one or more privileges to a **role**. + +#### RQ.SRS-006.RBAC.Role.Variables +version: 1.0 + +[ClickHouse] SHALL support assigning one or more variables to a **role**. + +#### RQ.SRS-006.RBAC.Role.SettingsProfile +version: 1.0 + +[ClickHouse] SHALL support assigning one or more **settings profiles** +to a **role**. + +#### RQ.SRS-006.RBAC.Role.Quotas +version: 1.0 + +[ClickHouse] SHALL support assigning one or more **quotas** to a **role**. + +#### RQ.SRS-006.RBAC.Role.RowPolicies +version: 1.0 + +[ClickHouse] SHALL support assigning one or more **row policies** to a **role**. + +#### Create Role + ##### RQ.SRS-006.RBAC.Role.Create version: 1.0 @@ -1396,6 +1240,8 @@ CREATE ROLE [IF NOT EXISTS | OR REPLACE] name [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] ``` +#### Alter Role + ##### RQ.SRS-006.RBAC.Role.Alter version: 1.0 @@ -1442,6 +1288,8 @@ ALTER ROLE [IF EXISTS] name [ON CLUSTER cluster_name] [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] ``` +#### Drop Role + ##### RQ.SRS-006.RBAC.Role.Drop version: 1.0 @@ -1469,6 +1317,8 @@ version: 1.0 DROP ROLE [IF EXISTS] name [,...] [ON CLUSTER cluster_name] ``` +#### Show Create Role + ##### RQ.SRS-006.RBAC.Role.ShowCreate version: 1.0 @@ -1484,326 +1334,15 @@ version: 1.0 SHOW CREATE ROLE name ``` -##### RQ.SRS-006.RBAC.Grant.Privilege.To +### Partial Revokes + +#### RQ.SRS-006.RBAC.PartialRevokes version: 1.0 -[ClickHouse] SHALL support granting privileges to one or more users or roles using `TO` clause -in the `GRANT PRIVILEGE` statement. +[ClickHouse] SHALL support partial revoking of privileges granted +to a **user** or a **role**. -##### RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser -version: 1.0 - -[ClickHouse] SHALL support granting privileges to current user using `TO CURRENT_USER` clause -in the `GRANT PRIVILEGE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Select -version: 1.0 - -[ClickHouse] SHALL support granting the **select** privilege to one or more users or roles -for a database or a table using the `GRANT SELECT` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Insert -version: 1.0 - -[ClickHouse] SHALL support granting the **insert** privilege to one or more users or roles -for a database or a table using the `GRANT INSERT` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Alter -version: 1.0 - -[ClickHouse] SHALL support granting the **alter** privilege to one or more users or roles -for a database or a table using the `GRANT ALTER` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Create -version: 1.0 - -[ClickHouse] SHALL support granting the **create** privilege to one or more users or roles -using the `GRANT CREATE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Drop -version: 1.0 - -[ClickHouse] SHALL support granting the **drop** privilege to one or more users or roles -using the `GRANT DROP` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Truncate -version: 1.0 - -[ClickHouse] SHALL support granting the **truncate** privilege to one or more users or roles -for a database or a table using `GRANT TRUNCATE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Optimize -version: 1.0 - -[ClickHouse] SHALL support granting the **optimize** privilege to one or more users or roles -for a database or a table using `GRANT OPTIMIZE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Show -version: 1.0 - -[ClickHouse] SHALL support granting the **show** privilege to one or more users or roles -for a database or a table using `GRANT SHOW` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.KillQuery -version: 1.0 - -[ClickHouse] SHALL support granting the **kill query** privilege to one or more users or roles -for a database or a table using `GRANT KILL QUERY` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement -version: 1.0 - -[ClickHouse] SHALL support granting the **access management** privileges to one or more users or roles -for a database or a table using `GRANT ACCESS MANAGEMENT` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.System -version: 1.0 - -[ClickHouse] SHALL support granting the **system** privileges to one or more users or roles -for a database or a table using `GRANT SYSTEM` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Introspection -version: 1.0 - -[ClickHouse] SHALL support granting the **introspection** privileges to one or more users or roles -for a database or a table using `GRANT INTROSPECTION` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Sources -version: 1.0 - -[ClickHouse] SHALL support granting the **sources** privileges to one or more users or roles -for a database or a table using `GRANT SOURCES` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.DictGet -version: 1.0 - -[ClickHouse] SHALL support granting the **dictGet** privilege to one or more users or roles -for a database or a table using `GRANT dictGet` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.None -version: 1.0 - -[ClickHouse] SHALL support granting no privileges to one or more users or roles -for a database or a table using `GRANT NONE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.All -version: 1.0 - -[ClickHouse] SHALL support granting the **all** privileges to one or more users or roles -for a database or a table using the `GRANT ALL` or `GRANT ALL PRIVILEGES` statements. - -##### RQ.SRS-006.RBAC.Grant.Privilege.GrantOption -version: 1.0 - -[ClickHouse] SHALL support granting the **grant option** privilege to one or more users or roles -for a database or a table using the `WITH GRANT OPTION` clause in the `GRANT` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.On -version: 1.0 - -[ClickHouse] SHALL support the `ON` clause in the `GRANT` privilege statement -which SHALL allow to specify one or more tables to which the privilege SHALL -be granted using the following patterns - -* `*.*` any table in any database -* `database.*` any table in the specified database -* `database.table` specific table in the specified database -* `*` any table in the current database -* `table` specific table in the current database - -##### RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns -version: 1.0 - -[ClickHouse] SHALL support granting the privilege **some_privilege** to one or more users or roles -for a database or a table using the `GRANT some_privilege(column)` statement for one column. -Multiple columns will be supported with `GRANT some_privilege(column1, column2...)` statement. -The privileges will be granted for only the specified columns. - -##### RQ.SRS-006.RBAC.Grant.Privilege.OnCluster -version: 1.0 - -[ClickHouse] SHALL support specifying cluster on which to grant privileges using the `ON CLUSTER` -clause in the `GRANT PRIVILEGE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for the `GRANT` statement that -grants explicit privileges to a user or a role. - -```sql -GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] - ON {db.table|db.*|*.*|table|*} - TO {user | role | CURRENT_USER} [,...] - [WITH GRANT OPTION] -``` - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Cluster -version: 1.0 - -[ClickHouse] SHALL support revoking privileges to one or more users or roles -for a database or a table on some specific cluster using the `REVOKE ON CLUSTER cluster_name` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Any -version: 1.0 - -[ClickHouse] SHALL support revoking ANY privilege to one or more users or roles -for a database or a table using the `REVOKE some_privilege` statement. -**some_privilege** refers to any Clickhouse defined privilege, whose hierarchy includes -SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE, SHOW, KILL QUERY, ACCESS MANAGEMENT, -SYSTEM, INTROSPECTION, SOURCES, dictGet and all of their sub-privileges. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Select -version: 1.0 - -[ClickHouse] SHALL support revoking the **select** privilege to one or more users or roles -for a database or a table using the `REVOKE SELECT` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Insert -version: 1.0 - -[ClickHouse] SHALL support revoking the **insert** privilege to one or more users or roles -for a database or a table using the `REVOKE INSERT` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Alter -version: 1.0 - -[ClickHouse] SHALL support revoking the **alter** privilege to one or more users or roles -for a database or a table using the `REVOKE ALTER` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Create -version: 1.0 - -[ClickHouse] SHALL support revoking the **create** privilege to one or more users or roles -using the `REVOKE CREATE` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Drop -version: 1.0 - -[ClickHouse] SHALL support revoking the **drop** privilege to one or more users or roles -using the `REVOKE DROP` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Truncate -version: 1.0 - -[ClickHouse] SHALL support revoking the **truncate** privilege to one or more users or roles -for a database or a table using the `REVOKE TRUNCATE` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Optimize -version: 1.0 - -[ClickHouse] SHALL support revoking the **optimize** privilege to one or more users or roles -for a database or a table using the `REVOKE OPTIMIZE` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Show -version: 1.0 - -[ClickHouse] SHALL support revoking the **show** privilege to one or more users or roles -for a database or a table using the `REVOKE SHOW` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery -version: 1.0 - -[ClickHouse] SHALL support revoking the **kill query** privilege to one or more users or roles -for a database or a table using the `REVOKE KILL QUERY` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement -version: 1.0 - -[ClickHouse] SHALL support revoking the **access management** privilege to one or more users or roles -for a database or a table using the `REVOKE ACCESS MANAGEMENT` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.System -version: 1.0 - -[ClickHouse] SHALL support revoking the **system** privilege to one or more users or roles -for a database or a table using the `REVOKE SYSTEM` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Introspection -version: 1.0 - -[ClickHouse] SHALL support revoking the **introspection** privilege to one or more users or roles -for a database or a table using the `REVOKE INTROSPECTION` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Sources -version: 1.0 - -[ClickHouse] SHALL support revoking the **sources** privilege to one or more users or roles -for a database or a table using the `REVOKE SOURCES` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.DictGet -version: 1.0 - -[ClickHouse] SHALL support revoking the **dictGet** privilege to one or more users or roles -for a database or a table using the `REVOKE dictGet` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.PrivelegeColumns -version: 1.0 - -[ClickHouse] SHALL support revoking the privilege **some_privilege** to one or more users or roles -for a database or a table using the `REVOKE some_privilege(column)` statement for one column. -Multiple columns will be supported with `REVOKE some_privilege(column1, column2...)` statement. -The privileges will be revoked for only the specified columns. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Multiple -version: 1.0 - -[ClickHouse] SHALL support revoking MULTIPLE **privileges** to one or more users or roles -for a database or a table using the `REVOKE privilege1, privilege2...` statement. -**privileges** refers to any set of Clickhouse defined privilege, whose hierarchy includes -SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE, SHOW, KILL QUERY, ACCESS MANAGEMENT, -SYSTEM, INTROSPECTION, SOURCES, dictGet and all of their sub-privileges. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.All -version: 1.0 - -[ClickHouse] SHALL support revoking **all** privileges to one or more users or roles -for a database or a table using the `REVOKE ALL` or `REVOKE ALL PRIVILEGES` statements. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.None -version: 1.0 - -[ClickHouse] SHALL support revoking **no** privileges to one or more users or roles -for a database or a table using the `REVOKE NONE` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.On -version: 1.0 - -[ClickHouse] SHALL support the `ON` clause in the `REVOKE` privilege statement -which SHALL allow to specify one or more tables to which the privilege SHALL -be revoked using the following patterns - -* `db.table` specific table in the specified database -* `db.*` any table in the specified database -* `*.*` any table in any database -* `table` specific table in the current database -* `*` any table in the current database - -##### RQ.SRS-006.RBAC.Revoke.Privilege.From -version: 1.0 - -[ClickHouse] SHALL support the `FROM` clause in the `REVOKE` privilege statement -which SHALL allow to specify one or more users to which the privilege SHALL -be revoked using the following patterns - -* `{user | CURRENT_USER} [,...]` some combination of users by name, which may include the current user -* `ALL` all users -* `ALL EXCEPT {user | CURRENT_USER} [,...]` the logical reverse of the first pattern - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for the `REVOKE` statement that -revokes explicit privileges of a user or a role. - -```sql -REVOKE [ON CLUSTER cluster_name] privilege - [(column_name [,...])] [,...] - ON {db.table|db.*|*.*|table|*} - FROM {user | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user | CURRENT_USER} [,...] -``` - -##### RQ.SRS-006.RBAC.PartialRevoke.Syntax +#### RQ.SRS-006.RBAC.PartialRevoke.Syntax version: 1.0 [ClickHouse] SHALL support partial revokes by using `partial_revokes` variable @@ -1821,102 +1360,22 @@ To enable partial revokes the `partial revokes` variable SHALL be set to `1` SET partial_revokes = 1 ``` -##### RQ.SRS-006.RBAC.Grant.Role +### Settings Profile + +#### RQ.SRS-006.RBAC.SettingsProfile version: 1.0 -[ClickHouse] SHALL support granting one or more roles to -one or more users or roles using the `GRANT` role statement. +[ClickHouse] SHALL support creation and manipulation of **settings profiles** +that can include value definition for one or more variables and can +can be assigned to one or more **users** or **roles**. -##### RQ.SRS-006.RBAC.Grant.Role.CurrentUser +#### RQ.SRS-006.RBAC.SettingsProfile.Constraints version: 1.0 -[ClickHouse] SHALL support granting one or more roles to current user using -`TO CURRENT_USER` clause in the `GRANT` role statement. +[ClickHouse] SHALL support assigning min, max and read-only constraints +for the variables specified in the **settings profile**. -##### RQ.SRS-006.RBAC.Grant.Role.AdminOption -version: 1.0 - -[ClickHouse] SHALL support granting `admin option` privilege -to one or more users or roles using the `WITH ADMIN OPTION` clause -in the `GRANT` role statement. - -##### RQ.SRS-006.RBAC.Grant.Role.OnCluster -version: 1.0 - -[ClickHouse] SHALL support specifying cluster on which the user is to be granted one or more roles -using `ON CLUSTER` clause in the `GRANT` statement. - -##### RQ.SRS-006.RBAC.Grant.Role.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for `GRANT` role statement - -``` sql -GRANT - ON CLUSTER cluster_name - role [, role ...] - TO {user | role | CURRENT_USER} [,...] - [WITH ADMIN OPTION] -``` - -##### RQ.SRS-006.RBAC.Revoke.Role -version: 1.0 - -[ClickHouse] SHALL support revoking one or more roles from -one or more users or roles using the `REVOKE` role statement. - -##### RQ.SRS-006.RBAC.Revoke.Role.Keywords -version: 1.0 - -[ClickHouse] SHALL support revoking one or more roles from -special groupings of one or more users or roles with the `ALL`, `ALL EXCEPT`, -and `CURRENT_USER` keywords. - -##### RQ.SRS-006.RBAC.Revoke.Role.Cluster -version: 1.0 - -[ClickHouse] SHALL support revoking one or more roles from -one or more users or roles from one or more clusters -using the `REVOKE ON CLUSTER` role statement. - -##### RQ.SRS-006.RBAC.Revoke.AdminOption -version: 1.0 - -[ClickHouse] SHALL support revoking `admin option` privilege -in one or more users or roles using the `ADMIN OPTION FOR` clause -in the `REVOKE` role statement. - -##### RQ.SRS-006.RBAC.Revoke.Role.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for the `REVOKE` role statement - -```sql -REVOKE [ON CLUSTER cluster_name] [ADMIN OPTION FOR] - role [,...] - FROM {user | role | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...] -``` - -##### RQ.SRS-006.RBAC.Show.Grants -version: 1.0 - -[ClickHouse] SHALL support listing all the privileges granted to current user and role -using the `SHOW GRANTS` statement. - -##### RQ.SRS-006.RBAC.Show.Grants.For -version: 1.0 - -[ClickHouse] SHALL support listing all the privileges granted to a user or a role -using the `FOR` clause in the `SHOW GRANTS` statement. - -##### RQ.SRS-006.RBAC.Show.Grants.Syntax -version: 1.0 - -[Clickhouse] SHALL use the following syntax for the `SHOW GRANTS` statement - -``` sql -SHOW GRANTS [FOR user_or_role] -``` +#### Create Settings Profile ##### RQ.SRS-006.RBAC.SettingsProfile.Create version: 1.0 @@ -2002,6 +1461,8 @@ CREATE SETTINGS PROFILE [IF NOT EXISTS | OR REPLACE] name [TO {user_or_role [,...] | NONE | ALL | ALL EXCEPT user_or_role [,...]}] ``` +#### Alter Settings Profile + ##### RQ.SRS-006.RBAC.SettingsProfile.Alter version: 1.0 @@ -2087,6 +1548,8 @@ ALTER SETTINGS PROFILE [IF EXISTS] name [TO {user_or_role [,...] | NONE | ALL | ALL EXCEPT user_or_role [,...]]} ``` +#### Drop Settings Profile + ##### RQ.SRS-006.RBAC.SettingsProfile.Drop version: 1.0 @@ -2115,6 +1578,8 @@ version: 1.0 DROP SETTINGS PROFILE [IF EXISTS] name [,name,...] ``` +#### Show Create Settings Profile + ##### RQ.SRS-006.RBAC.SettingsProfile.ShowCreateSettingsProfile version: 1.0 @@ -2125,6 +1590,63 @@ using the `SHOW CREATE SETTINGS PROFILE` statement with the following syntax SHOW CREATE SETTINGS PROFILE name ``` +### Quotas + +#### RQ.SRS-006.RBAC.Quotas +version: 1.0 + +[ClickHouse] SHALL support creation and manipulation of **quotas** +that can be used to limit resource usage by a **user** or a **role** +over a period of time. + +#### RQ.SRS-006.RBAC.Quotas.Keyed +version: 1.0 + +[ClickHouse] SHALL support creating **quotas** that are keyed +so that a quota is tracked separately for each key value. + +#### RQ.SRS-006.RBAC.Quotas.Queries +version: 1.0 + +[ClickHouse] SHALL support setting **queries** quota to limit the total number of requests. + +#### RQ.SRS-006.RBAC.Quotas.Errors +version: 1.0 + +[ClickHouse] SHALL support setting **errors** quota to limit the number of queries that threw an exception. + +#### RQ.SRS-006.RBAC.Quotas.ResultRows +version: 1.0 + +[ClickHouse] SHALL support setting **result rows** quota to limit the +the total number of rows given as the result. + +#### RQ.SRS-006.RBAC.Quotas.ReadRows +version: 1.0 + +[ClickHouse] SHALL support setting **read rows** quota to limit the total +number of source rows read from tables for running the query on all remote servers. + +#### RQ.SRS-006.RBAC.Quotas.ResultBytes +version: 1.0 + +[ClickHouse] SHALL support setting **result bytes** quota to limit the total number +of bytes that can be returned as the result. + +#### RQ.SRS-006.RBAC.Quotas.ReadBytes +version: 1.0 + +[ClickHouse] SHALL support setting **read bytes** quota to limit the total number +of source bytes read from tables for running the query on all remote servers. + +#### RQ.SRS-006.RBAC.Quotas.ExecutionTime +version: 1.0 + +[ClickHouse] SHALL support setting **execution time** quota to limit the maximum +query execution time. + +#### Create Quotas + ##### RQ.SRS-006.RBAC.Quota.Create version: 1.0 @@ -2163,7 +1685,6 @@ of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be: `FOR INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some real number to define the interval. - ##### RQ.SRS-006.RBAC.Quota.Create.Interval.Randomized version: 1.0 @@ -2286,6 +1807,8 @@ CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name] [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] ``` +#### Alter Quota + ##### RQ.SRS-006.RBAC.Quota.Alter version: 1.0 @@ -2444,6 +1967,8 @@ ALTER QUOTA [IF EXIST] name [TO {user_or_role [,...] | NONE | ALL} [EXCEPT user_or_role [,...]]] ``` +#### Drop Quota + ##### RQ.SRS-006.RBAC.Quota.Drop version: 1.0 @@ -2472,6 +1997,8 @@ version: 1.0 DROP QUOTA [IF EXISTS] name [,name...] ``` +#### Show Quotas + ##### RQ.SRS-006.RBAC.Quota.ShowQuotas version: 1.0 @@ -2496,7 +2023,6 @@ version: 1.0 [ClickHouse] SHALL support the `SETTINGS` clause in the `SHOW QUOTAS` statement to define settings in the showing of all quotas. - ##### RQ.SRS-006.RBAC.Quota.ShowQuotas.Syntax version: 1.0 @@ -2505,6 +2031,9 @@ with the following syntax ``` sql SHOW QUOTAS ``` + +#### Show Create Quota + ##### RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Name version: 1.0 @@ -2532,6 +2061,34 @@ using the `SHOW CREATE QUOTA` statement. SHOW CREATE QUOTA [name | CURRENT] ``` +### Row Policy + +#### RQ.SRS-006.RBAC.RowPolicy +version: 1.0 + +[ClickHouse] SHALL support creation and manipulation of table **row policies** +that can be used to limit access to the table contents for a **user** or a **role** +using a specified **condition**. + +#### RQ.SRS-006.RBAC.RowPolicy.Condition +version: 1.0 + +[ClickHouse] SHALL support row policy **conditions** that can be any SQL +expression that returns a boolean. + +#### RQ.SRS-006.RBAC.RowPolicy.Restriction +version: 1.0 + +[ClickHouse] SHALL restrict all access to a table when a row policy with a condition is created on that table. +All users require a permissive row policy in order to view the table. + +#### RQ.SRS-006.RBAC.RowPolicy.Nesting +version: 1.0 + +[ClickHouse] SHALL restrict rows of tables or views created on top of a table with row policies according to those policies. + +#### Create Row Policy + ##### RQ.SRS-006.RBAC.RowPolicy.Create version: 1.0 @@ -2586,14 +2143,14 @@ version: 1.0 [ClickHouse] SHALL support specifying which rows are affected using the `FOR SELECT` clause in the `CREATE ROW POLICY` statement. -REQUIRES CONFIRMATION +REQUIRES CONDITION. ##### RQ.SRS-006.RBAC.RowPolicy.Create.Condition version: 1.0 [ClickHouse] SHALL support specifying a condition that that can be any SQL expression which returns a boolean using the `USING` -clause in the `CREATE ROW POLOCY` statement. +clause in the `CREATE ROW POLICY` statement. ##### RQ.SRS-006.RBAC.RowPolicy.Create.Assignment version: 1.0 @@ -2632,6 +2189,8 @@ CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name [ON CLUSTER cluster [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] ``` +#### Alter Row Policy + ##### RQ.SRS-006.RBAC.RowPolicy.Alter version: 1.0 @@ -2738,6 +2297,8 @@ ALTER [ROW] POLICY [IF EXISTS] name [ON CLUSTER cluster_name] ON [database.]tabl [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] ``` +#### Drop Row Policy + ##### RQ.SRS-006.RBAC.RowPolicy.Drop version: 1.0 @@ -2772,6 +2333,8 @@ version: 1.0 DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...] [ON CLUSTER cluster_name] ``` +#### Show Create Row Policy + ##### RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy version: 1.0 @@ -2813,9 +2376,510 @@ version: 1.0 SHOW [ROW] POLICIES [ON [database.]table] ``` -#### Table Privileges +### Set Default Role -##### RQ.SRS-006.RBAC.Table.PublicTables +#### RQ.SRS-006.RBAC.SetDefaultRole +version: 1.0 + +[ClickHouse] SHALL support setting or changing granted roles to default for one or more +users using `SET DEFAULT ROLE` statement which +SHALL permanently change the default roles for the user or users if successful. + +#### RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser +version: 1.0 + +[ClickHouse] SHALL support setting or changing granted roles to default for +the current user using `CURRENT_USER` clause in the `SET DEFAULT ROLE` statement. + +#### RQ.SRS-006.RBAC.SetDefaultRole.All +version: 1.0 + +[ClickHouse] SHALL support setting or changing all granted roles to default +for one or more users using `ALL` clause in the `SET DEFAULT ROLE` statement. + +#### RQ.SRS-006.RBAC.SetDefaultRole.AllExcept +version: 1.0 + +[ClickHouse] SHALL support setting or changing all granted roles except those specified +to default for one or more users using `ALL EXCEPT` clause in the `SET DEFAULT ROLE` statement. + +#### RQ.SRS-006.RBAC.SetDefaultRole.None +version: 1.0 + +[ClickHouse] SHALL support removing all granted roles from default +for one or more users using `NONE` clause in the `SET DEFAULT ROLE` statement. + +#### RQ.SRS-006.RBAC.SetDefaultRole.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for the `SET DEFAULT ROLE` statement. + +```sql +SET DEFAULT ROLE + {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} + TO {user|CURRENT_USER} [,...] + +``` + +### Set Role + +#### RQ.SRS-006.RBAC.SetRole +version: 1.0 + +[ClickHouse] SHALL support activating role or roles for the current user +using `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.Default +version: 1.0 + +[ClickHouse] SHALL support activating default roles for the current user +using `DEFAULT` clause in the `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.None +version: 1.0 + +[ClickHouse] SHALL support activating no roles for the current user +using `NONE` clause in the `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.All +version: 1.0 + +[ClickHouse] SHALL support activating all roles for the current user +using `ALL` clause in the `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.AllExcept +version: 1.0 + +[ClickHouse] SHALL support activating all roles except those specified +for the current user using `ALL EXCEPT` clause in the `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.Syntax +version: 1.0 + +```sql +SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]} +``` + +### Grant + +#### RQ.SRS-006.RBAC.Grant.Privilege.To +version: 1.0 + +[ClickHouse] SHALL support granting privileges to one or more users or roles using `TO` clause +in the `GRANT PRIVILEGE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser +version: 1.0 + +[ClickHouse] SHALL support granting privileges to current user using `TO CURRENT_USER` clause +in the `GRANT PRIVILEGE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Select +version: 1.0 + +[ClickHouse] SHALL support granting the **select** privilege to one or more users or roles +for a database or a table using the `GRANT SELECT` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Insert +version: 1.0 + +[ClickHouse] SHALL support granting the **insert** privilege to one or more users or roles +for a database or a table using the `GRANT INSERT` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Alter +version: 1.0 + +[ClickHouse] SHALL support granting the **alter** privilege to one or more users or roles +for a database or a table using the `GRANT ALTER` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Create +version: 1.0 + +[ClickHouse] SHALL support granting the **create** privilege to one or more users or roles +using the `GRANT CREATE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Drop +version: 1.0 + +[ClickHouse] SHALL support granting the **drop** privilege to one or more users or roles +using the `GRANT DROP` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Truncate +version: 1.0 + +[ClickHouse] SHALL support granting the **truncate** privilege to one or more users or roles +for a database or a table using `GRANT TRUNCATE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Optimize +version: 1.0 + +[ClickHouse] SHALL support granting the **optimize** privilege to one or more users or roles +for a database or a table using `GRANT OPTIMIZE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Show +version: 1.0 + +[ClickHouse] SHALL support granting the **show** privilege to one or more users or roles +for a database or a table using `GRANT SHOW` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.KillQuery +version: 1.0 + +[ClickHouse] SHALL support granting the **kill query** privilege to one or more users or roles +for a database or a table using `GRANT KILL QUERY` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement +version: 1.0 + +[ClickHouse] SHALL support granting the **access management** privileges to one or more users or roles +for a database or a table using `GRANT ACCESS MANAGEMENT` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.System +version: 1.0 + +[ClickHouse] SHALL support granting the **system** privileges to one or more users or roles +for a database or a table using `GRANT SYSTEM` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Introspection +version: 1.0 + +[ClickHouse] SHALL support granting the **introspection** privileges to one or more users or roles +for a database or a table using `GRANT INTROSPECTION` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Sources +version: 1.0 + +[ClickHouse] SHALL support granting the **sources** privileges to one or more users or roles +for a database or a table using `GRANT SOURCES` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.DictGet +version: 1.0 + +[ClickHouse] SHALL support granting the **dictGet** privilege to one or more users or roles +for a database or a table using `GRANT dictGet` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.None +version: 1.0 + +[ClickHouse] SHALL support granting no privileges to one or more users or roles +for a database or a table using `GRANT NONE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.All +version: 1.0 + +[ClickHouse] SHALL support granting the **all** privileges to one or more users or roles +using the `GRANT ALL` or `GRANT ALL PRIVILEGES` statements. + +#### RQ.SRS-006.RBAC.Grant.Privilege.GrantOption +version: 1.0 + +[ClickHouse] SHALL support granting the **grant option** privilege to one or more users or roles +for a database or a table using the `WITH GRANT OPTION` clause in the `GRANT` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.On +version: 1.0 + +[ClickHouse] SHALL support the `ON` clause in the `GRANT` privilege statement +which SHALL allow to specify one or more tables to which the privilege SHALL +be granted using the following patterns + +* `*.*` any table in any database +* `database.*` any table in the specified database +* `database.table` specific table in the specified database +* `*` any table in the current database +* `table` specific table in the current database + +#### RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns +version: 1.0 + +[ClickHouse] SHALL support granting the privilege **some_privilege** to one or more users or roles +for a database or a table using the `GRANT some_privilege(column)` statement for one column. +Multiple columns will be supported with `GRANT some_privilege(column1, column2...)` statement. +The privileges will be granted for only the specified columns. + +#### RQ.SRS-006.RBAC.Grant.Privilege.OnCluster +version: 1.0 + +[ClickHouse] SHALL support specifying cluster on which to grant privileges using the `ON CLUSTER` +clause in the `GRANT PRIVILEGE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for the `GRANT` statement that +grants explicit privileges to a user or a role. + +```sql +GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] + ON {db.table|db.*|*.*|table|*} + TO {user | role | CURRENT_USER} [,...] + [WITH GRANT OPTION] +``` + +### Revoke + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Cluster +version: 1.0 + +[ClickHouse] SHALL support revoking privileges to one or more users or roles +for a database or a table on some specific cluster using the `REVOKE ON CLUSTER cluster_name` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Select +version: 1.0 + +[ClickHouse] SHALL support revoking the **select** privilege to one or more users or roles +for a database or a table using the `REVOKE SELECT` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Insert +version: 1.0 + +[ClickHouse] SHALL support revoking the **insert** privilege to one or more users or roles +for a database or a table using the `REVOKE INSERT` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Alter +version: 1.0 + +[ClickHouse] SHALL support revoking the **alter** privilege to one or more users or roles +for a database or a table using the `REVOKE ALTER` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Create +version: 1.0 + +[ClickHouse] SHALL support revoking the **create** privilege to one or more users or roles +using the `REVOKE CREATE` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Drop +version: 1.0 + +[ClickHouse] SHALL support revoking the **drop** privilege to one or more users or roles +using the `REVOKE DROP` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Truncate +version: 1.0 + +[ClickHouse] SHALL support revoking the **truncate** privilege to one or more users or roles +for a database or a table using the `REVOKE TRUNCATE` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Optimize +version: 1.0 + +[ClickHouse] SHALL support revoking the **optimize** privilege to one or more users or roles +for a database or a table using the `REVOKE OPTIMIZE` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Show +version: 1.0 + +[ClickHouse] SHALL support revoking the **show** privilege to one or more users or roles +for a database or a table using the `REVOKE SHOW` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery +version: 1.0 + +[ClickHouse] SHALL support revoking the **kill query** privilege to one or more users or roles +for a database or a table using the `REVOKE KILL QUERY` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement +version: 1.0 + +[ClickHouse] SHALL support revoking the **access management** privilege to one or more users or roles +for a database or a table using the `REVOKE ACCESS MANAGEMENT` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.System +version: 1.0 + +[ClickHouse] SHALL support revoking the **system** privilege to one or more users or roles +for a database or a table using the `REVOKE SYSTEM` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Introspection +version: 1.0 + +[ClickHouse] SHALL support revoking the **introspection** privilege to one or more users or roles +for a database or a table using the `REVOKE INTROSPECTION` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Sources +version: 1.0 + +[ClickHouse] SHALL support revoking the **sources** privilege to one or more users or roles +for a database or a table using the `REVOKE SOURCES` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.DictGet +version: 1.0 + +[ClickHouse] SHALL support revoking the **dictGet** privilege to one or more users or roles +for a database or a table using the `REVOKE dictGet` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.PrivilegeColumns +version: 1.0 + +[ClickHouse] SHALL support revoking the privilege **some_privilege** to one or more users or roles +for a database or a table using the `REVOKE some_privilege(column)` statement for one column. +Multiple columns will be supported with `REVOKE some_privilege(column1, column2...)` statement. +The privileges will be revoked for only the specified columns. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Multiple +version: 1.0 + +[ClickHouse] SHALL support revoking MULTIPLE **privileges** to one or more users or roles +for a database or a table using the `REVOKE privilege1, privilege2...` statement. +**privileges** refers to any set of Clickhouse defined privilege, whose hierarchy includes +SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE, SHOW, KILL QUERY, ACCESS MANAGEMENT, +SYSTEM, INTROSPECTION, SOURCES, dictGet and all of their sub-privileges. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.All +version: 1.0 + +[ClickHouse] SHALL support revoking **all** privileges to one or more users or roles +for a database or a table using the `REVOKE ALL` or `REVOKE ALL PRIVILEGES` statements. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.None +version: 1.0 + +[ClickHouse] SHALL support revoking **no** privileges to one or more users or roles +for a database or a table using the `REVOKE NONE` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.On +version: 1.0 + +[ClickHouse] SHALL support the `ON` clause in the `REVOKE` privilege statement +which SHALL allow to specify one or more tables to which the privilege SHALL +be revoked using the following patterns + +* `db.table` specific table in the specified database +* `db.*` any table in the specified database +* `*.*` any table in any database +* `table` specific table in the current database +* `*` any table in the current database + +#### RQ.SRS-006.RBAC.Revoke.Privilege.From +version: 1.0 + +[ClickHouse] SHALL support the `FROM` clause in the `REVOKE` privilege statement +which SHALL allow to specify one or more users to which the privilege SHALL +be revoked using the following patterns + +* `{user | CURRENT_USER} [,...]` some combination of users by name, which may include the current user +* `ALL` all users +* `ALL EXCEPT {user | CURRENT_USER} [,...]` the logical reverse of the first pattern + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for the `REVOKE` statement that +revokes explicit privileges of a user or a role. + +```sql +REVOKE [ON CLUSTER cluster_name] privilege + [(column_name [,...])] [,...] + ON {db.table|db.*|*.*|table|*} + FROM {user | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user | CURRENT_USER} [,...] +``` + +### Grant Role + +#### RQ.SRS-006.RBAC.Grant.Role +version: 1.0 + +[ClickHouse] SHALL support granting one or more roles to +one or more users or roles using the `GRANT` role statement. + +#### RQ.SRS-006.RBAC.Grant.Role.CurrentUser +version: 1.0 + +[ClickHouse] SHALL support granting one or more roles to current user using +`TO CURRENT_USER` clause in the `GRANT` role statement. + +#### RQ.SRS-006.RBAC.Grant.Role.AdminOption +version: 1.0 + +[ClickHouse] SHALL support granting `admin option` privilege +to one or more users or roles using the `WITH ADMIN OPTION` clause +in the `GRANT` role statement. + +#### RQ.SRS-006.RBAC.Grant.Role.OnCluster +version: 1.0 + +[ClickHouse] SHALL support specifying cluster on which the user is to be granted one or more roles +using `ON CLUSTER` clause in the `GRANT` statement. + +#### RQ.SRS-006.RBAC.Grant.Role.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for `GRANT` role statement + +``` sql +GRANT + ON CLUSTER cluster_name + role [, role ...] + TO {user | role | CURRENT_USER} [,...] + [WITH ADMIN OPTION] +``` + +### Revoke Role + +#### RQ.SRS-006.RBAC.Revoke.Role +version: 1.0 + +[ClickHouse] SHALL support revoking one or more roles from +one or more users or roles using the `REVOKE` role statement. + +#### RQ.SRS-006.RBAC.Revoke.Role.Keywords +version: 1.0 + +[ClickHouse] SHALL support revoking one or more roles from +special groupings of one or more users or roles with the `ALL`, `ALL EXCEPT`, +and `CURRENT_USER` keywords. + +#### RQ.SRS-006.RBAC.Revoke.Role.Cluster +version: 1.0 + +[ClickHouse] SHALL support revoking one or more roles from +one or more users or roles from one or more clusters +using the `REVOKE ON CLUSTER` role statement. + +#### RQ.SRS-006.RBAC.Revoke.AdminOption +version: 1.0 + +[ClickHouse] SHALL support revoking `admin option` privilege +in one or more users or roles using the `ADMIN OPTION FOR` clause +in the `REVOKE` role statement. + +#### RQ.SRS-006.RBAC.Revoke.Role.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for the `REVOKE` role statement + +```sql +REVOKE [ON CLUSTER cluster_name] [ADMIN OPTION FOR] + role [,...] + FROM {user | role | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...] +``` + +### Show Grants + +#### RQ.SRS-006.RBAC.Show.Grants +version: 1.0 + +[ClickHouse] SHALL support listing all the privileges granted to current user and role +using the `SHOW GRANTS` statement. + +#### RQ.SRS-006.RBAC.Show.Grants.For +version: 1.0 + +[ClickHouse] SHALL support listing all the privileges granted to a user or a role +using the `FOR` clause in the `SHOW GRANTS` statement. + +#### RQ.SRS-006.RBAC.Show.Grants.Syntax +version: 1.0 + +[Clickhouse] SHALL use the following syntax for the `SHOW GRANTS` statement + +``` sql +SHOW GRANTS [FOR user_or_role] +``` + +### Table Privileges + +#### RQ.SRS-006.RBAC.Table.PublicTables version: 1.0 [ClickHouse] SHALL support that a user without any privileges will be able to access the following tables @@ -2825,7 +2889,7 @@ version: 1.0 * system.contributors * system.functions -##### RQ.SRS-006.RBAC.Table.SensitiveTables +#### RQ.SRS-006.RBAC.Table.SensitiveTables version: 1.0 [ClickHouse] SHALL not support a user with no privileges accessing the following `system` tables: @@ -2842,15 +2906,15 @@ version: 1.0 * zookeeper * macros -#### Distributed Tables +### Distributed Tables -##### RQ.SRS-006.RBAC.DistributedTable.Create +#### RQ.SRS-006.RBAC.DistributedTable.Create version: 1.0 [ClickHouse] SHALL successfully `CREATE` a distributed table if and only if the user has **create table** privilege on the table and **remote** privilege on *.* -##### RQ.SRS-006.RBAC.DistributedTable.Select +#### RQ.SRS-006.RBAC.DistributedTable.Select version: 1.0 [ClickHouse] SHALL successfully `SELECT` from a distributed table if and only if @@ -2858,7 +2922,7 @@ the user has **select** privilege on the table and on the remote table specified Does not require **select** privilege for the remote table if the remote table does not exist on the same server as the user. -##### RQ.SRS-006.RBAC.DistributedTable.Insert +#### RQ.SRS-006.RBAC.DistributedTable.Insert version: 1.0 [ClickHouse] SHALL successfully `INSERT` into a distributed table if and only if @@ -2867,7 +2931,7 @@ the user has **insert** privilege on the table and on the remote table specified Does not require **insert** privilege for the remote table if the remote table does not exist on the same server as the user, insert executes into the remote table on a different server. -##### RQ.SRS-006.RBAC.DistributedTable.SpecialTables +#### RQ.SRS-006.RBAC.DistributedTable.SpecialTables version: 1.0 [ClickHouse] SHALL successfully execute a query using a distributed table that uses one of the special tables if and only if @@ -2877,29 +2941,29 @@ Special tables include: * distributed table * source table of a materialized view -##### RQ.SRS-006.RBAC.DistributedTable.LocalUser +#### RQ.SRS-006.RBAC.DistributedTable.LocalUser version: 1.0 [ClickHouse] SHALL successfully execute a query using a distributed table from a user present locally, but not remotely. -##### RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges +#### RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges version: 1.0 [ClickHouse] SHALL successfully execute a query using a distributed table by a user that exists on multiple nodes if and only if the user has the required privileges on the node the query is being executed from. -#### Views +### Views -##### View +#### View -###### RQ.SRS-006.RBAC.View +##### RQ.SRS-006.RBAC.View version: 1.0 [ClickHouse] SHALL support controlling access to **create**, **select** and **drop** privileges for a view for users or roles. -###### RQ.SRS-006.RBAC.View.Create +##### RQ.SRS-006.RBAC.View.Create version: 1.0 [ClickHouse] SHALL only successfully execute a `CREATE VIEW` command if and only if @@ -2917,7 +2981,7 @@ CREATE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL CREATE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2 ``` -###### RQ.SRS-006.RBAC.View.Select +##### RQ.SRS-006.RBAC.View.Select version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from a view if and only if @@ -2937,21 +3001,21 @@ CREATE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2 SELECT * FROM view ``` -###### RQ.SRS-006.RBAC.View.Drop +##### RQ.SRS-006.RBAC.View.Drop version: 1.0 [ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if the user has **drop view** privilege on that view either explicitly or through a role. -##### Materialized View +#### Materialized View -###### RQ.SRS-006.RBAC.MaterializedView +##### RQ.SRS-006.RBAC.MaterializedView version: 1.0 [ClickHouse] SHALL support controlling access to **create**, **select**, **alter** and **drop** privileges for a materialized view for users or roles. -###### RQ.SRS-006.RBAC.MaterializedView.Create +##### RQ.SRS-006.RBAC.MaterializedView.Create version: 1.0 [ClickHouse] SHALL only successfully execute a `CREATE MATERIALIZED VIEW` command if and only if @@ -2983,7 +3047,7 @@ For example, CREATE MATERIALIZED VIEW view TO target_table AS SELECT * FROM source_table ``` -###### RQ.SRS-006.RBAC.MaterializedView.Select +##### RQ.SRS-006.RBAC.MaterializedView.Select version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from a materialized view if and only if @@ -3003,25 +3067,25 @@ CREATE MATERIALIZED VIEW view0 ENGINE = Memory AS SELECT column FROM view1 UNION SELECT * FROM view ``` -###### RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable +##### RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from the target table, implicit or explicit, of a materialized view if and only if the user has `SELECT` privilege for the table, either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable +##### RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from the source table of a materialized view if and only if the user has `SELECT` privilege for the table, either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.Drop +##### RQ.SRS-006.RBAC.MaterializedView.Drop version: 1.0 [ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if the user has **drop view** privilege on that view either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.ModifyQuery +##### RQ.SRS-006.RBAC.MaterializedView.ModifyQuery version: 1.0 [ClickHouse] SHALL only successfully execute a `MODIFY QUERY` command if and only if @@ -3034,33 +3098,33 @@ For example, ALTER TABLE view MODIFY QUERY SELECT * FROM source_table ``` -###### RQ.SRS-006.RBAC.MaterializedView.Insert +##### RQ.SRS-006.RBAC.MaterializedView.Insert version: 1.0 [ClickHouse] SHALL only succesfully `INSERT` into a materialized view if and only if the user has `INSERT` privilege on the view, either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable +##### RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable version: 1.0 [ClickHouse] SHALL only succesfully `INSERT` into a source table of a materialized view if and only if the user has `INSERT` privilege on the source table, either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable +##### RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable version: 1.0 [ClickHouse] SHALL only succesfully `INSERT` into a target table of a materialized view if and only if the user has `INSERT` privelege on the target table, either explicitly or through a role. -##### Live View +#### Live View -###### RQ.SRS-006.RBAC.LiveView +##### RQ.SRS-006.RBAC.LiveView version: 1.0 [ClickHouse] SHALL support controlling access to **create**, **select**, **alter** and **drop** privileges for a live view for users or roles. -###### RQ.SRS-006.RBAC.LiveView.Create +##### RQ.SRS-006.RBAC.LiveView.Create version: 1.0 [ClickHouse] SHALL only successfully execute a `CREATE LIVE VIEW` command if and only if @@ -3078,7 +3142,7 @@ CREATE LIVE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNIO CREATE LIVE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2 ``` -###### RQ.SRS-006.RBAC.LiveView.Select +##### RQ.SRS-006.RBAC.LiveView.Select version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from a live view if and only if @@ -3098,28 +3162,28 @@ CREATE LIVE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM SELECT * FROM view ``` -###### RQ.SRS-006.RBAC.LiveView.Drop +##### RQ.SRS-006.RBAC.LiveView.Drop version: 1.0 [ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if the user has **drop view** privilege on that view either explicitly or through a role. -###### RQ.SRS-006.RBAC.LiveView.Refresh +##### RQ.SRS-006.RBAC.LiveView.Refresh version: 1.0 [ClickHouse] SHALL only successfully execute an `ALTER LIVE VIEW REFRESH` command if and only if the user has **refresh** privilege on that view either explicitly or through a role. -#### Select +### Select -##### RQ.SRS-006.RBAC.Select +#### RQ.SRS-006.RBAC.Select version: 1.0 [ClickHouse] SHALL execute `SELECT` if and only if the user has the **select** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -##### RQ.SRS-006.RBAC.Select.Column +#### RQ.SRS-006.RBAC.Select.Column version: 1.0 [ClickHouse] SHALL support granting or revoking **select** privilege @@ -3128,7 +3192,7 @@ Any `SELECT` statements SHALL not to be executed, unless the user has the **select** privilege for the destination column either because of the explicit grant or through one of the roles assigned to the user. -##### RQ.SRS-006.RBAC.Select.Cluster +#### RQ.SRS-006.RBAC.Select.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **select** privilege @@ -3136,7 +3200,7 @@ on a specified cluster to one or more **users** or **roles**. Any `SELECT` statements SHALL succeed only on nodes where the table exists and privilege was granted. -##### RQ.SRS-006.RBAC.Select.TableEngines +#### RQ.SRS-006.RBAC.Select.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **select** privilege @@ -3157,16 +3221,16 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -#### Insert +### Insert -##### RQ.SRS-006.RBAC.Insert +#### RQ.SRS-006.RBAC.Insert version: 1.0 [ClickHouse] SHALL execute `INSERT INTO` if and only if the user has the **insert** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -##### RQ.SRS-006.RBAC.Insert.Column +#### RQ.SRS-006.RBAC.Insert.Column version: 1.0 [ClickHouse] SHALL support granting or revoking **insert** privilege @@ -3175,7 +3239,7 @@ Any `INSERT INTO` statements SHALL not to be executed, unless the user has the **insert** privilege for the destination column either because of the explicit grant or through one of the roles assigned to the user. -##### RQ.SRS-006.RBAC.Insert.Cluster +#### RQ.SRS-006.RBAC.Insert.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **insert** privilege @@ -3183,7 +3247,7 @@ on a specified cluster to one or more **users** or **roles**. Any `INSERT INTO` statements SHALL succeed only on nodes where the table exists and privilege was granted. -##### RQ.SRS-006.RBAC.Insert.TableEngines +#### RQ.SRS-006.RBAC.Insert.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **insert** privilege @@ -3204,11 +3268,11 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -#### Alter +### Alter -##### Alter Column +#### Alter Column -###### RQ.SRS-006.RBAC.Privileges.AlterColumn +##### RQ.SRS-006.RBAC.Privileges.AlterColumn version: 1.0 [ClickHouse] SHALL support controlling access to the **alter column** privilege @@ -3218,19 +3282,19 @@ return an error, unless the user has the **alter column** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant version: 1.0 [ClickHouse] SHALL support granting **alter column** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter column** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.Column +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.Column version: 1.0 [ClickHouse] SHALL support granting or revoking **alter column** privilege @@ -3239,7 +3303,7 @@ Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN` statements SHALL retu unless the user has the **alter column** privilege for the destination column either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter column** privilege @@ -3247,7 +3311,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter column** privilege @@ -3268,9 +3332,9 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Index +#### Alter Index -###### RQ.SRS-006.RBAC.Privileges.AlterIndex +##### RQ.SRS-006.RBAC.Privileges.AlterIndex version: 1.0 [ClickHouse] SHALL support controlling access to the **alter index** privilege @@ -3280,19 +3344,19 @@ return an error, unless the user has the **alter index** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant version: 1.0 [ClickHouse] SHALL support granting **alter index** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter index** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter index** privilege @@ -3300,7 +3364,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... ORDER BY | ADD|DROP|MATERIALIZE|CLEAR INDEX` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter index** privilege @@ -3321,9 +3385,9 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Constraint +#### Alter Constraint -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint version: 1.0 [ClickHouse] SHALL support controlling access to the **alter constraint** privilege @@ -3333,19 +3397,19 @@ return an error, unless the user has the **alter constraint** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant version: 1.0 [ClickHouse] SHALL support granting **alter constraint** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter constraint** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter constraint** privilege @@ -3353,7 +3417,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... ADD|DROP CONSTRAINT` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter constraint** privilege @@ -3374,9 +3438,9 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter TTL +#### Alter TTL -###### RQ.SRS-006.RBAC.Privileges.AlterTTL +##### RQ.SRS-006.RBAC.Privileges.AlterTTL version: 1.0 [ClickHouse] SHALL support controlling access to the **alter ttl** or **alter materialize ttl** privilege @@ -3386,19 +3450,19 @@ return an error, unless the user has the **alter ttl** or **alter materialize tt the destination table either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant version: 1.0 [ClickHouse] SHALL support granting **alter ttl** or **alter materialize ttl** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter ttl** or **alter materialize ttl** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter ttl** or **alter materialize ttl** privilege @@ -3406,7 +3470,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... ALTER TTL | ALTER MATERIALIZE TTL` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter ttl** or **alter materialize ttl** privilege @@ -3414,9 +3478,9 @@ on tables created using the following engines * MergeTree -##### Alter Settings +#### Alter Settings -###### RQ.SRS-006.RBAC.Privileges.AlterSettings +##### RQ.SRS-006.RBAC.Privileges.AlterSettings version: 1.0 [ClickHouse] SHALL support controlling access to the **alter settings** privilege @@ -3427,19 +3491,19 @@ the destination table either because of the explicit grant or through one of the roles assigned to the user. The **alter settings** privilege allows modifying table engine settings. It doesn’t affect settings or server configuration parameters. -###### RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant version: 1.0 [ClickHouse] SHALL support granting **alter settings** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter settings** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter settings** privilege @@ -3447,7 +3511,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... MODIFY SETTING setting` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter settings** privilege @@ -3468,27 +3532,27 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Update +#### Alter Update -###### RQ.SRS-006.RBAC.Privileges.AlterUpdate +##### RQ.SRS-006.RBAC.Privileges.AlterUpdate version: 1.0 [ClickHouse] SHALL successfully execute `ALTER UPDATE` statement if and only if the user has **alter update** privilege for that column, either directly or through a role. -###### RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant version: 1.0 [ClickHouse] SHALL support granting **alter update** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter update** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter update** privilege @@ -3509,27 +3573,27 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Delete +#### Alter Delete -###### RQ.SRS-006.RBAC.Privileges.AlterDelete +##### RQ.SRS-006.RBAC.Privileges.AlterDelete version: 1.0 [ClickHouse] SHALL successfully execute `ALTER DELETE` statement if and only if the user has **alter delete** privilege for that table, either directly or through a role. -###### RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant version: 1.0 [ClickHouse] SHALL support granting **alter delete** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter delete** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter delete** privilege @@ -3550,27 +3614,27 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Freeze Partition +#### Alter Freeze Partition -###### RQ.SRS-006.RBAC.Privileges.AlterFreeze +##### RQ.SRS-006.RBAC.Privileges.AlterFreeze version: 1.0 [ClickHouse] SHALL successfully execute `ALTER FREEZE` statement if and only if the user has **alter freeze** privilege for that table, either directly or through a role. -###### RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant version: 1.0 [ClickHouse] SHALL support granting **alter freeze** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter freeze** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter freeze** privilege @@ -3591,27 +3655,27 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Fetch Partition +#### Alter Fetch Partition -###### RQ.SRS-006.RBAC.Privileges.AlterFetch +##### RQ.SRS-006.RBAC.Privileges.AlterFetch version: 1.0 [ClickHouse] SHALL successfully execute `ALTER FETCH` statement if and only if the user has **alter fetch** privilege for that table, either directly or through a role. -###### RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant version: 1.0 [ClickHouse] SHALL support granting **alter fetch** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter fetch** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter fetch** privilege @@ -3625,9 +3689,9 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Move Partition +#### Alter Move Partition -###### RQ.SRS-006.RBAC.Privileges.AlterMove +##### RQ.SRS-006.RBAC.Privileges.AlterMove version: 1.0 [ClickHouse] SHALL successfully execute `ALTER MOVE` statement if and only if the user has **alter move**, **select**, and **alter delete** privilege on the source table @@ -3637,19 +3701,19 @@ For example, ALTER TABLE source_table MOVE PARTITION 1 TO target_table ``` -###### RQ.SRS-006.RBAC.Privileges.AlterMove.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterMove.Grant version: 1.0 [ClickHouse] SHALL support granting **alter move** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter move** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter move** privilege @@ -3670,6 +3734,8 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree +### Create + #### RQ.SRS-006.RBAC.Privileges.CreateTable version: 1.0 @@ -3706,6 +3772,8 @@ version: 1.0 [ClickHouse] SHALL successfully execute `CREATE TEMPORARY TABLE` statement if and only if the user has **create temporary table** privilege on the table, either directly or through a role. +### Attach + #### RQ.SRS-006.RBAC.Privileges.AttachDatabase version: 1.0 @@ -3730,6 +3798,8 @@ version: 1.0 [ClickHouse] SHALL successfully execute `ATTACH TABLE` statement if and only if the user has **create table** privilege on the table, either directly or through a role. +### Drop + #### RQ.SRS-006.RBAC.Privileges.DropTable version: 1.0 @@ -3748,6 +3818,8 @@ version: 1.0 [ClickHouse] SHALL successfully execute `DROP DICTIONARY` statement if and only if the user has **drop dictionary** privilege on the dictionary, either directly or through a role. +### Detach + #### RQ.SRS-006.RBAC.Privileges.DetachTable version: 1.0 @@ -3772,354 +3844,360 @@ version: 1.0 [ClickHouse] SHALL successfully execute `DETACH DICTIONARY` statement if and only if the user has **drop dictionary** privilege on the dictionary, either directly or through a role. +### Truncate + #### RQ.SRS-006.RBAC.Privileges.Truncate version: 1.0 [ClickHouse] SHALL successfully execute `TRUNCATE TABLE` statement if and only if the user has **truncate table** privilege on the table, either directly or through a role. +### Optimize + #### RQ.SRS-006.RBAC.Privileges.Optimize version: 1.0 [ClickHouse] SHALL successfully execute `OPTIMIZE TABLE` statement if and only if the user has **optimize table** privilege on the table, either directly or through a role. +### Kill Query + #### RQ.SRS-006.RBAC.Privileges.KillQuery version: 1.0 [ClickHouse] SHALL successfully execute `KILL QUERY` statement if and only if the user has **kill query** privilege, either directly or through a role. -#### Kill Mutation +### Kill Mutation -##### RQ.SRS-006.RBAC.Privileges.KillMutation +#### RQ.SRS-006.RBAC.Privileges.KillMutation version: 1.0 [ClickHouse] SHALL successfully execute `KILL MUTATION` statement if and only if the user has the privilege that created the mutation, either directly or through a role. For example, to `KILL MUTATION` after `ALTER UPDATE` query, the user needs `ALTER UPDATE` privilege. -##### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate +#### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate version: 1.0 [ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER UPDATE` mutation if and only if the user has `ALTER UPDATE` privilege on the table where the mutation was created, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete +#### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete version: 1.0 [ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER DELETE` mutation if and only if the user has `ALTER DELETE` privilege on the table where the mutation was created, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn +#### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn version: 1.0 [ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER DROP COLUMN` mutation if and only if the user has `ALTER DROP COLUMN` privilege on the table where the mutation was created, either directly or through a role. -#### Show +### Show -##### RQ.SRS-006.RBAC.ShowTables.Privilege +#### RQ.SRS-006.RBAC.ShowTables.Privilege version: 1.0 [ClickHouse] SHALL grant **show tables** privilege on a table to a user if that user has recieved any grant, including `SHOW TABLES`, on that table, either directly or through a role. -##### RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW TABLES` statement if and only if the user has **show tables** privilege, or any privilege on the table either directly or through a role. -##### RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege +#### RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `EXISTS table` statement if and only if the user has **show tables** privilege, or any privilege on the table either directly or through a role. -##### RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege +#### RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `CHECK table` statement if and only if the user has **show tables** privilege, or any privilege on the table either directly or through a role. -##### RQ.SRS-006.RBAC.ShowDatabases.Privilege +#### RQ.SRS-006.RBAC.ShowDatabases.Privilege version: 1.0 [ClickHouse] SHALL grant **show databases** privilege on a database to a user if that user has recieved any grant, including `SHOW DATABASES`, on that table, either directly or through a role. -##### RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW DATABASES` statement if and only if the user has **show databases** privilege, or any privilege on the database either directly or through a role. -##### RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE DATABASE` statement if and only if the user has **show databases** privilege, or any privilege on the database either directly or through a role. -##### RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege +#### RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `USE database` statement if and only if the user has **show databases** privilege, or any privilege on the database either directly or through a role. -##### RQ.SRS-006.RBAC.ShowColumns.Privilege +#### RQ.SRS-006.RBAC.ShowColumns.Privilege version: 1.0 [ClickHouse] SHALL support granting or revoking the `SHOW COLUMNS` privilege. -##### RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE TABLE` statement if and only if the user has **show columns** privilege on that table, either directly or through a role. -##### RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege +#### RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `DESCRIBE table` statement if and only if the user has **show columns** privilege on that table, either directly or through a role. -##### RQ.SRS-006.RBAC.ShowDictionaries.Privilege +#### RQ.SRS-006.RBAC.ShowDictionaries.Privilege version: 1.0 [ClickHouse] SHALL grant **show dictionaries** privilege on a dictionary to a user if that user has recieved any grant, including `SHOW DICTIONARIES`, on that dictionary, either directly or through a role. -##### RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW DICTIONARIES` statement if and only if the user has **show dictionaries** privilege, or any privilege on the dictionary either directly or through a role. -##### RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE DICTIONARY` statement if and only if the user has **show dictionaries** privilege, or any privilege on the dictionary either directly or through a role. -##### RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege +#### RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `EXISTS dictionary` statement if and only if the user has **show dictionaries** privilege, or any privilege on the dictionary either directly or through a role. -#### Access Management +### Access Management -##### RQ.SRS-006.RBAC.Privileges.CreateUser +#### RQ.SRS-006.RBAC.Privileges.CreateUser version: 1.0 [ClickHouse] SHALL successfully execute `CREATE USER` statement if and only if the user has **create user** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole +#### RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole version: 1.0 [ClickHouse] SHALL successfully execute `CREATE USER` statement with `DEFAULT ROLE ` clause if and only if the user has **create user** privilege and the role with **admin option**, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterUser +#### RQ.SRS-006.RBAC.Privileges.AlterUser version: 1.0 [ClickHouse] SHALL successfully execute `ALTER USER` statement if and only if the user has **alter user** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropUser +#### RQ.SRS-006.RBAC.Privileges.DropUser version: 1.0 [ClickHouse] SHALL successfully execute `DROP USER` statement if and only if the user has **drop user** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateRole +#### RQ.SRS-006.RBAC.Privileges.CreateRole version: 1.0 [ClickHouse] SHALL successfully execute `CREATE ROLE` statement if and only if the user has **create role** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterRole +#### RQ.SRS-006.RBAC.Privileges.AlterRole version: 1.0 [ClickHouse] SHALL successfully execute `ALTER ROLE` statement if and only if the user has **alter role** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropRole +#### RQ.SRS-006.RBAC.Privileges.DropRole version: 1.0 [ClickHouse] SHALL successfully execute `DROP ROLE` statement if and only if the user has **drop role** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateRowPolicy +#### RQ.SRS-006.RBAC.Privileges.CreateRowPolicy version: 1.0 [ClickHouse] SHALL successfully execute `CREATE ROW POLICY` statement if and only if the user has **create row policy** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterRowPolicy +#### RQ.SRS-006.RBAC.Privileges.AlterRowPolicy version: 1.0 [ClickHouse] SHALL successfully execute `ALTER ROW POLICY` statement if and only if the user has **alter row policy** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropRowPolicy +#### RQ.SRS-006.RBAC.Privileges.DropRowPolicy version: 1.0 [ClickHouse] SHALL successfully execute `DROP ROW POLICY` statement if and only if the user has **drop row policy** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateQuota +#### RQ.SRS-006.RBAC.Privileges.CreateQuota version: 1.0 [ClickHouse] SHALL successfully execute `CREATE QUOTA` statement if and only if the user has **create quota** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterQuota +#### RQ.SRS-006.RBAC.Privileges.AlterQuota version: 1.0 [ClickHouse] SHALL successfully execute `ALTER QUOTA` statement if and only if the user has **alter quota** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropQuota +#### RQ.SRS-006.RBAC.Privileges.DropQuota version: 1.0 [ClickHouse] SHALL successfully execute `DROP QUOTA` statement if and only if the user has **drop quota** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile +#### RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile version: 1.0 [ClickHouse] SHALL successfully execute `CREATE SETTINGS PROFILE` statement if and only if the user has **create settings profile** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile +#### RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile version: 1.0 [ClickHouse] SHALL successfully execute `ALTER SETTINGS PROFILE` statement if and only if the user has **alter settings profile** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropSettingsProfile +#### RQ.SRS-006.RBAC.Privileges.DropSettingsProfile version: 1.0 [ClickHouse] SHALL successfully execute `DROP SETTINGS PROFILE` statement if and only if the user has **drop settings profile** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.RoleAdmin +#### RQ.SRS-006.RBAC.Privileges.RoleAdmin version: 1.0 [ClickHouse] SHALL successfully execute any role grant or revoke by a user with `ROLE ADMIN` privilege. -##### Show Access +#### Show Access -###### RQ.SRS-006.RBAC.ShowUsers.Privilege +##### RQ.SRS-006.RBAC.ShowUsers.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW USERS` privilege when the user is granted `SHOW USERS`, `SHOW CREATE USER`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW USERS` statement if and only if the user has **show users** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE USER` statement if and only if the user has **show users** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowRoles.Privilege +##### RQ.SRS-006.RBAC.ShowRoles.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW ROLES` privilege when the user is granted `SHOW ROLES`, `SHOW CREATE ROLE`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW ROLES` statement if and only if the user has **show roles** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE ROLE` statement if and only if the user has **show roles** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowRowPolicies.Privilege +##### RQ.SRS-006.RBAC.ShowRowPolicies.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW ROW POLICIES` privilege when the user is granted `SHOW ROW POLICIES`, `SHOW POLICIES`, `SHOW CREATE ROW POLICY`, `SHOW CREATE POLICY`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW ROW POLICIES` or `SHOW POLICIES` statement if and only if the user has **show row policies** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE ROW POLICY` or `SHOW CREATE POLICY` statement if and only if the user has **show row policies** privilege,either directly or through a role. -###### RQ.SRS-006.RBAC.ShowQuotas.Privilege +##### RQ.SRS-006.RBAC.ShowQuotas.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW QUOTAS` privilege when the user is granted `SHOW QUOTAS`, `SHOW CREATE QUOTA`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW QUOTAS` statement if and only if the user has **show quotas** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE QUOTA` statement if and only if the user has **show quotas** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege +##### RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW SETTINGS PROFILES` privilege when the user is granted `SHOW SETTINGS PROFILES`, `SHOW PROFILES`, `SHOW CREATE SETTINGS PROFILE`, `SHOW SETTINGS PROFILE`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW SETTINGS PROFILES` or `SHOW PROFILES` statement if and only if the user has **show settings profiles** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE SETTINGS PROFILE` or `SHOW CREATE PROFILE` statement if and only if the user has **show settings profiles** privilege, either directly or through a role. -#### dictGet +### dictGet -##### RQ.SRS-006.RBAC.dictGet.Privilege +#### RQ.SRS-006.RBAC.dictGet.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `dictGet` privilege when the user is granted `dictGet`, `dictHas`, `dictGetHierarchy`, or `dictIsIn`. -##### RQ.SRS-006.RBAC.dictGet.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictGet.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictGet` statement if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role. -##### RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictGet[TYPE]` statement @@ -4141,270 +4219,283 @@ Available types: * UUID * String -##### RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictGetOrDefault` statement if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role. -##### RQ.SRS-006.RBAC.dictHas.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictHas.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictHas` statement if and only if the user has **dictGet** privilege, either directly or through a role. -##### RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictGetHierarchy` statement if and only if the user has **dictGet** privilege, either directly or through a role. -##### RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictIsIn` statement if and only if the user has **dictGet** privilege, either directly or through a role. -#### Introspection +### Introspection -##### RQ.SRS-006.RBAC.Privileges.Introspection +#### RQ.SRS-006.RBAC.Privileges.Introspection version: 1.0 [ClickHouse] SHALL successfully grant `INTROSPECTION` privilege when the user is granted `INTROSPECTION` or `INTROSPECTION FUNCTIONS`. -##### RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine +#### RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine version: 1.0 [ClickHouse] SHALL successfully execute `addressToLine` statement if and only if the user has **introspection** privilege, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol +#### RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol version: 1.0 [ClickHouse] SHALL successfully execute `addressToSymbol` statement if and only if the user has **introspection** privilege, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Introspection.demangle +#### RQ.SRS-006.RBAC.Privileges.Introspection.demangle version: 1.0 [ClickHouse] SHALL successfully execute `demangle` statement if and only if the user has **introspection** privilege, either directly or through a role. -#### System +### System -##### RQ.SRS-006.RBAC.Privileges.System.Shutdown +#### RQ.SRS-006.RBAC.Privileges.System.Shutdown version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM SHUTDOWN` privilege when the user is granted `SYSTEM`, `SYSTEM SHUTDOWN`, `SHUTDOWN`,or `SYSTEM KILL`. -##### RQ.SRS-006.RBAC.Privileges.System.DropCache +#### RQ.SRS-006.RBAC.Privileges.System.DropCache version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DROP CACHE` privilege when the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, or `DROP CACHE`. -##### RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS +#### RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DROP DNS CACHE` privilege when the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP DNS CACHE`, `SYSTEM DROP DNS`, `DROP DNS CACHE`, or `DROP DNS`. -##### RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark +#### RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DROP MARK CACHE` privilege when the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP MARK CACHE`, `SYSTEM DROP MARK`, `DROP MARK CACHE`, or `DROP MARKS`. -##### RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed +#### RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DROP UNCOMPRESSED CACHE` privilege when the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP UNCOMPRESSED CACHE`, `SYSTEM DROP UNCOMPRESSED`, `DROP UNCOMPRESSED CACHE`, or `DROP UNCOMPRESSED`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload +#### RQ.SRS-006.RBAC.Privileges.System.Reload version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD` privilege when the user is granted `SYSTEM` or `SYSTEM RELOAD`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload.Config +#### RQ.SRS-006.RBAC.Privileges.System.Reload.Config version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD CONFIG` privilege when the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD CONFIG`, or `RELOAD CONFIG`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary +#### RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD DICTIONARY` privilege when the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARIES`, `RELOAD DICTIONARIES`, or `RELOAD DICTIONARY`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries +#### RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD DICTIONARIES` privilege when the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARIES`, `RELOAD DICTIONARIES`, or `RELOAD DICTIONARY`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries +#### RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD EMBEDDED DICTIONARIES` privilege when the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARY ON *.*`, or `SYSTEM RELOAD EMBEDDED DICTIONARIES`. -##### RQ.SRS-006.RBAC.Privileges.System.Merges +#### RQ.SRS-006.RBAC.Privileges.System.Merges version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM MERGES` privilege when the user is granted `SYSTEM`, `SYSTEM MERGES`, `SYSTEM STOP MERGES`, `SYSTEM START MERGES`, `STOP MERGES`, or `START MERGES`. -##### RQ.SRS-006.RBAC.Privileges.System.TTLMerges +#### RQ.SRS-006.RBAC.Privileges.System.TTLMerges version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM TTL MERGES` privilege when the user is granted `SYSTEM`, `SYSTEM TTL MERGES`, `SYSTEM STOP TTL MERGES`, `SYSTEM START TTL MERGES`, `STOP TTL MERGES`, or `START TTL MERGES`. -##### RQ.SRS-006.RBAC.Privileges.System.Fetches +#### RQ.SRS-006.RBAC.Privileges.System.Fetches version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM FETCHES` privilege when the user is granted `SYSTEM`, `SYSTEM FETCHES`, `SYSTEM STOP FETCHES`, `SYSTEM START FETCHES`, `STOP FETCHES`, or `START FETCHES`. -##### RQ.SRS-006.RBAC.Privileges.System.Moves +#### RQ.SRS-006.RBAC.Privileges.System.Moves version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM MOVES` privilege when the user is granted `SYSTEM`, `SYSTEM MOVES`, `SYSTEM STOP MOVES`, `SYSTEM START MOVES`, `STOP MOVES`, or `START MOVES`. -##### RQ.SRS-006.RBAC.Privileges.System.Sends +#### RQ.SRS-006.RBAC.Privileges.System.Sends version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM SENDS` privilege when the user is granted `SYSTEM`, `SYSTEM SENDS`, `SYSTEM STOP SENDS`, `SYSTEM START SENDS`, `STOP SENDS`, or `START SENDS`. -##### RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed +#### RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DISTRIBUTED SENDS` privilege when the user is granted `SYSTEM`, `SYSTEM DISTRIBUTED SENDS`, `SYSTEM STOP DISTRIBUTED SENDS`, `SYSTEM START DISTRIBUTED SENDS`, `STOP DISTRIBUTED SENDS`, or `START DISTRIBUTED SENDS`. -##### RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated +#### RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM REPLICATED SENDS` privilege when the user is granted `SYSTEM`, `SYSTEM REPLICATED SENDS`, `SYSTEM STOP REPLICATED SENDS`, `SYSTEM START REPLICATED SENDS`, `STOP REPLICATED SENDS`, or `START REPLICATED SENDS`. -##### RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues +#### RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM REPLICATION QUEUES` privilege when the user is granted `SYSTEM`, `SYSTEM REPLICATION QUEUES`, `SYSTEM STOP REPLICATION QUEUES`, `SYSTEM START REPLICATION QUEUES`, `STOP REPLICATION QUEUES`, or `START REPLICATION QUEUES`. -##### RQ.SRS-006.RBAC.Privileges.System.SyncReplica +#### RQ.SRS-006.RBAC.Privileges.System.SyncReplica version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM SYNC REPLICA` privilege when the user is granted `SYSTEM`, `SYSTEM SYNC REPLICA`, or `SYNC REPLICA`. -##### RQ.SRS-006.RBAC.Privileges.System.RestartReplica +#### RQ.SRS-006.RBAC.Privileges.System.RestartReplica version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RESTART REPLICA` privilege when the user is granted `SYSTEM`, `SYSTEM RESTART REPLICA`, or `RESTART REPLICA`. -##### RQ.SRS-006.RBAC.Privileges.System.Flush +#### RQ.SRS-006.RBAC.Privileges.System.Flush version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM FLUSH` privilege when the user is granted `SYSTEM` or `SYSTEM FLUSH`. -##### RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed +#### RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM FLUSH DISTRIBUTED` privilege when the user is granted `SYSTEM`, `SYSTEM FLUSH DISTRIBUTED`, or `FLUSH DISTRIBUTED`. -##### RQ.SRS-006.RBAC.Privileges.System.Flush.Logs +#### RQ.SRS-006.RBAC.Privileges.System.Flush.Logs version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM FLUSH LOGS` privilege when the user is granted `SYSTEM`, `SYSTEM FLUSH LOGS`, or `FLUSH LOGS`. -#### Sources +### Sources -##### RQ.SRS-006.RBAC.Privileges.Sources +#### RQ.SRS-006.RBAC.Privileges.Sources version: 1.0 [ClickHouse] SHALL support granting or revoking `SOURCES` privilege from the user, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.File +#### RQ.SRS-006.RBAC.Privileges.Sources.File version: 1.0 [ClickHouse] SHALL support the use of `FILE` source by a user if and only if the user has `FILE` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.URL +#### RQ.SRS-006.RBAC.Privileges.Sources.URL version: 1.0 [ClickHouse] SHALL support the use of `URL` source by a user if and only if the user has `URL` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.Remote +#### RQ.SRS-006.RBAC.Privileges.Sources.Remote version: 1.0 [ClickHouse] SHALL support the use of `REMOTE` source by a user if and only if the user has `REMOTE` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.MySQL +#### RQ.SRS-006.RBAC.Privileges.Sources.MySQL version: 1.0 [ClickHouse] SHALL support the use of `MySQL` source by a user if and only if the user has `MySQL` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.ODBC +#### RQ.SRS-006.RBAC.Privileges.Sources.ODBC version: 1.0 [ClickHouse] SHALL support the use of `ODBC` source by a user if and only if the user has `ODBC` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.JDBC +#### RQ.SRS-006.RBAC.Privileges.Sources.JDBC version: 1.0 [ClickHouse] SHALL support the use of `JDBC` source by a user if and only if the user has `JDBC` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.HDFS +#### RQ.SRS-006.RBAC.Privileges.Sources.HDFS version: 1.0 [ClickHouse] SHALL support the use of `HDFS` source by a user if and only if the user has `HDFS` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.S3 +#### RQ.SRS-006.RBAC.Privileges.Sources.S3 version: 1.0 [ClickHouse] SHALL support the use of `S3` source by a user if and only if the user has `S3` or `SOURCES` privileges granted to them directly or through a role. -#### RQ.SRS-006.RBAC.Privileges.GrantOption +### RQ.SRS-006.RBAC.Privileges.GrantOption version: 1.0 [ClickHouse] SHALL successfully execute `GRANT` or `REVOKE` privilege statements by a user if and only if the user has that privilege with `GRANT OPTION`, either directly or through a role. -#### RQ.SRS-006.RBAC.Privileges.All +### RQ.SRS-006.RBAC.Privileges.All version: 1.0 -[ClickHouse] SHALL support granting or revoking `ALL` privilege. +[ClickHouse] SHALL support granting or revoking `ALL` privilege +using `GRANT ALL ON *.* TO user`. -#### RQ.SRS-006.RBAC.Privileges.AdminOption +### RQ.SRS-006.RBAC.Privileges.RoleAll +version: 1.0 + +[ClickHouse] SHALL support granting a role named `ALL` using `GRANT ALL TO user`. +This shall only grant the user the privileges that have been granted to the role. + +### RQ.SRS-006.RBAC.Privileges.None +version: 1.0 + +[ClickHouse] SHALL support granting or revoking `NONE` privilege +using `GRANT NONE TO user` or `GRANT USAGE ON *.* TO user`. + +### RQ.SRS-006.RBAC.Privileges.AdminOption version: 1.0 [ClickHouse] SHALL support a user granting or revoking a role if and only if diff --git a/tests/testflows/rbac/requirements/requirements.py b/tests/testflows/rbac/requirements/requirements.py index f276d811f19..27f455d3fe6 100755 --- a/tests/testflows/rbac/requirements/requirements.py +++ b/tests/testflows/rbac/requirements/requirements.py @@ -1,28 +1,9983 @@ # These requirements were auto generated # from software requirements specification (SRS) -# document by TestFlows v1.6.201124.1002350. +# document by TestFlows v1.6.201216.1172002. # Do not edit by hand but re-generate instead # using 'tfs requirements generate' command. from testflows.core import Specification from testflows.core import Requirement +Heading = Specification.Heading + +RQ_SRS_006_RBAC = Requirement( + name='RQ.SRS-006.RBAC', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support role based access control.\n' + '\n' + ), + link=None, + level=3, + num='5.1.1') + +RQ_SRS_006_RBAC_Login = Requirement( + name='RQ.SRS-006.RBAC.Login', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only allow access to the server for a given\n' + 'user only when correct username and password are used during\n' + 'the connection to the server.\n' + '\n' + ), + link=None, + level=3, + num='5.2.1') + +RQ_SRS_006_RBAC_Login_DefaultUser = Requirement( + name='RQ.SRS-006.RBAC.Login.DefaultUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL use the **default user** when no username and password\n' + 'are specified during the connection to the server.\n' + '\n' + ), + link=None, + level=3, + num='5.2.2') + +RQ_SRS_006_RBAC_User = Requirement( + name='RQ.SRS-006.RBAC.User', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creation and manipulation of\n' + 'one or more **user** accounts to which roles, privileges,\n' + 'settings profile, quotas and row policies can be assigned.\n' + '\n' + ), + link=None, + level=3, + num='5.3.1') + +RQ_SRS_006_RBAC_User_Roles = Requirement( + name='RQ.SRS-006.RBAC.User.Roles', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more **roles**\n' + 'to a **user**.\n' + '\n' + ), + link=None, + level=3, + num='5.3.2') + +RQ_SRS_006_RBAC_User_Privileges = Requirement( + name='RQ.SRS-006.RBAC.User.Privileges', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more privileges to a **user**.\n' + '\n' + ), + link=None, + level=3, + num='5.3.3') + +RQ_SRS_006_RBAC_User_Variables = Requirement( + name='RQ.SRS-006.RBAC.User.Variables', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more variables to a **user**.\n' + '\n' + ), + link=None, + level=3, + num='5.3.4') + +RQ_SRS_006_RBAC_User_Variables_Constraints = Requirement( + name='RQ.SRS-006.RBAC.User.Variables.Constraints', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning min, max and read-only constraints\n' + 'for the variables that can be set and read by the **user**.\n' + '\n' + ), + link=None, + level=3, + num='5.3.5') + +RQ_SRS_006_RBAC_User_SettingsProfile = Requirement( + name='RQ.SRS-006.RBAC.User.SettingsProfile', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more **settings profiles**\n' + 'to a **user**.\n' + '\n' + ), + link=None, + level=3, + num='5.3.6') + +RQ_SRS_006_RBAC_User_Quotas = Requirement( + name='RQ.SRS-006.RBAC.User.Quotas', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more **quotas** to a **user**.\n' + '\n' + ), + link=None, + level=3, + num='5.3.7') + +RQ_SRS_006_RBAC_User_RowPolicies = Requirement( + name='RQ.SRS-006.RBAC.User.RowPolicies', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more **row policies** to a **user**.\n' + '\n' + ), + link=None, + level=3, + num='5.3.8') + +RQ_SRS_006_RBAC_User_DefaultRole = Requirement( + name='RQ.SRS-006.RBAC.User.DefaultRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning a default role to a **user**.\n' + '\n' + ), + link=None, + level=3, + num='5.3.9') + +RQ_SRS_006_RBAC_User_RoleSelection = Requirement( + name='RQ.SRS-006.RBAC.User.RoleSelection', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support selection of one or more **roles** from the available roles\n' + 'that are assigned to a **user** using `SET ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.3.10') + +RQ_SRS_006_RBAC_User_ShowCreate = Requirement( + name='RQ.SRS-006.RBAC.User.ShowCreate', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing the command of how **user** account was created.\n' + '\n' + ), + link=None, + level=3, + num='5.3.11') + +RQ_SRS_006_RBAC_User_ShowPrivileges = Requirement( + name='RQ.SRS-006.RBAC.User.ShowPrivileges', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support listing the privileges of the **user**.\n' + '\n' + ), + link=None, + level=3, + num='5.3.12') + +RQ_SRS_006_RBAC_User_Use_DefaultRole = Requirement( + name='RQ.SRS-006.RBAC.User.Use.DefaultRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL by default use default role or roles assigned\n' + 'to the user if specified.\n' + '\n' + ), + link=None, + level=3, + num='5.3.13') + +RQ_SRS_006_RBAC_User_Use_AllRolesWhenNoDefaultRole = Requirement( + name='RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL by default use all the roles assigned to the user\n' + 'if no default role or roles are specified for the user.\n' + '\n' + ), + link=None, + level=3, + num='5.3.14') + +RQ_SRS_006_RBAC_User_Create = Requirement( + name='RQ.SRS-006.RBAC.User.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creating **user** accounts using `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.1') + +RQ_SRS_006_RBAC_User_Create_IfNotExists = Requirement( + name='RQ.SRS-006.RBAC.User.Create.IfNotExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE USER` statement\n' + 'to skip raising an exception if a user with the same **name** already exists.\n' + 'If the `IF NOT EXISTS` clause is not specified then an exception SHALL be\n' + 'raised if a user with the same **name** already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.2') + +RQ_SRS_006_RBAC_User_Create_Replace = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Replace', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE USER` statement\n' + 'to replace existing user account if already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.3') + +RQ_SRS_006_RBAC_User_Create_Password_NoPassword = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.NoPassword', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying no password when creating\n' + 'user account using `IDENTIFIED WITH NO_PASSWORD` clause .\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.4') + +RQ_SRS_006_RBAC_User_Create_Password_NoPassword_Login = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.NoPassword.Login', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL use no password for the user when connecting to the server\n' + 'when an account was created with `IDENTIFIED WITH NO_PASSWORD` clause.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.5') + +RQ_SRS_006_RBAC_User_Create_Password_PlainText = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.PlainText', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying plaintext password when creating\n' + 'user account using `IDENTIFIED WITH PLAINTEXT_PASSWORD BY` clause.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.6') + +RQ_SRS_006_RBAC_User_Create_Password_PlainText_Login = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.PlainText.Login', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL use the plaintext password passed by the user when connecting to the server\n' + 'when an account was created with `IDENTIFIED WITH PLAINTEXT_PASSWORD` clause\n' + 'and compare the password with the one used in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.7') + +RQ_SRS_006_RBAC_User_Create_Password_Sha256Password = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Password', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying the result of applying SHA256\n' + 'to some password when creating user account using `IDENTIFIED WITH SHA256_PASSWORD BY` or `IDENTIFIED BY`\n' + 'clause.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.8') + +RQ_SRS_006_RBAC_User_Create_Password_Sha256Password_Login = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Password.Login', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL calculate `SHA256` of the password passed by the user when connecting to the server\n' + "when an account was created with `IDENTIFIED WITH SHA256_PASSWORD` or with 'IDENTIFIED BY' clause\n" + 'and compare the calculated hash to the one used in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.9') + +RQ_SRS_006_RBAC_User_Create_Password_Sha256Hash = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying the result of applying SHA256\n' + 'to some already calculated hash when creating user account using `IDENTIFIED WITH SHA256_HASH`\n' + 'clause.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.10') + +RQ_SRS_006_RBAC_User_Create_Password_Sha256Hash_Login = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash.Login', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL calculate `SHA256` of the already calculated hash passed by\n' + 'the user when connecting to the server\n' + 'when an account was created with `IDENTIFIED WITH SHA256_HASH` clause\n' + 'and compare the calculated hash to the one used in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.11') + +RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Password = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying the result of applying SHA1 two times\n' + 'to a password when creating user account using `IDENTIFIED WITH DOUBLE_SHA1_PASSWORD`\n' + 'clause.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.12') + +RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Password_Login = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password.Login', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL calculate `SHA1` two times over the password passed by\n' + 'the user when connecting to the server\n' + 'when an account was created with `IDENTIFIED WITH DOUBLE_SHA1_PASSWORD` clause\n' + 'and compare the calculated value to the one used in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.13') + +RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Hash = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying the result of applying SHA1 two times\n' + 'to a hash when creating user account using `IDENTIFIED WITH DOUBLE_SHA1_HASH`\n' + 'clause.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.14') + +RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Hash_Login = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash.Login', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL calculate `SHA1` two times over the hash passed by\n' + 'the user when connecting to the server\n' + 'when an account was created with `IDENTIFIED WITH DOUBLE_SHA1_HASH` clause\n' + 'and compare the calculated value to the one used in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.15') + +RQ_SRS_006_RBAC_User_Create_Host_Name = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Host.Name', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more hostnames from\n' + 'which user can access the server using the `HOST NAME` clause\n' + 'in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.16') + +RQ_SRS_006_RBAC_User_Create_Host_Regexp = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Host.Regexp', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more regular expressions\n' + 'to match hostnames from which user can access the server\n' + 'using the `HOST REGEXP` clause in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.17') + +RQ_SRS_006_RBAC_User_Create_Host_IP = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Host.IP', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more IP address or subnet from\n' + 'which user can access the server using the `HOST IP` clause in the\n' + '`CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.18') + +RQ_SRS_006_RBAC_User_Create_Host_Any = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Host.Any', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying `HOST ANY` clause in the `CREATE USER` statement\n' + 'to indicate that user can access the server from any host.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.19') + +RQ_SRS_006_RBAC_User_Create_Host_None = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Host.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support fobidding access from any host using `HOST NONE` clause in the\n' + '`CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.20') + +RQ_SRS_006_RBAC_User_Create_Host_Local = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Host.Local', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting user access to local only using `HOST LOCAL` clause in the\n' + '`CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.21') + +RQ_SRS_006_RBAC_User_Create_Host_Like = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Host.Like', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying host using `LIKE` command syntax using the\n' + '`HOST LIKE` clause in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.22') + +RQ_SRS_006_RBAC_User_Create_Host_Default = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Host.Default', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support user access to server from any host\n' + 'if no `HOST` clause is specified in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.23') + +RQ_SRS_006_RBAC_User_Create_DefaultRole = Requirement( + name='RQ.SRS-006.RBAC.User.Create.DefaultRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more default roles\n' + 'using `DEFAULT ROLE` clause in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.24') + +RQ_SRS_006_RBAC_User_Create_DefaultRole_None = Requirement( + name='RQ.SRS-006.RBAC.User.Create.DefaultRole.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying no default roles\n' + 'using `DEFAULT ROLE NONE` clause in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.25') + +RQ_SRS_006_RBAC_User_Create_DefaultRole_All = Requirement( + name='RQ.SRS-006.RBAC.User.Create.DefaultRole.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying all roles to be used as default\n' + 'using `DEFAULT ROLE ALL` clause in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.26') + +RQ_SRS_006_RBAC_User_Create_Settings = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Settings', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying settings and profile\n' + 'using `SETTINGS` clause in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.27') + +RQ_SRS_006_RBAC_User_Create_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.User.Create.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying cluster on which the user\n' + 'will be created using `ON CLUSTER` clause in the `CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.28') + +RQ_SRS_006_RBAC_User_Create_Syntax = Requirement( + name='RQ.SRS-006.RBAC.User.Create.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for `CREATE USER` statement.\n' + '\n' + '```sql\n' + 'CREATE USER [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name]\n' + " [IDENTIFIED [WITH {NO_PASSWORD|PLAINTEXT_PASSWORD|SHA256_PASSWORD|SHA256_HASH|DOUBLE_SHA1_PASSWORD|DOUBLE_SHA1_HASH}] BY {'password'|'hash'}]\n" + " [HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]\n" + ' [DEFAULT ROLE role [,...]]\n' + " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" + '```\n' + '\n' + ), + link=None, + level=4, + num='5.3.15.29') + +RQ_SRS_006_RBAC_User_Alter = Requirement( + name='RQ.SRS-006.RBAC.User.Alter', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering **user** accounts using `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.1') + +RQ_SRS_006_RBAC_User_Alter_OrderOfEvaluation = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.OrderOfEvaluation', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support evaluating `ALTER USER` statement from left to right\n' + 'where things defined on the right override anything that was previously defined on\n' + 'the left.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.2') + +RQ_SRS_006_RBAC_User_Alter_IfExists = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `IF EXISTS` clause in the `ALTER USER` statement\n' + 'to skip raising an exception (producing a warning instead) if a user with the specified **name** does not exist.\n' + 'If the `IF EXISTS` clause is not specified then an exception SHALL be raised if a user with the **name** does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.3') + +RQ_SRS_006_RBAC_User_Alter_Cluster = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying the cluster the user is on\n' + 'when altering user account using `ON CLUSTER` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.4') + +RQ_SRS_006_RBAC_User_Alter_Rename = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Rename', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying a new name for the user when\n' + 'altering user account using `RENAME` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.5') + +RQ_SRS_006_RBAC_User_Alter_Password_PlainText = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Password.PlainText', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying plaintext password when altering\n' + 'user account using `IDENTIFIED WITH PLAINTEXT_PASSWORD BY` or\n' + 'using shorthand `IDENTIFIED BY` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.6') + +RQ_SRS_006_RBAC_User_Alter_Password_Sha256Password = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Password.Sha256Password', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying the result of applying SHA256\n' + 'to some password as identification when altering user account using\n' + '`IDENTIFIED WITH SHA256_PASSWORD` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.7') + +RQ_SRS_006_RBAC_User_Alter_Password_DoubleSha1Password = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Password.DoubleSha1Password', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying the result of applying Double SHA1\n' + 'to some password as identification when altering user account using\n' + '`IDENTIFIED WITH DOUBLE_SHA1_PASSWORD` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.8') + +RQ_SRS_006_RBAC_User_Alter_Host_AddDrop = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Host.AddDrop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering user by adding and dropping access to hosts\n' + 'with the `ADD HOST` or the `DROP HOST` in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.9') + +RQ_SRS_006_RBAC_User_Alter_Host_Local = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Host.Local', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting user access to local only using `HOST LOCAL` clause in the\n' + '`ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.10') + +RQ_SRS_006_RBAC_User_Alter_Host_Name = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Host.Name', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more hostnames from\n' + 'which user can access the server using the `HOST NAME` clause\n' + 'in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.11') + +RQ_SRS_006_RBAC_User_Alter_Host_Regexp = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Host.Regexp', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more regular expressions\n' + 'to match hostnames from which user can access the server\n' + 'using the `HOST REGEXP` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.12') + +RQ_SRS_006_RBAC_User_Alter_Host_IP = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Host.IP', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more IP address or subnet from\n' + 'which user can access the server using the `HOST IP` clause in the\n' + '`ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.13') + +RQ_SRS_006_RBAC_User_Alter_Host_Like = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Host.Like', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more similar hosts using `LIKE` command syntax\n' + 'using the `HOST LIKE` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.14') + +RQ_SRS_006_RBAC_User_Alter_Host_Any = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Host.Any', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying `HOST ANY` clause in the `ALTER USER` statement\n' + 'to indicate that user can access the server from any host.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.15') + +RQ_SRS_006_RBAC_User_Alter_Host_None = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Host.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support fobidding access from any host using `HOST NONE` clause in the\n' + '`ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.16') + +RQ_SRS_006_RBAC_User_Alter_DefaultRole = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.DefaultRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more default roles\n' + 'using `DEFAULT ROLE` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.17') + +RQ_SRS_006_RBAC_User_Alter_DefaultRole_All = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.DefaultRole.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying all roles to be used as default\n' + 'using `DEFAULT ROLE ALL` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.18') + +RQ_SRS_006_RBAC_User_Alter_DefaultRole_AllExcept = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.DefaultRole.AllExcept', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more roles which will not be used as default\n' + 'using `DEFAULT ROLE ALL EXCEPT` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.19') + +RQ_SRS_006_RBAC_User_Alter_Settings = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Settings', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying one or more variables\n' + 'using `SETTINGS` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.20') + +RQ_SRS_006_RBAC_User_Alter_Settings_Min = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Settings.Min', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying a minimum value for the variable specifed using `SETTINGS` with `MIN` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.21') + +RQ_SRS_006_RBAC_User_Alter_Settings_Max = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Settings.Max', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying a maximum value for the variable specifed using `SETTINGS` with `MAX` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.22') + +RQ_SRS_006_RBAC_User_Alter_Settings_Profile = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Settings.Profile', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying the name of a profile for the variable specifed using `SETTINGS` with `PROFILE` clause in the `ALTER USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.23') + +RQ_SRS_006_RBAC_User_Alter_Syntax = Requirement( + name='RQ.SRS-006.RBAC.User.Alter.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `ALTER USER` statement.\n' + '\n' + '```sql\n' + 'ALTER USER [IF EXISTS] name [ON CLUSTER cluster_name]\n' + ' [RENAME TO new_name]\n' + " [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}]\n" + " [[ADD|DROP] HOST {LOCAL | NAME 'name' | REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]\n" + ' [DEFAULT ROLE role [,...] | ALL | ALL EXCEPT role [,...] ]\n' + " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" + '```\n' + '\n' + ), + link=None, + level=4, + num='5.3.16.24') + +RQ_SRS_006_RBAC_User_ShowCreateUser = Requirement( + name='RQ.SRS-006.RBAC.User.ShowCreateUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing the `CREATE USER` statement used to create the current user object\n' + 'using the `SHOW CREATE USER` statement with `CURRENT_USER` or no argument.\n' + '\n' + ), + link=None, + level=4, + num='5.3.17.1') + +RQ_SRS_006_RBAC_User_ShowCreateUser_For = Requirement( + name='RQ.SRS-006.RBAC.User.ShowCreateUser.For', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing the `CREATE USER` statement used to create the specified user object\n' + 'using the `FOR` clause in the `SHOW CREATE USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.17.2') + +RQ_SRS_006_RBAC_User_ShowCreateUser_Syntax = Requirement( + name='RQ.SRS-006.RBAC.User.ShowCreateUser.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing the following syntax for `SHOW CREATE USER` statement.\n' + '\n' + '```sql\n' + 'SHOW CREATE USER [name | CURRENT_USER]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.3.17.3') + +RQ_SRS_006_RBAC_User_Drop = Requirement( + name='RQ.SRS-006.RBAC.User.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support removing a user account using `DROP USER` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.3.18.1') + +RQ_SRS_006_RBAC_User_Drop_IfExists = Requirement( + name='RQ.SRS-006.RBAC.User.Drop.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support using `IF EXISTS` clause in the `DROP USER` statement\n' + 'to skip raising an exception if the user account does not exist.\n' + 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' + 'raised if a user does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.3.18.2') + +RQ_SRS_006_RBAC_User_Drop_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.User.Drop.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support using `ON CLUSTER` clause in the `DROP USER` statement\n' + 'to specify the name of the cluster the user should be dropped from.\n' + '\n' + ), + link=None, + level=4, + num='5.3.18.3') + +RQ_SRS_006_RBAC_User_Drop_Syntax = Requirement( + name='RQ.SRS-006.RBAC.User.Drop.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for `DROP USER` statement\n' + '\n' + '```sql\n' + 'DROP USER [IF EXISTS] name [,...] [ON CLUSTER cluster_name]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.3.18.4') + +RQ_SRS_006_RBAC_Role = Requirement( + name='RQ.SRS-006.RBAC.Role', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClikHouse] SHALL support creation and manipulation of **roles**\n' + 'to which privileges, settings profile, quotas and row policies can be\n' + 'assigned.\n' + '\n' + ), + link=None, + level=3, + num='5.4.1') + +RQ_SRS_006_RBAC_Role_Privileges = Requirement( + name='RQ.SRS-006.RBAC.Role.Privileges', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more privileges to a **role**.\n' + '\n' + ), + link=None, + level=3, + num='5.4.2') + +RQ_SRS_006_RBAC_Role_Variables = Requirement( + name='RQ.SRS-006.RBAC.Role.Variables', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more variables to a **role**.\n' + '\n' + ), + link=None, + level=3, + num='5.4.3') + +RQ_SRS_006_RBAC_Role_SettingsProfile = Requirement( + name='RQ.SRS-006.RBAC.Role.SettingsProfile', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more **settings profiles**\n' + 'to a **role**.\n' + '\n' + ), + link=None, + level=3, + num='5.4.4') + +RQ_SRS_006_RBAC_Role_Quotas = Requirement( + name='RQ.SRS-006.RBAC.Role.Quotas', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more **quotas** to a **role**.\n' + '\n' + ), + link=None, + level=3, + num='5.4.5') + +RQ_SRS_006_RBAC_Role_RowPolicies = Requirement( + name='RQ.SRS-006.RBAC.Role.RowPolicies', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning one or more **row policies** to a **role**.\n' + '\n' + ), + link=None, + level=3, + num='5.4.6') + +RQ_SRS_006_RBAC_Role_Create = Requirement( + name='RQ.SRS-006.RBAC.Role.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creating a **role** using `CREATE ROLE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.4.7.1') + +RQ_SRS_006_RBAC_Role_Create_IfNotExists = Requirement( + name='RQ.SRS-006.RBAC.Role.Create.IfNotExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE ROLE` statement\n' + 'to raising an exception if a role with the same **name** already exists.\n' + 'If the `IF NOT EXISTS` clause is not specified then an exception SHALL be\n' + 'raised if a role with the same **name** already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.4.7.2') + +RQ_SRS_006_RBAC_Role_Create_Replace = Requirement( + name='RQ.SRS-006.RBAC.Role.Create.Replace', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE ROLE` statement\n' + 'to replace existing role if it already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.4.7.3') + +RQ_SRS_006_RBAC_Role_Create_Settings = Requirement( + name='RQ.SRS-006.RBAC.Role.Create.Settings', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying settings and profile using `SETTINGS`\n' + 'clause in the `CREATE ROLE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.4.7.4') + +RQ_SRS_006_RBAC_Role_Create_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Role.Create.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `CREATE ROLE` statement\n' + '\n' + '``` sql\n' + 'CREATE ROLE [IF NOT EXISTS | OR REPLACE] name\n' + " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" + '```\n' + '\n' + ), + link=None, + level=4, + num='5.4.7.5') + +RQ_SRS_006_RBAC_Role_Alter = Requirement( + name='RQ.SRS-006.RBAC.Role.Alter', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering one **role** using `ALTER ROLE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.4.8.1') + +RQ_SRS_006_RBAC_Role_Alter_IfExists = Requirement( + name='RQ.SRS-006.RBAC.Role.Alter.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering one **role** using `ALTER ROLE IF EXISTS` statement, where no exception\n' + 'will be thrown if the role does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.4.8.2') + +RQ_SRS_006_RBAC_Role_Alter_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Role.Alter.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering one **role** using `ALTER ROLE role ON CLUSTER` statement to specify the\n' + 'cluster location of the specified role.\n' + '\n' + ), + link=None, + level=4, + num='5.4.8.3') + +RQ_SRS_006_RBAC_Role_Alter_Rename = Requirement( + name='RQ.SRS-006.RBAC.Role.Alter.Rename', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering one **role** using `ALTER ROLE role RENAME TO` statement which renames the\n' + 'role to a specified new name. If the new name already exists, that an exception SHALL be raised unless the\n' + '`IF EXISTS` clause is specified, by which no exception will be raised and nothing will change.\n' + '\n' + ), + link=None, + level=4, + num='5.4.8.4') + +RQ_SRS_006_RBAC_Role_Alter_Settings = Requirement( + name='RQ.SRS-006.RBAC.Role.Alter.Settings', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the settings of one **role** using `ALTER ROLE role SETTINGS ...` statement.\n' + 'Altering variable values, creating max and min values, specifying readonly or writable, and specifying the\n' + 'profiles for which this alter change shall be applied to, are all supported, using the following syntax.\n' + '\n' + '```sql\n' + "[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" + '```\n' + '\n' + 'One or more variables and profiles may be specified as shown above.\n' + '\n' + ), + link=None, + level=4, + num='5.4.8.5') + +RQ_SRS_006_RBAC_Role_Alter_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Role.Alter.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '```sql\n' + 'ALTER ROLE [IF EXISTS] name [ON CLUSTER cluster_name]\n' + ' [RENAME TO new_name]\n' + " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" + '```\n' + '\n' + ), + link=None, + level=4, + num='5.4.8.6') + +RQ_SRS_006_RBAC_Role_Drop = Requirement( + name='RQ.SRS-006.RBAC.Role.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support removing one or more roles using `DROP ROLE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.4.9.1') + +RQ_SRS_006_RBAC_Role_Drop_IfExists = Requirement( + name='RQ.SRS-006.RBAC.Role.Drop.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support using `IF EXISTS` clause in the `DROP ROLE` statement\n' + 'to skip raising an exception if the role does not exist.\n' + 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' + 'raised if a role does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.4.9.2') + +RQ_SRS_006_RBAC_Role_Drop_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Role.Drop.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support using `ON CLUSTER` clause in the `DROP ROLE` statement to specify the cluster from which to drop the specified role.\n' + '\n' + ), + link=None, + level=4, + num='5.4.9.3') + +RQ_SRS_006_RBAC_Role_Drop_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Role.Drop.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `DROP ROLE` statement\n' + '\n' + '``` sql\n' + 'DROP ROLE [IF EXISTS] name [,...] [ON CLUSTER cluster_name]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.4.9.4') + +RQ_SRS_006_RBAC_Role_ShowCreate = Requirement( + name='RQ.SRS-006.RBAC.Role.ShowCreate', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support viewing the settings for a role upon creation with the `SHOW CREATE ROLE`\n' + 'statement.\n' + '\n' + ), + link=None, + level=4, + num='5.4.10.1') + +RQ_SRS_006_RBAC_Role_ShowCreate_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Role.ShowCreate.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `SHOW CREATE ROLE` command.\n' + '\n' + '```sql\n' + 'SHOW CREATE ROLE name\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.4.10.2') + +RQ_SRS_006_RBAC_PartialRevokes = Requirement( + name='RQ.SRS-006.RBAC.PartialRevokes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support partial revoking of privileges granted\n' + 'to a **user** or a **role**.\n' + '\n' + ), + link=None, + level=3, + num='5.5.1') + +RQ_SRS_006_RBAC_PartialRevoke_Syntax = Requirement( + name='RQ.SRS-006.RBAC.PartialRevoke.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support partial revokes by using `partial_revokes` variable\n' + 'that can be set or unset using the following syntax.\n' + '\n' + 'To disable partial revokes the `partial_revokes` variable SHALL be set to `0`\n' + '\n' + '```sql\n' + 'SET partial_revokes = 0\n' + '```\n' + '\n' + 'To enable partial revokes the `partial revokes` variable SHALL be set to `1`\n' + '\n' + '```sql\n' + 'SET partial_revokes = 1\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='5.5.2') + +RQ_SRS_006_RBAC_SettingsProfile = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creation and manipulation of **settings profiles**\n' + 'that can include value definition for one or more variables and can\n' + 'can be assigned to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=3, + num='5.6.1') + +RQ_SRS_006_RBAC_SettingsProfile_Constraints = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Constraints', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning min, max and read-only constraints\n' + 'for the variables specified in the **settings profile**.\n' + '\n' + ), + link=None, + level=3, + num='5.6.2') + +RQ_SRS_006_RBAC_SettingsProfile_Create = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creating settings profile using the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.1') + +RQ_SRS_006_RBAC_SettingsProfile_Create_IfNotExists = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.IfNotExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE SETTINGS PROFILE` statement\n' + 'to skip raising an exception if a settings profile with the same **name** already exists.\n' + 'If `IF NOT EXISTS` clause is not specified then an exception SHALL be raised if\n' + 'a settings profile with the same **name** already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.2') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Replace = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Replace', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE SETTINGS PROFILE` statement\n' + 'to replace existing settings profile if it already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.3') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Variables = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Variables', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning values and constraints to one or more\n' + 'variables in the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.4') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Value = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Value', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning variable value in the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.5') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Constraints', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting `MIN`, `MAX`, `READONLY`, and `WRITABLE`\n' + 'constraints for the variables in the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.6') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning settings profile to one or more users\n' + 'or roles in the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.7') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_None = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning settings profile to no users or roles using\n' + '`TO NONE` clause in the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.8') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_All = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning settings profile to all current users and roles\n' + 'using `TO ALL` clause in the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.9') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_AllExcept = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.AllExcept', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support excluding assignment to one or more users or roles using\n' + 'the `ALL EXCEPT` clause in the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.10') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Inherit = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Inherit', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support inheriting profile settings from indicated profile using\n' + 'the `INHERIT` clause in the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.11') + +RQ_SRS_006_RBAC_SettingsProfile_Create_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying what cluster to create settings profile on\n' + 'using `ON CLUSTER` clause in the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.12') + +RQ_SRS_006_RBAC_SettingsProfile_Create_Syntax = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Create.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `CREATE SETTINGS PROFILE` statement.\n' + '\n' + '``` sql\n' + 'CREATE SETTINGS PROFILE [IF NOT EXISTS | OR REPLACE] name\n' + ' [ON CLUSTER cluster_name]\n' + " [SET varname [= value] [MIN min] [MAX max] [READONLY|WRITABLE] | [INHERIT 'profile_name'] [,...]]\n" + ' [TO {user_or_role [,...] | NONE | ALL | ALL EXCEPT user_or_role [,...]}]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.6.3.13') + +RQ_SRS_006_RBAC_SettingsProfile_Alter = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering settings profile using the `ALTER STETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.1') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_IfExists = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `IF EXISTS` clause in the `ALTER SETTINGS PROFILE` statement\n' + 'to not raise exception if a settings profile does not exist.\n' + 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' + 'raised if a settings profile does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.2') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Rename = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Rename', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support renaming settings profile using the `RANAME TO` clause\n' + 'in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.3') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering values and constraints of one or more\n' + 'variables in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.4') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Value', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering value of the variable in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.5') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Constraints', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering `MIN`, `MAX`, `READONLY`, and `WRITABLE`\n' + 'constraints for the variables in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.6') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support reassigning settings profile to one or more users\n' + 'or roles using the `TO` clause in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.7') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_None = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support reassigning settings profile to no users or roles using the\n' + '`TO NONE` clause in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.8') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_All = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support reassigning settings profile to all current users and roles\n' + 'using the `TO ALL` clause in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.9') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_AllExcept = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.AllExcept', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support excluding assignment to one or more users or roles using\n' + 'the `TO ALL EXCEPT` clause in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.10') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_Inherit = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.Inherit', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the settings profile by inheriting settings from\n' + 'specified profile using `INHERIT` clause in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.11') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the settings profile on a specified cluster using\n' + '`ON CLUSTER` clause in the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.12') + +RQ_SRS_006_RBAC_SettingsProfile_Alter_Syntax = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `ALTER SETTINGS PROFILE` statement.\n' + '\n' + '``` sql\n' + 'ALTER SETTINGS PROFILE [IF EXISTS] name\n' + ' [ON CLUSTER cluster_name]\n' + ' [RENAME TO new_name]\n' + " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | INHERIT 'profile_name'] [,...]\n" + ' [TO {user_or_role [,...] | NONE | ALL | ALL EXCEPT user_or_role [,...]]}\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.6.4.13') + +RQ_SRS_006_RBAC_SettingsProfile_Drop = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support removing one or more settings profiles using the `DROP SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.5.1') + +RQ_SRS_006_RBAC_SettingsProfile_Drop_IfExists = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Drop.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support using `IF EXISTS` clause in the `DROP SETTINGS PROFILE` statement\n' + 'to skip raising an exception if the settings profile does not exist.\n' + 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' + 'raised if a settings profile does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.6.5.2') + +RQ_SRS_006_RBAC_SettingsProfile_Drop_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Drop.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support dropping one or more settings profiles on specified cluster using\n' + '`ON CLUSTER` clause in the `DROP SETTINGS PROFILE` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.6.5.3') + +RQ_SRS_006_RBAC_SettingsProfile_Drop_Syntax = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.Drop.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `DROP SETTINGS PROFILE` statement\n' + '\n' + '``` sql\n' + 'DROP SETTINGS PROFILE [IF EXISTS] name [,name,...]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.6.5.4') + +RQ_SRS_006_RBAC_SettingsProfile_ShowCreateSettingsProfile = Requirement( + name='RQ.SRS-006.RBAC.SettingsProfile.ShowCreateSettingsProfile', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing the `CREATE SETTINGS PROFILE` statement used to create the settings profile\n' + 'using the `SHOW CREATE SETTINGS PROFILE` statement with the following syntax\n' + '\n' + '``` sql\n' + 'SHOW CREATE SETTINGS PROFILE name\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.6.6.1') + +RQ_SRS_006_RBAC_Quotas = Requirement( + name='RQ.SRS-006.RBAC.Quotas', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creation and manipulation of **quotas**\n' + 'that can be used to limit resource usage by a **user** or a **role**\n' + 'over a period of time.\n' + '\n' + ), + link=None, + level=3, + num='5.7.1') + +RQ_SRS_006_RBAC_Quotas_Keyed = Requirement( + name='RQ.SRS-006.RBAC.Quotas.Keyed', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creating **quotas** that are keyed\n' + 'so that a quota is tracked separately for each key value.\n' + '\n' + ), + link=None, + level=3, + num='5.7.2') + +RQ_SRS_006_RBAC_Quotas_Queries = Requirement( + name='RQ.SRS-006.RBAC.Quotas.Queries', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting **queries** quota to limit the total number of requests.\n' + '\n' + ), + link=None, + level=3, + num='5.7.3') + +RQ_SRS_006_RBAC_Quotas_Errors = Requirement( + name='RQ.SRS-006.RBAC.Quotas.Errors', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting **errors** quota to limit the number of queries that threw an exception.\n' + '\n' + ), + link=None, + level=3, + num='5.7.4') + +RQ_SRS_006_RBAC_Quotas_ResultRows = Requirement( + name='RQ.SRS-006.RBAC.Quotas.ResultRows', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting **result rows** quota to limit the\n' + 'the total number of rows given as the result.\n' + '\n' + ), + link=None, + level=3, + num='5.7.5') + +RQ_SRS_006_RBAC_Quotas_ReadRows = Requirement( + name='RQ.SRS-006.RBAC.Quotas.ReadRows', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting **read rows** quota to limit the total\n' + 'number of source rows read from tables for running the query on all remote servers.\n' + '\n' + ), + link=None, + level=3, + num='5.7.6') + +RQ_SRS_006_RBAC_Quotas_ResultBytes = Requirement( + name='RQ.SRS-006.RBAC.Quotas.ResultBytes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting **result bytes** quota to limit the total number\n' + 'of bytes that can be returned as the result.\n' + '\n' + ), + link=None, + level=3, + num='5.7.7') + +RQ_SRS_006_RBAC_Quotas_ReadBytes = Requirement( + name='RQ.SRS-006.RBAC.Quotas.ReadBytes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting **read bytes** quota to limit the total number\n' + 'of source bytes read from tables for running the query on all remote servers.\n' + '\n' + ), + link=None, + level=3, + num='5.7.8') + +RQ_SRS_006_RBAC_Quotas_ExecutionTime = Requirement( + name='RQ.SRS-006.RBAC.Quotas.ExecutionTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting **execution time** quota to limit the maximum\n' + 'query execution time.\n' + '\n' + ), + link=None, + level=3, + num='5.7.9') + +RQ_SRS_006_RBAC_Quota_Create = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creating quotas using the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.1') + +RQ_SRS_006_RBAC_Quota_Create_IfNotExists = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.IfNotExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE QUOTA` statement\n' + 'to skip raising an exception if a quota with the same **name** already exists.\n' + 'If `IF NOT EXISTS` clause is not specified then an exception SHALL be raised if\n' + 'a quota with the same **name** already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.2') + +RQ_SRS_006_RBAC_Quota_Create_Replace = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Replace', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE QUOTA` statement\n' + 'to replace existing quota if it already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.3') + +RQ_SRS_006_RBAC_Quota_Create_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creating quotas on a specific cluster with the\n' + '`ON CLUSTER` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.4') + +RQ_SRS_006_RBAC_Quota_Create_Interval = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Interval', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support defining the quota interval that specifies\n' + 'a period of time over for which the quota SHALL apply using the\n' + '`FOR INTERVAL` clause in the `CREATE QUOTA` statement.\n' + '\n' + 'This statement SHALL also support a number and a time period which will be one\n' + 'of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be:\n' + '\n' + '`FOR INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some real number\n' + 'to define the interval.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.5') + +RQ_SRS_006_RBAC_Quota_Create_Interval_Randomized = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Interval.Randomized', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support defining the quota randomized interval that specifies\n' + 'a period of time over for which the quota SHALL apply using the\n' + '`FOR RANDOMIZED INTERVAL` clause in the `CREATE QUOTA` statement.\n' + '\n' + 'This statement SHALL also support a number and a time period which will be one\n' + 'of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be:\n' + '\n' + '`FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some\n' + 'real number to define the interval.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.6') + +RQ_SRS_006_RBAC_Quota_Create_Queries = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Queries', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting number of requests over a period of time\n' + 'using the `QUERIES` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.7') + +RQ_SRS_006_RBAC_Quota_Create_Errors = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Errors', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting number of queries that threw an exception\n' + 'using the `ERRORS` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.8') + +RQ_SRS_006_RBAC_Quota_Create_ResultRows = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.ResultRows', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting the total number of rows given as the result\n' + 'using the `RESULT ROWS` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.9') + +RQ_SRS_006_RBAC_Quota_Create_ReadRows = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.ReadRows', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting the total number of source rows read from tables\n' + 'for running the query on all remote servers\n' + 'using the `READ ROWS` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.10') + +RQ_SRS_006_RBAC_Quota_Create_ResultBytes = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.ResultBytes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting the total number of bytes that can be returned as the result\n' + 'using the `RESULT BYTES` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.11') + +RQ_SRS_006_RBAC_Quota_Create_ReadBytes = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.ReadBytes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting the total number of source bytes read from tables\n' + 'for running the query on all remote servers\n' + 'using the `READ BYTES` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.12') + +RQ_SRS_006_RBAC_Quota_Create_ExecutionTime = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.ExecutionTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting the maximum query execution time\n' + 'using the `EXECUTION TIME` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.13') + +RQ_SRS_006_RBAC_Quota_Create_NoLimits = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.NoLimits', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting the maximum query execution time\n' + 'using the `NO LIMITS` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.14') + +RQ_SRS_006_RBAC_Quota_Create_TrackingOnly = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.TrackingOnly', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting the maximum query execution time\n' + 'using the `TRACKING ONLY` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.15') + +RQ_SRS_006_RBAC_Quota_Create_KeyedBy = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.KeyedBy', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support to track quota for some key\n' + 'following the `KEYED BY` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.16') + +RQ_SRS_006_RBAC_Quota_Create_KeyedByOptions = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.KeyedByOptions', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support to track quota separately for some parameter\n' + "using the `KEYED BY 'parameter'` clause in the `CREATE QUOTA` statement.\n" + '\n' + "'parameter' can be one of:\n" + "`{'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}`\n" + '\n' + ), + link=None, + level=4, + num='5.7.10.17') + +RQ_SRS_006_RBAC_Quota_Create_Assignment = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Assignment', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning quota to one or more users\n' + 'or roles using the `TO` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.18') + +RQ_SRS_006_RBAC_Quota_Create_Assignment_None = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Assignment.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning quota to no users or roles using\n' + '`TO NONE` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.19') + +RQ_SRS_006_RBAC_Quota_Create_Assignment_All = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Assignment.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning quota to all current users and roles\n' + 'using `TO ALL` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.20') + +RQ_SRS_006_RBAC_Quota_Create_Assignment_Except = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Assignment.Except', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support excluding assignment of quota to one or more users or roles using\n' + 'the `EXCEPT` clause in the `CREATE QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.21') + +RQ_SRS_006_RBAC_Quota_Create_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Quota.Create.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `CREATE QUOTA` statement\n' + '\n' + '```sql\n' + 'CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name]\n' + " [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]\n" + ' [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}\n' + ' {MAX { {QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number } [,...] |\n' + ' NO LIMITS | TRACKING ONLY} [,...]]\n' + ' [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.7.10.22') + +RQ_SRS_006_RBAC_Quota_Alter = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering quotas using the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.1') + +RQ_SRS_006_RBAC_Quota_Alter_IfExists = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `IF EXISTS` clause in the `ALTER QUOTA` statement\n' + 'to skip raising an exception if a quota does not exist.\n' + 'If the `IF EXISTS` clause is not specified then an exception SHALL be raised if\n' + 'a quota does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.2') + +RQ_SRS_006_RBAC_Quota_Alter_Rename = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Rename', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `RENAME TO` clause in the `ALTER QUOTA` statement\n' + 'to rename the quota to the specified name.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.3') + +RQ_SRS_006_RBAC_Quota_Alter_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering quotas on a specific cluster with the\n' + '`ON CLUSTER` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.4') + +RQ_SRS_006_RBAC_Quota_Alter_Interval = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Interval', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support redefining the quota interval that specifies\n' + 'a period of time over for which the quota SHALL apply using the\n' + '`FOR INTERVAL` clause in the `ALTER QUOTA` statement.\n' + '\n' + 'This statement SHALL also support a number and a time period which will be one\n' + 'of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be:\n' + '\n' + '`FOR INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some real number\n' + 'to define the interval.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.5') + +RQ_SRS_006_RBAC_Quota_Alter_Interval_Randomized = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Interval.Randomized', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support redefining the quota randomized interval that specifies\n' + 'a period of time over for which the quota SHALL apply using the\n' + '`FOR RANDOMIZED INTERVAL` clause in the `ALTER QUOTA` statement.\n' + '\n' + 'This statement SHALL also support a number and a time period which will be one\n' + 'of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be:\n' + '\n' + '`FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some\n' + 'real number to define the interval.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.6') + +RQ_SRS_006_RBAC_Quota_Alter_Queries = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Queries', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the limit of number of requests over a period of time\n' + 'using the `QUERIES` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.7') + +RQ_SRS_006_RBAC_Quota_Alter_Errors = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Errors', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the limit of number of queries that threw an exception\n' + 'using the `ERRORS` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.8') + +RQ_SRS_006_RBAC_Quota_Alter_ResultRows = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.ResultRows', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the limit of the total number of rows given as the result\n' + 'using the `RESULT ROWS` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.9') + +RQ_SRS_006_RBAC_Quota_Alter_ReadRows = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.ReadRows', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the limit of the total number of source rows read from tables\n' + 'for running the query on all remote servers\n' + 'using the `READ ROWS` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.10') + +RQ_SRS_006_RBAC_Quota_ALter_ResultBytes = Requirement( + name='RQ.SRS-006.RBAC.Quota.ALter.ResultBytes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the limit of the total number of bytes that can be returned as the result\n' + 'using the `RESULT BYTES` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.11') + +RQ_SRS_006_RBAC_Quota_Alter_ReadBytes = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.ReadBytes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the limit of the total number of source bytes read from tables\n' + 'for running the query on all remote servers\n' + 'using the `READ BYTES` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.12') + +RQ_SRS_006_RBAC_Quota_Alter_ExecutionTime = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.ExecutionTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering the limit of the maximum query execution time\n' + 'using the `EXECUTION TIME` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.13') + +RQ_SRS_006_RBAC_Quota_Alter_NoLimits = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.NoLimits', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting the maximum query execution time\n' + 'using the `NO LIMITS` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.14') + +RQ_SRS_006_RBAC_Quota_Alter_TrackingOnly = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.TrackingOnly', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support limiting the maximum query execution time\n' + 'using the `TRACKING ONLY` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.15') + +RQ_SRS_006_RBAC_Quota_Alter_KeyedBy = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.KeyedBy', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering quota to track quota separately for some key\n' + 'following the `KEYED BY` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.16') + +RQ_SRS_006_RBAC_Quota_Alter_KeyedByOptions = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.KeyedByOptions', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering quota to track quota separately for some parameter\n' + "using the `KEYED BY 'parameter'` clause in the `ALTER QUOTA` statement.\n" + '\n' + "'parameter' can be one of:\n" + "`{'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}`\n" + '\n' + ), + link=None, + level=4, + num='5.7.11.17') + +RQ_SRS_006_RBAC_Quota_Alter_Assignment = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Assignment', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support reassigning quota to one or more users\n' + 'or roles using the `TO` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.18') + +RQ_SRS_006_RBAC_Quota_Alter_Assignment_None = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Assignment.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support reassigning quota to no users or roles using\n' + '`TO NONE` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.19') + +RQ_SRS_006_RBAC_Quota_Alter_Assignment_All = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Assignment.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support reassigning quota to all current users and roles\n' + 'using `TO ALL` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.20') + +RQ_SRS_006_RBAC_Quota_Alter_Assignment_Except = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Assignment.Except', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support excluding assignment of quota to one or more users or roles using\n' + 'the `EXCEPT` clause in the `ALTER QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.21') + +RQ_SRS_006_RBAC_Quota_Alter_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Quota.Alter.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `ALTER QUOTA` statement\n' + '\n' + '``` sql\n' + 'ALTER QUOTA [IF EXIST] name\n' + ' {{{QUERIES | ERRORS | RESULT ROWS | READ ROWS | RESULT BYTES | READ BYTES | EXECUTION TIME} number} [, ...] FOR INTERVAL number time_unit} [, ...]\n' + ' [KEYED BY USERNAME | KEYED BY IP | NOT KEYED] [ALLOW CUSTOM KEY | DISALLOW CUSTOM KEY]\n' + ' [TO {user_or_role [,...] | NONE | ALL} [EXCEPT user_or_role [,...]]]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.7.11.22') + +RQ_SRS_006_RBAC_Quota_Drop = Requirement( + name='RQ.SRS-006.RBAC.Quota.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support removing one or more quotas using the `DROP QUOTA` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.7.12.1') + +RQ_SRS_006_RBAC_Quota_Drop_IfExists = Requirement( + name='RQ.SRS-006.RBAC.Quota.Drop.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support using `IF EXISTS` clause in the `DROP QUOTA` statement\n' + 'to skip raising an exception when the quota does not exist.\n' + 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' + 'raised if the quota does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.7.12.2') + +RQ_SRS_006_RBAC_Quota_Drop_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Quota.Drop.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support using `ON CLUSTER` clause in the `DROP QUOTA` statement\n' + 'to indicate the cluster the quota to be dropped is located on.\n' + '\n' + ), + link=None, + level=4, + num='5.7.12.3') + +RQ_SRS_006_RBAC_Quota_Drop_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Quota.Drop.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `DROP QUOTA` statement\n' + '\n' + '``` sql\n' + 'DROP QUOTA [IF EXISTS] name [,name...]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.7.12.4') + +RQ_SRS_006_RBAC_Quota_ShowQuotas = Requirement( + name='RQ.SRS-006.RBAC.Quota.ShowQuotas', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing all of the current quotas\n' + 'using the `SHOW QUOTAS` statement with the following syntax\n' + '\n' + ), + link=None, + level=4, + num='5.7.13.1') + +RQ_SRS_006_RBAC_Quota_ShowQuotas_IntoOutfile = Requirement( + name='RQ.SRS-006.RBAC.Quota.ShowQuotas.IntoOutfile', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the `INTO OUTFILE` clause in the `SHOW QUOTAS` statement to define an outfile by some given string literal.\n' + '\n' + ), + link=None, + level=4, + num='5.7.13.2') + +RQ_SRS_006_RBAC_Quota_ShowQuotas_Format = Requirement( + name='RQ.SRS-006.RBAC.Quota.ShowQuotas.Format', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the `FORMAT` clause in the `SHOW QUOTAS` statement to define a format for the output quota list.\n' + '\n' + 'The types of valid formats are many, listed in output column:\n' + 'https://clickhouse.tech/docs/en/interfaces/formats/\n' + '\n' + ), + link=None, + level=4, + num='5.7.13.3') + +RQ_SRS_006_RBAC_Quota_ShowQuotas_Settings = Requirement( + name='RQ.SRS-006.RBAC.Quota.ShowQuotas.Settings', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the `SETTINGS` clause in the `SHOW QUOTAS` statement to define settings in the showing of all quotas.\n' + '\n' + ), + link=None, + level=4, + num='5.7.13.4') + +RQ_SRS_006_RBAC_Quota_ShowQuotas_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Quota.ShowQuotas.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support using the `SHOW QUOTAS` statement\n' + 'with the following syntax\n' + '``` sql\n' + 'SHOW QUOTAS\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.7.13.5') + +RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Name = Requirement( + name='RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Name', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing the `CREATE QUOTA` statement used to create the quota with some given name\n' + 'using the `SHOW CREATE QUOTA` statement with the following syntax\n' + '\n' + '``` sql\n' + 'SHOW CREATE QUOTA name\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.7.14.1') + +RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Current = Requirement( + name='RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Current', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing the `CREATE QUOTA` statement used to create the CURRENT quota\n' + 'using the `SHOW CREATE QUOTA CURRENT` statement or the shorthand form\n' + '`SHOW CREATE QUOTA`\n' + '\n' + ), + link=None, + level=4, + num='5.7.14.2') + +RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax when\n' + 'using the `SHOW CREATE QUOTA` statement.\n' + '\n' + '```sql\n' + 'SHOW CREATE QUOTA [name | CURRENT]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.7.14.3') + +RQ_SRS_006_RBAC_RowPolicy = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creation and manipulation of table **row policies**\n' + 'that can be used to limit access to the table contents for a **user** or a **role**\n' + 'using a specified **condition**.\n' + '\n' + ), + link=None, + level=3, + num='5.8.1') + +RQ_SRS_006_RBAC_RowPolicy_Condition = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Condition', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support row policy **conditions** that can be any SQL\n' + 'expression that returns a boolean.\n' + '\n' + ), + link=None, + level=3, + num='5.8.2') + +RQ_SRS_006_RBAC_RowPolicy_Restriction = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Restriction', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL restrict all access to a table when a row policy with a condition is created on that table.\n' + 'All users require a permissive row policy in order to view the table.\n' + '\n' + ), + link=None, + level=3, + num='5.8.3') + +RQ_SRS_006_RBAC_RowPolicy_Nesting = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Nesting', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL restrict rows of tables or views created on top of a table with row policies according to those policies.\n' + '\n' + ), + link=None, + level=3, + num='5.8.4') + +RQ_SRS_006_RBAC_RowPolicy_Create = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support creating row policy using the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.1') + +RQ_SRS_006_RBAC_RowPolicy_Create_IfNotExists = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.IfNotExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE ROW POLICY` statement\n' + 'to skip raising an exception if a row policy with the same **name** already exists.\n' + 'If the `IF NOT EXISTS` clause is not specified then an exception SHALL be raised if\n' + 'a row policy with the same **name** already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.2') + +RQ_SRS_006_RBAC_RowPolicy_Create_Replace = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Replace', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE ROW POLICY` statement\n' + 'to replace existing row policy if it already exists.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.3') + +RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying cluster on which to create the role policy\n' + 'using the `ON CLUSTER` clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.4') + +RQ_SRS_006_RBAC_RowPolicy_Create_On = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.On', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying table on which to create the role policy\n' + 'using the `ON` clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.5') + +RQ_SRS_006_RBAC_RowPolicy_Create_Access = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Access', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support allowing or restricting access to rows using the\n' + '`AS` clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.6') + +RQ_SRS_006_RBAC_RowPolicy_Create_Access_Permissive = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Access.Permissive', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support allowing access to rows using the\n' + '`AS PERMISSIVE` clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.7') + +RQ_SRS_006_RBAC_RowPolicy_Create_Access_Restrictive = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Access.Restrictive', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support restricting access to rows using the\n' + '`AS RESTRICTIVE` clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.8') + +RQ_SRS_006_RBAC_RowPolicy_Create_ForSelect = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.ForSelect', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying which rows are affected\n' + 'using the `FOR SELECT` clause in the `CREATE ROW POLICY` statement.\n' + 'REQUIRES CONDITION.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.9') + +RQ_SRS_006_RBAC_RowPolicy_Create_Condition = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Condition', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying a condition that\n' + 'that can be any SQL expression which returns a boolean using the `USING`\n' + 'clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.10') + +RQ_SRS_006_RBAC_RowPolicy_Create_Assignment = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning row policy to one or more users\n' + 'or roles using the `TO` clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.11') + +RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_None = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning row policy to no users or roles using\n' + 'the `TO NONE` clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.12') + +RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_All = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support assigning row policy to all current users and roles\n' + 'using `TO ALL` clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.13') + +RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_AllExcept = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.AllExcept', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support excluding assignment of row policy to one or more users or roles using\n' + 'the `ALL EXCEPT` clause in the `CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.14') + +RQ_SRS_006_RBAC_RowPolicy_Create_Syntax = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Create.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `CRETE ROW POLICY` statement\n' + '\n' + '``` sql\n' + 'CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name [ON CLUSTER cluster_name] ON [db.]table\n' + ' [AS {PERMISSIVE | RESTRICTIVE}]\n' + ' [FOR SELECT]\n' + ' [USING condition]\n' + ' [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.8.5.15') + +RQ_SRS_006_RBAC_RowPolicy_Alter = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering row policy using the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.1') + +RQ_SRS_006_RBAC_RowPolicy_Alter_IfExists = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the `IF EXISTS` clause in the `ALTER ROW POLICY` statement\n' + 'to skip raising an exception if a row policy does not exist.\n' + 'If the `IF EXISTS` clause is not specified then an exception SHALL be raised if\n' + 'a row policy does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.2') + +RQ_SRS_006_RBAC_RowPolicy_Alter_ForSelect = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.ForSelect', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support modifying rows on which to apply the row policy\n' + 'using the `FOR SELECT` clause in the `ALTER ROW POLICY` statement.\n' + 'REQUIRES FUNCTION CONFIRMATION.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.3') + +RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying cluster on which to alter the row policy\n' + 'using the `ON CLUSTER` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.4') + +RQ_SRS_006_RBAC_RowPolicy_Alter_On = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.On', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying table on which to alter the row policy\n' + 'using the `ON` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.5') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Rename = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Rename', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support renaming the row policy using the `RENAME` clause\n' + 'in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.6') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Access = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Access', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support altering access to rows using the\n' + '`AS` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.7') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Permissive = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Permissive', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support permitting access to rows using the\n' + '`AS PERMISSIVE` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.8') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Restrictive = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Restrictive', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support restricting access to rows using the\n' + '`AS RESTRICTIVE` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.9') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Condition = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Condition', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support re-specifying the row policy condition\n' + 'using the `USING` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.10') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Condition_None = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Condition.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support removing the row policy condition\n' + 'using the `USING NONE` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.11') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support reassigning row policy to one or more users\n' + 'or roles using the `TO` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.12') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_None = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support reassigning row policy to no users or roles using\n' + 'the `TO NONE` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.13') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_All = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support reassigning row policy to all current users and roles\n' + 'using the `TO ALL` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.14') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_AllExcept = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.AllExcept', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support excluding assignment of row policy to one or more users or roles using\n' + 'the `ALL EXCEPT` clause in the `ALTER ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.15') + +RQ_SRS_006_RBAC_RowPolicy_Alter_Syntax = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Alter.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `ALTER ROW POLICY` statement\n' + '\n' + '``` sql\n' + 'ALTER [ROW] POLICY [IF EXISTS] name [ON CLUSTER cluster_name] ON [database.]table\n' + ' [RENAME TO new_name]\n' + ' [AS {PERMISSIVE | RESTRICTIVE}]\n' + ' [FOR SELECT]\n' + ' [USING {condition | NONE}][,...]\n' + ' [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.8.6.16') + +RQ_SRS_006_RBAC_RowPolicy_Drop = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support removing one or more row policies using the `DROP ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.7.1') + +RQ_SRS_006_RBAC_RowPolicy_Drop_IfExists = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Drop.IfExists', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support using the `IF EXISTS` clause in the `DROP ROW POLICY` statement\n' + 'to skip raising an exception when the row policy does not exist.\n' + 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' + 'raised if the row policy does not exist.\n' + '\n' + ), + link=None, + level=4, + num='5.8.7.2') + +RQ_SRS_006_RBAC_RowPolicy_Drop_On = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Drop.On', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support removing row policy from one or more specified tables\n' + 'using the `ON` clause in the `DROP ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.7.3') + +RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Drop.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support removing row policy from specified cluster\n' + 'using the `ON CLUSTER` clause in the `DROP ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.7.4') + +RQ_SRS_006_RBAC_RowPolicy_Drop_Syntax = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.Drop.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `DROP ROW POLICY` statement.\n' + '\n' + '``` sql\n' + 'DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...] [ON CLUSTER cluster_name]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.8.7.5') + +RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing the `CREATE ROW POLICY` statement used to create the row policy\n' + 'using the `SHOW CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.8.1') + +RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_On = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.On', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing statement used to create row policy on specific table\n' + 'using the `ON` in the `SHOW CREATE ROW POLICY` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.8.2') + +RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_Syntax = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for `SHOW CREATE ROW POLICY`.\n' + '\n' + '``` sql\n' + 'SHOW CREATE [ROW] POLICY name ON [database.]table\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.8.8.3') + +RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing row policies using the `SHOW ROW POLICIES` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.8.4') + +RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_On = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.On', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support showing row policies on a specific table\n' + 'using the `ON` clause in the `SHOW ROW POLICIES` statement.\n' + '\n' + ), + link=None, + level=4, + num='5.8.8.5') + +RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_Syntax = Requirement( + name='RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for `SHOW ROW POLICIES`.\n' + '\n' + '```sql\n' + 'SHOW [ROW] POLICIES [ON [database.]table]\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.8.8.6') + +RQ_SRS_006_RBAC_SetDefaultRole = Requirement( + name='RQ.SRS-006.RBAC.SetDefaultRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting or changing granted roles to default for one or more\n' + 'users using `SET DEFAULT ROLE` statement which\n' + 'SHALL permanently change the default roles for the user or users if successful.\n' + '\n' + ), + link=None, + level=3, + num='5.9.1') + +RQ_SRS_006_RBAC_SetDefaultRole_CurrentUser = Requirement( + name='RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting or changing granted roles to default for\n' + 'the current user using `CURRENT_USER` clause in the `SET DEFAULT ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.9.2') + +RQ_SRS_006_RBAC_SetDefaultRole_All = Requirement( + name='RQ.SRS-006.RBAC.SetDefaultRole.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting or changing all granted roles to default\n' + 'for one or more users using `ALL` clause in the `SET DEFAULT ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.9.3') + +RQ_SRS_006_RBAC_SetDefaultRole_AllExcept = Requirement( + name='RQ.SRS-006.RBAC.SetDefaultRole.AllExcept', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support setting or changing all granted roles except those specified\n' + 'to default for one or more users using `ALL EXCEPT` clause in the `SET DEFAULT ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.9.4') + +RQ_SRS_006_RBAC_SetDefaultRole_None = Requirement( + name='RQ.SRS-006.RBAC.SetDefaultRole.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support removing all granted roles from default\n' + 'for one or more users using `NONE` clause in the `SET DEFAULT ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.9.5') + +RQ_SRS_006_RBAC_SetDefaultRole_Syntax = Requirement( + name='RQ.SRS-006.RBAC.SetDefaultRole.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `SET DEFAULT ROLE` statement.\n' + '\n' + '```sql\n' + 'SET DEFAULT ROLE\n' + ' {NONE | role [,...] | ALL | ALL EXCEPT role [,...]}\n' + ' TO {user|CURRENT_USER} [,...]\n' + '\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='5.9.6') + +RQ_SRS_006_RBAC_SetRole = Requirement( + name='RQ.SRS-006.RBAC.SetRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support activating role or roles for the current user\n' + 'using `SET ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.10.1') + +RQ_SRS_006_RBAC_SetRole_Default = Requirement( + name='RQ.SRS-006.RBAC.SetRole.Default', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support activating default roles for the current user\n' + 'using `DEFAULT` clause in the `SET ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.10.2') + +RQ_SRS_006_RBAC_SetRole_None = Requirement( + name='RQ.SRS-006.RBAC.SetRole.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support activating no roles for the current user\n' + 'using `NONE` clause in the `SET ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.10.3') + +RQ_SRS_006_RBAC_SetRole_All = Requirement( + name='RQ.SRS-006.RBAC.SetRole.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support activating all roles for the current user\n' + 'using `ALL` clause in the `SET ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.10.4') + +RQ_SRS_006_RBAC_SetRole_AllExcept = Requirement( + name='RQ.SRS-006.RBAC.SetRole.AllExcept', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support activating all roles except those specified\n' + 'for the current user using `ALL EXCEPT` clause in the `SET ROLE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.10.5') + +RQ_SRS_006_RBAC_SetRole_Syntax = Requirement( + name='RQ.SRS-006.RBAC.SetRole.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '```sql\n' + 'SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]}\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='5.10.6') + +RQ_SRS_006_RBAC_Grant_Privilege_To = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.To', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting privileges to one or more users or roles using `TO` clause\n' + 'in the `GRANT PRIVILEGE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.1') + +RQ_SRS_006_RBAC_Grant_Privilege_ToCurrentUser = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting privileges to current user using `TO CURRENT_USER` clause\n' + 'in the `GRANT PRIVILEGE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.2') + +RQ_SRS_006_RBAC_Grant_Privilege_Select = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Select', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **select** privilege to one or more users or roles\n' + 'for a database or a table using the `GRANT SELECT` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.3') + +RQ_SRS_006_RBAC_Grant_Privilege_Insert = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Insert', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **insert** privilege to one or more users or roles\n' + 'for a database or a table using the `GRANT INSERT` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.4') + +RQ_SRS_006_RBAC_Grant_Privilege_Alter = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Alter', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **alter** privilege to one or more users or roles\n' + 'for a database or a table using the `GRANT ALTER` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.5') + +RQ_SRS_006_RBAC_Grant_Privilege_Create = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **create** privilege to one or more users or roles\n' + 'using the `GRANT CREATE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.6') + +RQ_SRS_006_RBAC_Grant_Privilege_Drop = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **drop** privilege to one or more users or roles\n' + 'using the `GRANT DROP` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.7') + +RQ_SRS_006_RBAC_Grant_Privilege_Truncate = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Truncate', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **truncate** privilege to one or more users or roles\n' + 'for a database or a table using `GRANT TRUNCATE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.8') + +RQ_SRS_006_RBAC_Grant_Privilege_Optimize = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Optimize', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **optimize** privilege to one or more users or roles\n' + 'for a database or a table using `GRANT OPTIMIZE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.9') + +RQ_SRS_006_RBAC_Grant_Privilege_Show = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Show', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **show** privilege to one or more users or roles\n' + 'for a database or a table using `GRANT SHOW` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.10') + +RQ_SRS_006_RBAC_Grant_Privilege_KillQuery = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.KillQuery', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **kill query** privilege to one or more users or roles\n' + 'for a database or a table using `GRANT KILL QUERY` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.11') + +RQ_SRS_006_RBAC_Grant_Privilege_AccessManagement = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **access management** privileges to one or more users or roles\n' + 'for a database or a table using `GRANT ACCESS MANAGEMENT` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.12') + +RQ_SRS_006_RBAC_Grant_Privilege_System = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.System', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **system** privileges to one or more users or roles\n' + 'for a database or a table using `GRANT SYSTEM` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.13') + +RQ_SRS_006_RBAC_Grant_Privilege_Introspection = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Introspection', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **introspection** privileges to one or more users or roles\n' + 'for a database or a table using `GRANT INTROSPECTION` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.14') + +RQ_SRS_006_RBAC_Grant_Privilege_Sources = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Sources', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **sources** privileges to one or more users or roles\n' + 'for a database or a table using `GRANT SOURCES` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.15') + +RQ_SRS_006_RBAC_Grant_Privilege_DictGet = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.DictGet', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **dictGet** privilege to one or more users or roles\n' + 'for a database or a table using `GRANT dictGet` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.16') + +RQ_SRS_006_RBAC_Grant_Privilege_None = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting no privileges to one or more users or roles\n' + 'for a database or a table using `GRANT NONE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.17') + +RQ_SRS_006_RBAC_Grant_Privilege_All = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **all** privileges to one or more users or roles\n' + 'using the `GRANT ALL` or `GRANT ALL PRIVILEGES` statements.\n' + '\n' + ), + link=None, + level=3, + num='5.11.18') + +RQ_SRS_006_RBAC_Grant_Privilege_GrantOption = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.GrantOption', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the **grant option** privilege to one or more users or roles\n' + 'for a database or a table using the `WITH GRANT OPTION` clause in the `GRANT` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.19') + +RQ_SRS_006_RBAC_Grant_Privilege_On = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.On', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the `ON` clause in the `GRANT` privilege statement\n' + 'which SHALL allow to specify one or more tables to which the privilege SHALL\n' + 'be granted using the following patterns\n' + '\n' + '* `*.*` any table in any database\n' + '* `database.*` any table in the specified database\n' + '* `database.table` specific table in the specified database\n' + '* `*` any table in the current database\n' + '* `table` specific table in the current database\n' + '\n' + ), + link=None, + level=3, + num='5.11.20') + +RQ_SRS_006_RBAC_Grant_Privilege_PrivilegeColumns = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting the privilege **some_privilege** to one or more users or roles\n' + 'for a database or a table using the `GRANT some_privilege(column)` statement for one column.\n' + 'Multiple columns will be supported with `GRANT some_privilege(column1, column2...)` statement.\n' + 'The privileges will be granted for only the specified columns.\n' + '\n' + ), + link=None, + level=3, + num='5.11.21') + +RQ_SRS_006_RBAC_Grant_Privilege_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying cluster on which to grant privileges using the `ON CLUSTER`\n' + 'clause in the `GRANT PRIVILEGE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.11.22') + +RQ_SRS_006_RBAC_Grant_Privilege_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Grant.Privilege.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `GRANT` statement that\n' + 'grants explicit privileges to a user or a role.\n' + '\n' + '```sql\n' + 'GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...]\n' + ' ON {db.table|db.*|*.*|table|*}\n' + ' TO {user | role | CURRENT_USER} [,...]\n' + ' [WITH GRANT OPTION]\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='5.11.23') + +RQ_SRS_006_RBAC_Revoke_Privilege_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking privileges to one or more users or roles\n' + 'for a database or a table on some specific cluster using the `REVOKE ON CLUSTER cluster_name` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.1') + +RQ_SRS_006_RBAC_Revoke_Privilege_Select = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Select', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **select** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE SELECT` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.2') + +RQ_SRS_006_RBAC_Revoke_Privilege_Insert = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Insert', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **insert** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE INSERT` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.3') + +RQ_SRS_006_RBAC_Revoke_Privilege_Alter = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Alter', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **alter** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE ALTER` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.4') + +RQ_SRS_006_RBAC_Revoke_Privilege_Create = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **create** privilege to one or more users or roles\n' + 'using the `REVOKE CREATE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.5') + +RQ_SRS_006_RBAC_Revoke_Privilege_Drop = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **drop** privilege to one or more users or roles\n' + 'using the `REVOKE DROP` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.6') + +RQ_SRS_006_RBAC_Revoke_Privilege_Truncate = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Truncate', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **truncate** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE TRUNCATE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.7') + +RQ_SRS_006_RBAC_Revoke_Privilege_Optimize = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Optimize', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **optimize** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE OPTIMIZE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.8') + +RQ_SRS_006_RBAC_Revoke_Privilege_Show = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Show', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **show** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE SHOW` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.9') + +RQ_SRS_006_RBAC_Revoke_Privilege_KillQuery = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **kill query** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE KILL QUERY` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.10') + +RQ_SRS_006_RBAC_Revoke_Privilege_AccessManagement = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **access management** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE ACCESS MANAGEMENT` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.11') + +RQ_SRS_006_RBAC_Revoke_Privilege_System = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.System', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **system** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE SYSTEM` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.12') + +RQ_SRS_006_RBAC_Revoke_Privilege_Introspection = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Introspection', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **introspection** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE INTROSPECTION` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.13') + +RQ_SRS_006_RBAC_Revoke_Privilege_Sources = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Sources', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **sources** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE SOURCES` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.14') + +RQ_SRS_006_RBAC_Revoke_Privilege_DictGet = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.DictGet', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the **dictGet** privilege to one or more users or roles\n' + 'for a database or a table using the `REVOKE dictGet` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.15') + +RQ_SRS_006_RBAC_Revoke_Privilege_PrivilegeColumns = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.PrivilegeColumns', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking the privilege **some_privilege** to one or more users or roles\n' + 'for a database or a table using the `REVOKE some_privilege(column)` statement for one column.\n' + 'Multiple columns will be supported with `REVOKE some_privilege(column1, column2...)` statement.\n' + 'The privileges will be revoked for only the specified columns.\n' + '\n' + ), + link=None, + level=3, + num='5.12.16') + +RQ_SRS_006_RBAC_Revoke_Privilege_Multiple = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Multiple', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking MULTIPLE **privileges** to one or more users or roles\n' + 'for a database or a table using the `REVOKE privilege1, privilege2...` statement.\n' + '**privileges** refers to any set of Clickhouse defined privilege, whose hierarchy includes\n' + 'SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE, SHOW, KILL QUERY, ACCESS MANAGEMENT,\n' + 'SYSTEM, INTROSPECTION, SOURCES, dictGet and all of their sub-privileges.\n' + '\n' + ), + link=None, + level=3, + num='5.12.17') + +RQ_SRS_006_RBAC_Revoke_Privilege_All = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **all** privileges to one or more users or roles\n' + 'for a database or a table using the `REVOKE ALL` or `REVOKE ALL PRIVILEGES` statements.\n' + '\n' + ), + link=None, + level=3, + num='5.12.18') + +RQ_SRS_006_RBAC_Revoke_Privilege_None = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **no** privileges to one or more users or roles\n' + 'for a database or a table using the `REVOKE NONE` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.12.19') + +RQ_SRS_006_RBAC_Revoke_Privilege_On = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.On', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the `ON` clause in the `REVOKE` privilege statement\n' + 'which SHALL allow to specify one or more tables to which the privilege SHALL\n' + 'be revoked using the following patterns\n' + '\n' + '* `db.table` specific table in the specified database\n' + '* `db.*` any table in the specified database\n' + '* `*.*` any table in any database\n' + '* `table` specific table in the current database\n' + '* `*` any table in the current database\n' + '\n' + ), + link=None, + level=3, + num='5.12.20') + +RQ_SRS_006_RBAC_Revoke_Privilege_From = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.From', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the `FROM` clause in the `REVOKE` privilege statement\n' + 'which SHALL allow to specify one or more users to which the privilege SHALL\n' + 'be revoked using the following patterns\n' + '\n' + '* `{user | CURRENT_USER} [,...]` some combination of users by name, which may include the current user\n' + '* `ALL` all users\n' + '* `ALL EXCEPT {user | CURRENT_USER} [,...]` the logical reverse of the first pattern\n' + '\n' + ), + link=None, + level=3, + num='5.12.21') + +RQ_SRS_006_RBAC_Revoke_Privilege_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Privilege.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `REVOKE` statement that\n' + 'revokes explicit privileges of a user or a role.\n' + '\n' + '```sql\n' + 'REVOKE [ON CLUSTER cluster_name] privilege\n' + ' [(column_name [,...])] [,...]\n' + ' ON {db.table|db.*|*.*|table|*}\n' + ' FROM {user | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user | CURRENT_USER} [,...]\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='5.12.22') + +RQ_SRS_006_RBAC_Grant_Role = Requirement( + name='RQ.SRS-006.RBAC.Grant.Role', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting one or more roles to\n' + 'one or more users or roles using the `GRANT` role statement.\n' + '\n' + ), + link=None, + level=3, + num='5.13.1') + +RQ_SRS_006_RBAC_Grant_Role_CurrentUser = Requirement( + name='RQ.SRS-006.RBAC.Grant.Role.CurrentUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting one or more roles to current user using\n' + '`TO CURRENT_USER` clause in the `GRANT` role statement.\n' + '\n' + ), + link=None, + level=3, + num='5.13.2') + +RQ_SRS_006_RBAC_Grant_Role_AdminOption = Requirement( + name='RQ.SRS-006.RBAC.Grant.Role.AdminOption', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting `admin option` privilege\n' + 'to one or more users or roles using the `WITH ADMIN OPTION` clause\n' + 'in the `GRANT` role statement.\n' + '\n' + ), + link=None, + level=3, + num='5.13.3') + +RQ_SRS_006_RBAC_Grant_Role_OnCluster = Requirement( + name='RQ.SRS-006.RBAC.Grant.Role.OnCluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support specifying cluster on which the user is to be granted one or more roles\n' + 'using `ON CLUSTER` clause in the `GRANT` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.13.4') + +RQ_SRS_006_RBAC_Grant_Role_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Grant.Role.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for `GRANT` role statement\n' + '\n' + '``` sql\n' + 'GRANT\n' + ' ON CLUSTER cluster_name\n' + ' role [, role ...]\n' + ' TO {user | role | CURRENT_USER} [,...]\n' + ' [WITH ADMIN OPTION]\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='5.13.5') + +RQ_SRS_006_RBAC_Revoke_Role = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Role', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking one or more roles from\n' + 'one or more users or roles using the `REVOKE` role statement.\n' + '\n' + ), + link=None, + level=3, + num='5.14.1') + +RQ_SRS_006_RBAC_Revoke_Role_Keywords = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Role.Keywords', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking one or more roles from\n' + 'special groupings of one or more users or roles with the `ALL`, `ALL EXCEPT`,\n' + 'and `CURRENT_USER` keywords.\n' + '\n' + ), + link=None, + level=3, + num='5.14.2') + +RQ_SRS_006_RBAC_Revoke_Role_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Role.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking one or more roles from\n' + 'one or more users or roles from one or more clusters\n' + 'using the `REVOKE ON CLUSTER` role statement.\n' + '\n' + ), + link=None, + level=3, + num='5.14.3') + +RQ_SRS_006_RBAC_Revoke_AdminOption = Requirement( + name='RQ.SRS-006.RBAC.Revoke.AdminOption', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking `admin option` privilege\n' + 'in one or more users or roles using the `ADMIN OPTION FOR` clause\n' + 'in the `REVOKE` role statement.\n' + '\n' + ), + link=None, + level=3, + num='5.14.4') + +RQ_SRS_006_RBAC_Revoke_Role_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Revoke.Role.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the following syntax for the `REVOKE` role statement\n' + '\n' + '```sql\n' + 'REVOKE [ON CLUSTER cluster_name] [ADMIN OPTION FOR]\n' + ' role [,...]\n' + ' FROM {user | role | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...]\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='5.14.5') + +RQ_SRS_006_RBAC_Show_Grants = Requirement( + name='RQ.SRS-006.RBAC.Show.Grants', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support listing all the privileges granted to current user and role\n' + 'using the `SHOW GRANTS` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.15.1') + +RQ_SRS_006_RBAC_Show_Grants_For = Requirement( + name='RQ.SRS-006.RBAC.Show.Grants.For', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support listing all the privileges granted to a user or a role\n' + 'using the `FOR` clause in the `SHOW GRANTS` statement.\n' + '\n' + ), + link=None, + level=3, + num='5.15.2') + +RQ_SRS_006_RBAC_Show_Grants_Syntax = Requirement( + name='RQ.SRS-006.RBAC.Show.Grants.Syntax', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[Clickhouse] SHALL use the following syntax for the `SHOW GRANTS` statement\n' + '\n' + '``` sql\n' + 'SHOW GRANTS [FOR user_or_role]\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='5.15.3') + +RQ_SRS_006_RBAC_Table_PublicTables = Requirement( + name='RQ.SRS-006.RBAC.Table.PublicTables', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support that a user without any privileges will be able to access the following tables\n' + '\n' + '* system.one\n' + '* system.numbers\n' + '* system.contributors\n' + '* system.functions\n' + '\n' + ), + link=None, + level=3, + num='5.16.1') + +RQ_SRS_006_RBAC_Table_SensitiveTables = Requirement( + name='RQ.SRS-006.RBAC.Table.SensitiveTables', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL not support a user with no privileges accessing the following `system` tables:\n' + '\n' + '* processes\n' + '* query_log\n' + '* query_thread_log\n' + '* clusters\n' + '* events\n' + '* graphite_retentions\n' + '* stack_trace\n' + '* trace_log\n' + '* user_directories\n' + '* zookeeper\n' + '* macros\n' + '\n' + ), + link=None, + level=3, + num='5.16.2') + +RQ_SRS_006_RBAC_DistributedTable_Create = Requirement( + name='RQ.SRS-006.RBAC.DistributedTable.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully `CREATE` a distributed table if and only if\n' + 'the user has **create table** privilege on the table and **remote** privilege on *.*\n' + '\n' + ), + link=None, + level=3, + num='5.17.1') + +RQ_SRS_006_RBAC_DistributedTable_Select = Requirement( + name='RQ.SRS-006.RBAC.DistributedTable.Select', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully `SELECT` from a distributed table if and only if\n' + 'the user has **select** privilege on the table and on the remote table specified in the `CREATE` query of the distributed table.\n' + '\n' + 'Does not require **select** privilege for the remote table if the remote table does not exist on the same server as the user.\n' + '\n' + ), + link=None, + level=3, + num='5.17.2') + +RQ_SRS_006_RBAC_DistributedTable_Insert = Requirement( + name='RQ.SRS-006.RBAC.DistributedTable.Insert', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully `INSERT` into a distributed table if and only if\n' + 'the user has **insert** privilege on the table and on the remote table specified in the `CREATE` query of the distributed table.\n' + '\n' + 'Does not require **insert** privilege for the remote table if the remote table does not exist on the same server as the user,\n' + 'insert executes into the remote table on a different server.\n' + '\n' + ), + link=None, + level=3, + num='5.17.3') + +RQ_SRS_006_RBAC_DistributedTable_SpecialTables = Requirement( + name='RQ.SRS-006.RBAC.DistributedTable.SpecialTables', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute a query using a distributed table that uses one of the special tables if and only if\n' + 'the user has the necessary privileges to interact with that special table, either granted directly or through a role.\n' + 'Special tables include:\n' + '* materialized view\n' + '* distributed table\n' + '* source table of a materialized view\n' + '\n' + ), + link=None, + level=3, + num='5.17.4') + +RQ_SRS_006_RBAC_DistributedTable_LocalUser = Requirement( + name='RQ.SRS-006.RBAC.DistributedTable.LocalUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute a query using a distributed table from\n' + 'a user present locally, but not remotely.\n' + '\n' + ), + link=None, + level=3, + num='5.17.5') + +RQ_SRS_006_RBAC_DistributedTable_SameUserDifferentNodesDifferentPrivileges = Requirement( + name='RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute a query using a distributed table by a user that exists on multiple nodes\n' + 'if and only if the user has the required privileges on the node the query is being executed from.\n' + '\n' + ), + link=None, + level=3, + num='5.17.6') + +RQ_SRS_006_RBAC_View = Requirement( + name='RQ.SRS-006.RBAC.View', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to **create**, **select** and **drop**\n' + 'privileges for a view for users or roles.\n' + '\n' + ), + link=None, + level=4, + num='5.18.1.1') + +RQ_SRS_006_RBAC_View_Create = Requirement( + name='RQ.SRS-006.RBAC.View.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully execute a `CREATE VIEW` command if and only if\n' + 'the user has **create view** privilege either explicitly or through roles.\n' + '\n' + 'If the stored query includes one or more source tables, the user must have **select** privilege\n' + 'on all the source tables either explicitly or through a role.\n' + 'For example,\n' + '```sql\n' + 'CREATE VIEW view AS SELECT * FROM source_table\n' + 'CREATE VIEW view AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' + 'CREATE VIEW view AS SELECT * FROM table0 JOIN table1 USING column\n' + 'CREATE VIEW view AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' + 'CREATE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' + 'CREATE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.18.1.2') + +RQ_SRS_006_RBAC_View_Select = Requirement( + name='RQ.SRS-006.RBAC.View.Select', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully `SELECT` from a view if and only if\n' + 'the user has **select** privilege for that view either explicitly or through a role.\n' + '\n' + 'If the stored query includes one or more source tables, the user must have **select** privilege\n' + 'on all the source tables either explicitly or through a role.\n' + 'For example,\n' + '```sql\n' + 'CREATE VIEW view AS SELECT * FROM source_table\n' + 'CREATE VIEW view AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' + 'CREATE VIEW view AS SELECT * FROM table0 JOIN table1 USING column\n' + 'CREATE VIEW view AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' + 'CREATE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' + 'CREATE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' + '\n' + 'SELECT * FROM view\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.18.1.3') + +RQ_SRS_006_RBAC_View_Drop = Requirement( + name='RQ.SRS-006.RBAC.View.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if\n' + 'the user has **drop view** privilege on that view either explicitly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.18.1.4') + +RQ_SRS_006_RBAC_MaterializedView = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to **create**, **select**, **alter** and **drop**\n' + 'privileges for a materialized view for users or roles.\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.1') + +RQ_SRS_006_RBAC_MaterializedView_Create = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully execute a `CREATE MATERIALIZED VIEW` command if and only if\n' + 'the user has **create view** privilege either explicitly or through roles.\n' + '\n' + 'If `POPULATE` is specified, the user must have `INSERT` privilege on the view,\n' + 'either explicitly or through roles.\n' + 'For example,\n' + '```sql\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory POPULATE AS SELECT * FROM source_table\n' + '```\n' + '\n' + 'If the stored query includes one or more source tables, the user must have **select** privilege\n' + 'on all the source tables either explicitly or through a role.\n' + 'For example,\n' + '```sql\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM source_table\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 JOIN table1 USING column\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' + 'CREATE MATERIALIZED VIEW view0 ENGINE = Memory AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' + '```\n' + '\n' + 'If the materialized view has a target table explicitly declared in the `TO` clause, the user must have\n' + '**insert** and **select** privilege on the target table.\n' + 'For example,\n' + '```sql\n' + 'CREATE MATERIALIZED VIEW view TO target_table AS SELECT * FROM source_table\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.2') + +RQ_SRS_006_RBAC_MaterializedView_Select = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView.Select', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully `SELECT` from a materialized view if and only if\n' + 'the user has **select** privilege for that view either explicitly or through a role.\n' + '\n' + 'If the stored query includes one or more source tables, the user must have **select** privilege\n' + 'on all the source tables either explicitly or through a role.\n' + 'For example,\n' + '```sql\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM source_table\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 JOIN table1 USING column\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' + 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' + 'CREATE MATERIALIZED VIEW view0 ENGINE = Memory AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' + '\n' + 'SELECT * FROM view\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.3') + +RQ_SRS_006_RBAC_MaterializedView_Select_TargetTable = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully `SELECT` from the target table, implicit or explicit, of a materialized view if and only if\n' + 'the user has `SELECT` privilege for the table, either explicitly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.4') + +RQ_SRS_006_RBAC_MaterializedView_Select_SourceTable = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully `SELECT` from the source table of a materialized view if and only if\n' + 'the user has `SELECT` privilege for the table, either explicitly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.5') + +RQ_SRS_006_RBAC_MaterializedView_Drop = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if\n' + 'the user has **drop view** privilege on that view either explicitly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.6') + +RQ_SRS_006_RBAC_MaterializedView_ModifyQuery = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView.ModifyQuery', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully execute a `MODIFY QUERY` command if and only if\n' + 'the user has **modify query** privilege on that view either explicitly or through a role.\n' + '\n' + 'If the new query includes one or more source tables, the user must have **select** privilege\n' + 'on all the source tables either explicitly or through a role.\n' + 'For example,\n' + '```sql\n' + 'ALTER TABLE view MODIFY QUERY SELECT * FROM source_table\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.7') + +RQ_SRS_006_RBAC_MaterializedView_Insert = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView.Insert', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only succesfully `INSERT` into a materialized view if and only if\n' + 'the user has `INSERT` privilege on the view, either explicitly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.8') + +RQ_SRS_006_RBAC_MaterializedView_Insert_SourceTable = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only succesfully `INSERT` into a source table of a materialized view if and only if\n' + 'the user has `INSERT` privilege on the source table, either explicitly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.9') + +RQ_SRS_006_RBAC_MaterializedView_Insert_TargetTable = Requirement( + name='RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only succesfully `INSERT` into a target table of a materialized view if and only if\n' + 'the user has `INSERT` privelege on the target table, either explicitly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.18.2.10') + +RQ_SRS_006_RBAC_LiveView = Requirement( + name='RQ.SRS-006.RBAC.LiveView', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to **create**, **select**, **alter** and **drop**\n' + 'privileges for a live view for users or roles.\n' + '\n' + ), + link=None, + level=4, + num='5.18.3.1') + +RQ_SRS_006_RBAC_LiveView_Create = Requirement( + name='RQ.SRS-006.RBAC.LiveView.Create', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully execute a `CREATE LIVE VIEW` command if and only if\n' + 'the user has **create view** privilege either explicitly or through roles.\n' + '\n' + 'If the stored query includes one or more source tables, the user must have **select** privilege\n' + 'on all the source tables either explicitly or through a role.\n' + 'For example,\n' + '```sql\n' + 'CREATE LIVE VIEW view AS SELECT * FROM source_table\n' + 'CREATE LIVE VIEW view AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' + 'CREATE LIVE VIEW view AS SELECT * FROM table0 JOIN table1 USING column\n' + 'CREATE LIVE VIEW view AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' + 'CREATE LIVE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' + 'CREATE LIVE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.18.3.2') + +RQ_SRS_006_RBAC_LiveView_Select = Requirement( + name='RQ.SRS-006.RBAC.LiveView.Select', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully `SELECT` from a live view if and only if\n' + 'the user has **select** privilege for that view either explicitly or through a role.\n' + '\n' + 'If the stored query includes one or more source tables, the user must have **select** privilege\n' + 'on all the source tables either explicitly or through a role.\n' + 'For example,\n' + '```sql\n' + 'CREATE LIVE VIEW view AS SELECT * FROM source_table\n' + 'CREATE LIVE VIEW view AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' + 'CREATE LIVE VIEW view AS SELECT * FROM table0 JOIN table1 USING column\n' + 'CREATE LIVE VIEW view AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' + 'CREATE LIVE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' + 'CREATE LIVE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' + '\n' + 'SELECT * FROM view\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.18.3.3') + +RQ_SRS_006_RBAC_LiveView_Drop = Requirement( + name='RQ.SRS-006.RBAC.LiveView.Drop', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if\n' + 'the user has **drop view** privilege on that view either explicitly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.18.3.4') + +RQ_SRS_006_RBAC_LiveView_Refresh = Requirement( + name='RQ.SRS-006.RBAC.LiveView.Refresh', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully execute an `ALTER LIVE VIEW REFRESH` command if and only if\n' + 'the user has **refresh** privilege on that view either explicitly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.18.3.5') + +RQ_SRS_006_RBAC_Select = Requirement( + name='RQ.SRS-006.RBAC.Select', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL execute `SELECT` if and only if the user\n' + 'has the **select** privilege for the destination table\n' + 'either because of the explicit grant or through one of the roles assigned to the user.\n' + '\n' + ), + link=None, + level=3, + num='5.19.1') + +RQ_SRS_006_RBAC_Select_Column = Requirement( + name='RQ.SRS-006.RBAC.Select.Column', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **select** privilege\n' + 'for one or more specified columns in a table to one or more **users** or **roles**.\n' + 'Any `SELECT` statements SHALL not to be executed, unless the user\n' + 'has the **select** privilege for the destination column\n' + 'either because of the explicit grant or through one of the roles assigned to the user.\n' + '\n' + ), + link=None, + level=3, + num='5.19.2') + +RQ_SRS_006_RBAC_Select_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Select.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **select** privilege\n' + 'on a specified cluster to one or more **users** or **roles**.\n' + 'Any `SELECT` statements SHALL succeed only on nodes where\n' + 'the table exists and privilege was granted.\n' + '\n' + ), + link=None, + level=3, + num='5.19.3') + +RQ_SRS_006_RBAC_Select_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Select.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **select** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=3, + num='5.19.4') + +RQ_SRS_006_RBAC_Insert = Requirement( + name='RQ.SRS-006.RBAC.Insert', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL execute `INSERT INTO` if and only if the user\n' + 'has the **insert** privilege for the destination table\n' + 'either because of the explicit grant or through one of the roles assigned to the user.\n' + '\n' + ), + link=None, + level=3, + num='5.20.1') + +RQ_SRS_006_RBAC_Insert_Column = Requirement( + name='RQ.SRS-006.RBAC.Insert.Column', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **insert** privilege\n' + 'for one or more specified columns in a table to one or more **users** or **roles**.\n' + 'Any `INSERT INTO` statements SHALL not to be executed, unless the user\n' + 'has the **insert** privilege for the destination column\n' + 'either because of the explicit grant or through one of the roles assigned to the user.\n' + '\n' + ), + link=None, + level=3, + num='5.20.2') + +RQ_SRS_006_RBAC_Insert_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Insert.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **insert** privilege\n' + 'on a specified cluster to one or more **users** or **roles**.\n' + 'Any `INSERT INTO` statements SHALL succeed only on nodes where\n' + 'the table exists and privilege was granted.\n' + '\n' + ), + link=None, + level=3, + num='5.20.3') + +RQ_SRS_006_RBAC_Insert_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Insert.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **insert** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=3, + num='5.20.4') + +RQ_SRS_006_RBAC_Privileges_AlterColumn = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterColumn', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter column** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN` statements SHALL\n' + 'return an error, unless the user has the **alter column** privilege for\n' + 'the destination table either because of the explicit grant or through one of\n' + 'the roles assigned to the user.\n' + '\n' + ), + link=None, + level=4, + num='5.21.1.1') + +RQ_SRS_006_RBAC_Privileges_AlterColumn_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter column** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.1.2') + +RQ_SRS_006_RBAC_Privileges_AlterColumn_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter column** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**\n' + '\n' + ), + link=None, + level=4, + num='5.21.1.3') + +RQ_SRS_006_RBAC_Privileges_AlterColumn_Column = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Column', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **alter column** privilege\n' + 'for one or more specified columns in a table to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN` statements SHALL return an error,\n' + 'unless the user has the **alter column** privilege for the destination column\n' + 'either because of the explicit grant or through one of the roles assigned to the user.\n' + '\n' + ), + link=None, + level=4, + num='5.21.1.4') + +RQ_SRS_006_RBAC_Privileges_AlterColumn_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **alter column** privilege\n' + 'on a specified cluster to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN`\n' + 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' + '\n' + ), + link=None, + level=4, + num='5.21.1.5') + +RQ_SRS_006_RBAC_Privileges_AlterColumn_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter column** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.1.6') + +RQ_SRS_006_RBAC_Privileges_AlterIndex = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterIndex', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter index** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... ORDER BY | ADD|DROP|MATERIALIZE|CLEAR INDEX` statements SHALL\n' + 'return an error, unless the user has the **alter index** privilege for\n' + 'the destination table either because of the explicit grant or through one of\n' + 'the roles assigned to the user.\n' + '\n' + ), + link=None, + level=4, + num='5.21.2.1') + +RQ_SRS_006_RBAC_Privileges_AlterIndex_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter index** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.2.2') + +RQ_SRS_006_RBAC_Privileges_AlterIndex_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter index** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**\n' + '\n' + ), + link=None, + level=4, + num='5.21.2.3') + +RQ_SRS_006_RBAC_Privileges_AlterIndex_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **alter index** privilege\n' + 'on a specified cluster to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... ORDER BY | ADD|DROP|MATERIALIZE|CLEAR INDEX`\n' + 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' + '\n' + ), + link=None, + level=4, + num='5.21.2.4') + +RQ_SRS_006_RBAC_Privileges_AlterIndex_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter index** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.2.5') + +RQ_SRS_006_RBAC_Privileges_AlterConstraint = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterConstraint', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter constraint** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... ADD|CREATE CONSTRAINT` statements SHALL\n' + 'return an error, unless the user has the **alter constraint** privilege for\n' + 'the destination table either because of the explicit grant or through one of\n' + 'the roles assigned to the user.\n' + '\n' + ), + link=None, + level=4, + num='5.21.3.1') + +RQ_SRS_006_RBAC_Privileges_AlterConstraint_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter constraint** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.3.2') + +RQ_SRS_006_RBAC_Privileges_AlterConstraint_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter constraint** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**\n' + '\n' + ), + link=None, + level=4, + num='5.21.3.3') + +RQ_SRS_006_RBAC_Privileges_AlterConstraint_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **alter constraint** privilege\n' + 'on a specified cluster to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... ADD|DROP CONSTRAINT`\n' + 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' + '\n' + ), + link=None, + level=4, + num='5.21.3.4') + +RQ_SRS_006_RBAC_Privileges_AlterConstraint_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter constraint** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.3.5') + +RQ_SRS_006_RBAC_Privileges_AlterTTL = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterTTL', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter ttl** or **alter materialize ttl** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... ALTER TTL | ALTER MATERIALIZE TTL` statements SHALL\n' + 'return an error, unless the user has the **alter ttl** or **alter materialize ttl** privilege for\n' + 'the destination table either because of the explicit grant or through one of\n' + 'the roles assigned to the user.\n' + '\n' + ), + link=None, + level=4, + num='5.21.4.1') + +RQ_SRS_006_RBAC_Privileges_AlterTTL_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter ttl** or **alter materialize ttl** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.4.2') + +RQ_SRS_006_RBAC_Privileges_AlterTTL_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter ttl** or **alter materialize ttl** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**\n' + '\n' + ), + link=None, + level=4, + num='5.21.4.3') + +RQ_SRS_006_RBAC_Privileges_AlterTTL_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **alter ttl** or **alter materialize ttl** privilege\n' + 'on a specified cluster to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... ALTER TTL | ALTER MATERIALIZE TTL`\n' + 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' + '\n' + ), + link=None, + level=4, + num='5.21.4.4') + +RQ_SRS_006_RBAC_Privileges_AlterTTL_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter ttl** or **alter materialize ttl** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.4.5') + +RQ_SRS_006_RBAC_Privileges_AlterSettings = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterSettings', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter settings** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... MODIFY SETTING setting` statements SHALL\n' + 'return an error, unless the user has the **alter settings** privilege for\n' + 'the destination table either because of the explicit grant or through one of\n' + 'the roles assigned to the user. The **alter settings** privilege allows\n' + 'modifying table engine settings. It doesn’t affect settings or server configuration parameters.\n' + '\n' + ), + link=None, + level=4, + num='5.21.5.1') + +RQ_SRS_006_RBAC_Privileges_AlterSettings_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter settings** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.5.2') + +RQ_SRS_006_RBAC_Privileges_AlterSettings_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter settings** privilege\n' + 'for a database or a specific table to one or more **users** or **roles**\n' + '\n' + ), + link=None, + level=4, + num='5.21.5.3') + +RQ_SRS_006_RBAC_Privileges_AlterSettings_Cluster = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking **alter settings** privilege\n' + 'on a specified cluster to one or more **users** or **roles**.\n' + 'Any `ALTER TABLE ... MODIFY SETTING setting`\n' + 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' + '\n' + ), + link=None, + level=4, + num='5.21.5.4') + +RQ_SRS_006_RBAC_Privileges_AlterSettings_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter settings** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.5.5') + +RQ_SRS_006_RBAC_Privileges_AlterUpdate = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterUpdate', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER UPDATE` statement if and only if the user has **alter update** privilege for that column,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.21.6.1') + +RQ_SRS_006_RBAC_Privileges_AlterUpdate_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter update** privilege on a column level\n' + 'to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.6.2') + +RQ_SRS_006_RBAC_Privileges_AlterUpdate_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter update** privilege on a column level\n' + 'from one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.6.3') + +RQ_SRS_006_RBAC_Privileges_AlterUpdate_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter update** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.6.4') + +RQ_SRS_006_RBAC_Privileges_AlterDelete = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterDelete', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER DELETE` statement if and only if the user has **alter delete** privilege for that table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.21.7.1') + +RQ_SRS_006_RBAC_Privileges_AlterDelete_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter delete** privilege on a column level\n' + 'to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.7.2') + +RQ_SRS_006_RBAC_Privileges_AlterDelete_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter delete** privilege on a column level\n' + 'from one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.7.3') + +RQ_SRS_006_RBAC_Privileges_AlterDelete_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter delete** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.7.4') + +RQ_SRS_006_RBAC_Privileges_AlterFreeze = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterFreeze', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER FREEZE` statement if and only if the user has **alter freeze** privilege for that table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.21.8.1') + +RQ_SRS_006_RBAC_Privileges_AlterFreeze_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter freeze** privilege on a column level\n' + 'to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.8.2') + +RQ_SRS_006_RBAC_Privileges_AlterFreeze_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter freeze** privilege on a column level\n' + 'from one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.8.3') + +RQ_SRS_006_RBAC_Privileges_AlterFreeze_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter freeze** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.8.4') + +RQ_SRS_006_RBAC_Privileges_AlterFetch = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterFetch', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER FETCH` statement if and only if the user has **alter fetch** privilege for that table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.21.9.1') + +RQ_SRS_006_RBAC_Privileges_AlterFetch_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter fetch** privilege on a column level\n' + 'to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.9.2') + +RQ_SRS_006_RBAC_Privileges_AlterFetch_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter fetch** privilege on a column level\n' + 'from one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.9.3') + +RQ_SRS_006_RBAC_Privileges_AlterFetch_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter fetch** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.9.4') + +RQ_SRS_006_RBAC_Privileges_AlterMove = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterMove', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER MOVE` statement if and only if the user has **alter move**, **select**, and **alter delete** privilege on the source table\n' + 'and **insert** privilege on the target table, either directly or through a role.\n' + 'For example,\n' + '```sql\n' + 'ALTER TABLE source_table MOVE PARTITION 1 TO target_table\n' + '```\n' + '\n' + ), + link=None, + level=4, + num='5.21.10.1') + +RQ_SRS_006_RBAC_Privileges_AlterMove_Grant = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterMove.Grant', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting **alter move** privilege on a column level\n' + 'to one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.10.2') + +RQ_SRS_006_RBAC_Privileges_AlterMove_Revoke = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support revoking **alter move** privilege on a column level\n' + 'from one or more **users** or **roles**.\n' + '\n' + ), + link=None, + level=4, + num='5.21.10.3') + +RQ_SRS_006_RBAC_Privileges_AlterMove_TableEngines = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support controlling access to the **alter move** privilege\n' + 'on tables created using the following engines\n' + '\n' + '* MergeTree\n' + '* ReplacingMergeTree\n' + '* SummingMergeTree\n' + '* AggregatingMergeTree\n' + '* CollapsingMergeTree\n' + '* VersionedCollapsingMergeTree\n' + '* GraphiteMergeTree\n' + '* ReplicatedMergeTree\n' + '* ReplicatedSummingMergeTree\n' + '* ReplicatedReplacingMergeTree\n' + '* ReplicatedAggregatingMergeTree\n' + '* ReplicatedCollapsingMergeTree\n' + '* ReplicatedVersionedCollapsingMergeTree\n' + '* ReplicatedGraphiteMergeTree\n' + '\n' + ), + link=None, + level=4, + num='5.21.10.4') + +RQ_SRS_006_RBAC_Privileges_CreateTable = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL only successfully execute a `CREATE TABLE` command if and only if\n' + 'the user has **create table** privilege either explicitly or through roles.\n' + '\n' + 'If the stored query includes one or more source tables, the user must have **select** privilege\n' + "on all the source tables and **insert** for the table they're trying to create either explicitly or through a role.\n" + 'For example,\n' + '```sql\n' + 'CREATE TABLE table AS SELECT * FROM source_table\n' + 'CREATE TABLE table AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' + 'CREATE TABLE table AS SELECT * FROM table0 JOIN table1 USING column\n' + 'CREATE TABLE table AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' + 'CREATE TABLE table AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' + 'CREATE TABLE table0 AS SELECT column FROM table1 UNION ALL SELECT column FROM table2\n' + '```\n' + '\n' + ), + link=None, + level=3, + num='5.22.1') + +RQ_SRS_006_RBAC_Privileges_CreateDatabase = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateDatabase', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CREATE DATABASE` statement if and only if the user has **create database** privilege on the database,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.22.2') + +RQ_SRS_006_RBAC_Privileges_CreateDictionary = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateDictionary', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CREATE DICTIONARY` statement if and only if the user has **create dictionary** privilege on the dictionary,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.22.3') + +RQ_SRS_006_RBAC_Privileges_CreateTemporaryTable = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateTemporaryTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CREATE TEMPORARY TABLE` statement if and only if the user has **create temporary table** privilege on the table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.22.4') + +RQ_SRS_006_RBAC_Privileges_AttachDatabase = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AttachDatabase', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ATTACH DATABASE` statement if and only if the user has **create database** privilege on the database,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.23.1') + +RQ_SRS_006_RBAC_Privileges_AttachDictionary = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AttachDictionary', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ATTACH DICTIONARY` statement if and only if the user has **create dictionary** privilege on the dictionary,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.23.2') + +RQ_SRS_006_RBAC_Privileges_AttachTemporaryTable = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AttachTemporaryTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ATTACH TEMPORARY TABLE` statement if and only if the user has **create temporary table** privilege on the table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.23.3') + +RQ_SRS_006_RBAC_Privileges_AttachTable = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AttachTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ATTACH TABLE` statement if and only if the user has **create table** privilege on the table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.23.4') + +RQ_SRS_006_RBAC_Privileges_DropTable = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DropTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DROP TABLE` statement if and only if the user has **drop table** privilege on the table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.24.1') + +RQ_SRS_006_RBAC_Privileges_DropDatabase = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DropDatabase', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DROP DATABASE` statement if and only if the user has **drop database** privilege on the database,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.24.2') + +RQ_SRS_006_RBAC_Privileges_DropDictionary = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DropDictionary', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DROP DICTIONARY` statement if and only if the user has **drop dictionary** privilege on the dictionary,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.24.3') + +RQ_SRS_006_RBAC_Privileges_DetachTable = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DetachTable', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DETACH TABLE` statement if and only if the user has **drop table** privilege on the table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.25.1') + +RQ_SRS_006_RBAC_Privileges_DetachView = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DetachView', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DETACH VIEW` statement if and only if the user has **drop view** privilege on the view,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.25.2') + +RQ_SRS_006_RBAC_Privileges_DetachDatabase = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DetachDatabase', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DETACH DATABASE` statement if and only if the user has **drop database** privilege on the database,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.25.3') + +RQ_SRS_006_RBAC_Privileges_DetachDictionary = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DetachDictionary', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DETACH DICTIONARY` statement if and only if the user has **drop dictionary** privilege on the dictionary,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.25.4') + +RQ_SRS_006_RBAC_Privileges_Truncate = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Truncate', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `TRUNCATE TABLE` statement if and only if the user has **truncate table** privilege on the table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.26.1') + +RQ_SRS_006_RBAC_Privileges_Optimize = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Optimize', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `OPTIMIZE TABLE` statement if and only if the user has **optimize table** privilege on the table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.27.1') + +RQ_SRS_006_RBAC_Privileges_KillQuery = Requirement( + name='RQ.SRS-006.RBAC.Privileges.KillQuery', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `KILL QUERY` statement if and only if the user has **kill query** privilege,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.28.1') + +RQ_SRS_006_RBAC_Privileges_KillMutation = Requirement( + name='RQ.SRS-006.RBAC.Privileges.KillMutation', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `KILL MUTATION` statement if and only if\n' + 'the user has the privilege that created the mutation, either directly or through a role.\n' + 'For example, to `KILL MUTATION` after `ALTER UPDATE` query, the user needs `ALTER UPDATE` privilege.\n' + '\n' + ), + link=None, + level=3, + num='5.29.1') + +RQ_SRS_006_RBAC_Privileges_KillMutation_AlterUpdate = Requirement( + name='RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER UPDATE` mutation if and only if\n' + 'the user has `ALTER UPDATE` privilege on the table where the mutation was created, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.29.2') + +RQ_SRS_006_RBAC_Privileges_KillMutation_AlterDelete = Requirement( + name='RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER DELETE` mutation if and only if\n' + 'the user has `ALTER DELETE` privilege on the table where the mutation was created, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.29.3') + +RQ_SRS_006_RBAC_Privileges_KillMutation_AlterDropColumn = Requirement( + name='RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER DROP COLUMN` mutation if and only if\n' + 'the user has `ALTER DROP COLUMN` privilege on the table where the mutation was created, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.29.4') + +RQ_SRS_006_RBAC_ShowTables_Privilege = Requirement( + name='RQ.SRS-006.RBAC.ShowTables.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL grant **show tables** privilege on a table to a user if that user has recieved any grant,\n' + 'including `SHOW TABLES`, on that table, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.1') + +RQ_SRS_006_RBAC_ShowTables_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW TABLES` statement if and only if the user has **show tables** privilege,\n' + 'or any privilege on the table either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.2') + +RQ_SRS_006_RBAC_ExistsTable_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `EXISTS table` statement if and only if the user has **show tables** privilege,\n' + 'or any privilege on the table either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.3') + +RQ_SRS_006_RBAC_CheckTable_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CHECK table` statement if and only if the user has **show tables** privilege,\n' + 'or any privilege on the table either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.4') + +RQ_SRS_006_RBAC_ShowDatabases_Privilege = Requirement( + name='RQ.SRS-006.RBAC.ShowDatabases.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL grant **show databases** privilege on a database to a user if that user has recieved any grant,\n' + 'including `SHOW DATABASES`, on that table, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.5') + +RQ_SRS_006_RBAC_ShowDatabases_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW DATABASES` statement if and only if the user has **show databases** privilege,\n' + 'or any privilege on the database either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.6') + +RQ_SRS_006_RBAC_ShowCreateDatabase_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW CREATE DATABASE` statement if and only if the user has **show databases** privilege,\n' + 'or any privilege on the database either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.7') + +RQ_SRS_006_RBAC_UseDatabase_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `USE database` statement if and only if the user has **show databases** privilege,\n' + 'or any privilege on the database either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.8') + +RQ_SRS_006_RBAC_ShowColumns_Privilege = Requirement( + name='RQ.SRS-006.RBAC.ShowColumns.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking the `SHOW COLUMNS` privilege.\n' + '\n' + ), + link=None, + level=3, + num='5.30.9') + +RQ_SRS_006_RBAC_ShowCreateTable_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW CREATE TABLE` statement if and only if the user has **show columns** privilege on that table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.10') + +RQ_SRS_006_RBAC_DescribeTable_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DESCRIBE table` statement if and only if the user has **show columns** privilege on that table,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.11') + +RQ_SRS_006_RBAC_ShowDictionaries_Privilege = Requirement( + name='RQ.SRS-006.RBAC.ShowDictionaries.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL grant **show dictionaries** privilege on a dictionary to a user if that user has recieved any grant,\n' + 'including `SHOW DICTIONARIES`, on that dictionary, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.12') + +RQ_SRS_006_RBAC_ShowDictionaries_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW DICTIONARIES` statement if and only if the user has **show dictionaries** privilege,\n' + 'or any privilege on the dictionary either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.13') + +RQ_SRS_006_RBAC_ShowCreateDictionary_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW CREATE DICTIONARY` statement if and only if the user has **show dictionaries** privilege,\n' + 'or any privilege on the dictionary either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.14') + +RQ_SRS_006_RBAC_ExistsDictionary_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `EXISTS dictionary` statement if and only if the user has **show dictionaries** privilege,\n' + 'or any privilege on the dictionary either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.30.15') + +RQ_SRS_006_RBAC_Privileges_CreateUser = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CREATE USER` statement if and only if the user has **create user** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.1') + +RQ_SRS_006_RBAC_Privileges_CreateUser_DefaultRole = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CREATE USER` statement with `DEFAULT ROLE ` clause if and only if\n' + 'the user has **create user** privilege and the role with **admin option**, or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.2') + +RQ_SRS_006_RBAC_Privileges_AlterUser = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER USER` statement if and only if the user has **alter user** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.3') + +RQ_SRS_006_RBAC_Privileges_DropUser = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DropUser', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DROP USER` statement if and only if the user has **drop user** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.4') + +RQ_SRS_006_RBAC_Privileges_CreateRole = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CREATE ROLE` statement if and only if the user has **create role** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.5') + +RQ_SRS_006_RBAC_Privileges_AlterRole = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER ROLE` statement if and only if the user has **alter role** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.6') + +RQ_SRS_006_RBAC_Privileges_DropRole = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DropRole', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DROP ROLE` statement if and only if the user has **drop role** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.7') + +RQ_SRS_006_RBAC_Privileges_CreateRowPolicy = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateRowPolicy', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CREATE ROW POLICY` statement if and only if the user has **create row policy** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.8') + +RQ_SRS_006_RBAC_Privileges_AlterRowPolicy = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterRowPolicy', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER ROW POLICY` statement if and only if the user has **alter row policy** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.9') + +RQ_SRS_006_RBAC_Privileges_DropRowPolicy = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DropRowPolicy', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DROP ROW POLICY` statement if and only if the user has **drop row policy** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.10') + +RQ_SRS_006_RBAC_Privileges_CreateQuota = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateQuota', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CREATE QUOTA` statement if and only if the user has **create quota** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.11') + +RQ_SRS_006_RBAC_Privileges_AlterQuota = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterQuota', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER QUOTA` statement if and only if the user has **alter quota** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.12') + +RQ_SRS_006_RBAC_Privileges_DropQuota = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DropQuota', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DROP QUOTA` statement if and only if the user has **drop quota** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.13') + +RQ_SRS_006_RBAC_Privileges_CreateSettingsProfile = Requirement( + name='RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `CREATE SETTINGS PROFILE` statement if and only if the user has **create settings profile** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.14') + +RQ_SRS_006_RBAC_Privileges_AlterSettingsProfile = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `ALTER SETTINGS PROFILE` statement if and only if the user has **alter settings profile** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.15') + +RQ_SRS_006_RBAC_Privileges_DropSettingsProfile = Requirement( + name='RQ.SRS-006.RBAC.Privileges.DropSettingsProfile', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `DROP SETTINGS PROFILE` statement if and only if the user has **drop settings profile** privilege,\n' + 'or either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.31.16') + +RQ_SRS_006_RBAC_Privileges_RoleAdmin = Requirement( + name='RQ.SRS-006.RBAC.Privileges.RoleAdmin', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute any role grant or revoke by a user with `ROLE ADMIN` privilege.\n' + '\n' + ), + link=None, + level=3, + num='5.31.17') + +RQ_SRS_006_RBAC_ShowUsers_Privilege = Requirement( + name='RQ.SRS-006.RBAC.ShowUsers.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SHOW USERS` privilege when\n' + 'the user is granted `SHOW USERS`, `SHOW CREATE USER`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.1') + +RQ_SRS_006_RBAC_ShowUsers_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW USERS` statement if and only if the user has **show users** privilege,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.2') + +RQ_SRS_006_RBAC_ShowCreateUser_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW CREATE USER` statement if and only if the user has **show users** privilege,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.3') + +RQ_SRS_006_RBAC_ShowRoles_Privilege = Requirement( + name='RQ.SRS-006.RBAC.ShowRoles.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SHOW ROLES` privilege when\n' + 'the user is granted `SHOW ROLES`, `SHOW CREATE ROLE`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.4') + +RQ_SRS_006_RBAC_ShowRoles_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW ROLES` statement if and only if the user has **show roles** privilege,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.5') + +RQ_SRS_006_RBAC_ShowCreateRole_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW CREATE ROLE` statement if and only if the user has **show roles** privilege,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.6') + +RQ_SRS_006_RBAC_ShowRowPolicies_Privilege = Requirement( + name='RQ.SRS-006.RBAC.ShowRowPolicies.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SHOW ROW POLICIES` privilege when\n' + 'the user is granted `SHOW ROW POLICIES`, `SHOW POLICIES`, `SHOW CREATE ROW POLICY`,\n' + '`SHOW CREATE POLICY`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.7') + +RQ_SRS_006_RBAC_ShowRowPolicies_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW ROW POLICIES` or `SHOW POLICIES` statement if and only if\n' + 'the user has **show row policies** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.8') + +RQ_SRS_006_RBAC_ShowCreateRowPolicy_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW CREATE ROW POLICY` or `SHOW CREATE POLICY` statement\n' + 'if and only if the user has **show row policies** privilege,either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.9') + +RQ_SRS_006_RBAC_ShowQuotas_Privilege = Requirement( + name='RQ.SRS-006.RBAC.ShowQuotas.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SHOW QUOTAS` privilege when\n' + 'the user is granted `SHOW QUOTAS`, `SHOW CREATE QUOTA`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.10') + +RQ_SRS_006_RBAC_ShowQuotas_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW QUOTAS` statement if and only if the user has **show quotas** privilege,\n' + 'either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.11') + +RQ_SRS_006_RBAC_ShowCreateQuota_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW CREATE QUOTA` statement if and only if\n' + 'the user has **show quotas** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.12') + +RQ_SRS_006_RBAC_ShowSettingsProfiles_Privilege = Requirement( + name='RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SHOW SETTINGS PROFILES` privilege when\n' + 'the user is granted `SHOW SETTINGS PROFILES`, `SHOW PROFILES`, `SHOW CREATE SETTINGS PROFILE`,\n' + '`SHOW SETTINGS PROFILE`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.13') + +RQ_SRS_006_RBAC_ShowSettingsProfiles_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW SETTINGS PROFILES` or `SHOW PROFILES` statement\n' + 'if and only if the user has **show settings profiles** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.14') + +RQ_SRS_006_RBAC_ShowCreateSettingsProfile_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `SHOW CREATE SETTINGS PROFILE` or `SHOW CREATE PROFILE` statement\n' + 'if and only if the user has **show settings profiles** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=4, + num='5.31.18.15') + +RQ_SRS_006_RBAC_dictGet_Privilege = Requirement( + name='RQ.SRS-006.RBAC.dictGet.Privilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `dictGet` privilege when\n' + 'the user is granted `dictGet`, `dictHas`, `dictGetHierarchy`, or `dictIsIn`.\n' + '\n' + ), + link=None, + level=3, + num='5.32.1') + +RQ_SRS_006_RBAC_dictGet_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.dictGet.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `dictGet` statement\n' + 'if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.32.2') + +RQ_SRS_006_RBAC_dictGet_Type_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `dictGet[TYPE]` statement\n' + 'if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role.\n' + 'Available types:\n' + '\n' + '* Int8\n' + '* Int16\n' + '* Int32\n' + '* Int64\n' + '* UInt8\n' + '* UInt16\n' + '* UInt32\n' + '* UInt64\n' + '* Float32\n' + '* Float64\n' + '* Date\n' + '* DateTime\n' + '* UUID\n' + '* String\n' + '\n' + ), + link=None, + level=3, + num='5.32.3') + +RQ_SRS_006_RBAC_dictGet_OrDefault_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `dictGetOrDefault` statement\n' + 'if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.32.4') + +RQ_SRS_006_RBAC_dictHas_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.dictHas.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `dictHas` statement\n' + 'if and only if the user has **dictGet** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.32.5') + +RQ_SRS_006_RBAC_dictGetHierarchy_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `dictGetHierarchy` statement\n' + 'if and only if the user has **dictGet** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.32.6') + +RQ_SRS_006_RBAC_dictIsIn_RequiredPrivilege = Requirement( + name='RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `dictIsIn` statement\n' + 'if and only if the user has **dictGet** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.32.7') + +RQ_SRS_006_RBAC_Privileges_Introspection = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Introspection', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `INTROSPECTION` privilege when\n' + 'the user is granted `INTROSPECTION` or `INTROSPECTION FUNCTIONS`.\n' + '\n' + ), + link=None, + level=3, + num='5.33.1') + +RQ_SRS_006_RBAC_Privileges_Introspection_addressToLine = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `addressToLine` statement if and only if\n' + 'the user has **introspection** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.33.2') + +RQ_SRS_006_RBAC_Privileges_Introspection_addressToSymbol = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `addressToSymbol` statement if and only if\n' + 'the user has **introspection** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.33.3') + +RQ_SRS_006_RBAC_Privileges_Introspection_demangle = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Introspection.demangle', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `demangle` statement if and only if\n' + 'the user has **introspection** privilege, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.33.4') + +RQ_SRS_006_RBAC_Privileges_System_Shutdown = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Shutdown', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM SHUTDOWN` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM SHUTDOWN`, `SHUTDOWN`,or `SYSTEM KILL`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.1') + +RQ_SRS_006_RBAC_Privileges_System_DropCache = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.DropCache', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM DROP CACHE` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, or `DROP CACHE`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.2') + +RQ_SRS_006_RBAC_Privileges_System_DropCache_DNS = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM DROP DNS CACHE` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP DNS CACHE`,\n' + '`SYSTEM DROP DNS`, `DROP DNS CACHE`, or `DROP DNS`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.3') + +RQ_SRS_006_RBAC_Privileges_System_DropCache_Mark = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM DROP MARK CACHE` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP MARK CACHE`,\n' + '`SYSTEM DROP MARK`, `DROP MARK CACHE`, or `DROP MARKS`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.4') + +RQ_SRS_006_RBAC_Privileges_System_DropCache_Uncompressed = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM DROP UNCOMPRESSED CACHE` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP UNCOMPRESSED CACHE`,\n' + '`SYSTEM DROP UNCOMPRESSED`, `DROP UNCOMPRESSED CACHE`, or `DROP UNCOMPRESSED`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.5') + +RQ_SRS_006_RBAC_Privileges_System_Reload = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Reload', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD` privilege when\n' + 'the user is granted `SYSTEM` or `SYSTEM RELOAD`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.6') + +RQ_SRS_006_RBAC_Privileges_System_Reload_Config = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Reload.Config', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD CONFIG` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD CONFIG`, or `RELOAD CONFIG`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.7') + +RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionary = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD DICTIONARY` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARIES`, `RELOAD DICTIONARIES`, or `RELOAD DICTIONARY`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.8') + +RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionaries = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD DICTIONARIES` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARIES`, `RELOAD DICTIONARIES`, or `RELOAD DICTIONARY`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.9') + +RQ_SRS_006_RBAC_Privileges_System_Reload_EmbeddedDictionaries = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD EMBEDDED DICTIONARIES` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARY ON *.*`, or `SYSTEM RELOAD EMBEDDED DICTIONARIES`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.10') + +RQ_SRS_006_RBAC_Privileges_System_Merges = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Merges', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM MERGES` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM MERGES`, `SYSTEM STOP MERGES`, `SYSTEM START MERGES`, `STOP MERGES`, or `START MERGES`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.11') + +RQ_SRS_006_RBAC_Privileges_System_TTLMerges = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.TTLMerges', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM TTL MERGES` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM TTL MERGES`, `SYSTEM STOP TTL MERGES`, `SYSTEM START TTL MERGES`, `STOP TTL MERGES`, or `START TTL MERGES`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.12') + +RQ_SRS_006_RBAC_Privileges_System_Fetches = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Fetches', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM FETCHES` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM FETCHES`, `SYSTEM STOP FETCHES`, `SYSTEM START FETCHES`, `STOP FETCHES`, or `START FETCHES`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.13') + +RQ_SRS_006_RBAC_Privileges_System_Moves = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Moves', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM MOVES` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM MOVES`, `SYSTEM STOP MOVES`, `SYSTEM START MOVES`, `STOP MOVES`, or `START MOVES`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.14') + +RQ_SRS_006_RBAC_Privileges_System_Sends = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Sends', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM SENDS` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM SENDS`, `SYSTEM STOP SENDS`, `SYSTEM START SENDS`, `STOP SENDS`, or `START SENDS`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.15') + +RQ_SRS_006_RBAC_Privileges_System_Sends_Distributed = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM DISTRIBUTED SENDS` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM DISTRIBUTED SENDS`, `SYSTEM STOP DISTRIBUTED SENDS`,\n' + '`SYSTEM START DISTRIBUTED SENDS`, `STOP DISTRIBUTED SENDS`, or `START DISTRIBUTED SENDS`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.16') + +RQ_SRS_006_RBAC_Privileges_System_Sends_Replicated = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM REPLICATED SENDS` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM REPLICATED SENDS`, `SYSTEM STOP REPLICATED SENDS`,\n' + '`SYSTEM START REPLICATED SENDS`, `STOP REPLICATED SENDS`, or `START REPLICATED SENDS`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.17') + +RQ_SRS_006_RBAC_Privileges_System_ReplicationQueues = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM REPLICATION QUEUES` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM REPLICATION QUEUES`, `SYSTEM STOP REPLICATION QUEUES`,\n' + '`SYSTEM START REPLICATION QUEUES`, `STOP REPLICATION QUEUES`, or `START REPLICATION QUEUES`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.18') + +RQ_SRS_006_RBAC_Privileges_System_SyncReplica = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.SyncReplica', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM SYNC REPLICA` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM SYNC REPLICA`, or `SYNC REPLICA`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.19') + +RQ_SRS_006_RBAC_Privileges_System_RestartReplica = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.RestartReplica', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM RESTART REPLICA` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM RESTART REPLICA`, or `RESTART REPLICA`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.20') + +RQ_SRS_006_RBAC_Privileges_System_Flush = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Flush', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM FLUSH` privilege when\n' + 'the user is granted `SYSTEM` or `SYSTEM FLUSH`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.21') + +RQ_SRS_006_RBAC_Privileges_System_Flush_Distributed = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM FLUSH DISTRIBUTED` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM FLUSH DISTRIBUTED`, or `FLUSH DISTRIBUTED`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.22') + +RQ_SRS_006_RBAC_Privileges_System_Flush_Logs = Requirement( + name='RQ.SRS-006.RBAC.Privileges.System.Flush.Logs', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully grant `SYSTEM FLUSH LOGS` privilege when\n' + 'the user is granted `SYSTEM`, `SYSTEM FLUSH LOGS`, or `FLUSH LOGS`.\n' + '\n' + ), + link=None, + level=3, + num='5.34.23') + +RQ_SRS_006_RBAC_Privileges_Sources = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Sources', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking `SOURCES` privilege from\n' + 'the user, either directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.35.1') + +RQ_SRS_006_RBAC_Privileges_Sources_File = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Sources.File', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the use of `FILE` source by a user if and only if\n' + 'the user has `FILE` or `SOURCES` privileges granted to them directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.35.2') + +RQ_SRS_006_RBAC_Privileges_Sources_URL = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Sources.URL', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the use of `URL` source by a user if and only if\n' + 'the user has `URL` or `SOURCES` privileges granted to them directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.35.3') + +RQ_SRS_006_RBAC_Privileges_Sources_Remote = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Sources.Remote', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the use of `REMOTE` source by a user if and only if\n' + 'the user has `REMOTE` or `SOURCES` privileges granted to them directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.35.4') + +RQ_SRS_006_RBAC_Privileges_Sources_MySQL = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Sources.MySQL', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the use of `MySQL` source by a user if and only if\n' + 'the user has `MySQL` or `SOURCES` privileges granted to them directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.35.5') + +RQ_SRS_006_RBAC_Privileges_Sources_ODBC = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Sources.ODBC', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the use of `ODBC` source by a user if and only if\n' + 'the user has `ODBC` or `SOURCES` privileges granted to them directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.35.6') + +RQ_SRS_006_RBAC_Privileges_Sources_JDBC = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Sources.JDBC', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the use of `JDBC` source by a user if and only if\n' + 'the user has `JDBC` or `SOURCES` privileges granted to them directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.35.7') + +RQ_SRS_006_RBAC_Privileges_Sources_HDFS = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Sources.HDFS', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the use of `HDFS` source by a user if and only if\n' + 'the user has `HDFS` or `SOURCES` privileges granted to them directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.35.8') + +RQ_SRS_006_RBAC_Privileges_Sources_S3 = Requirement( + name='RQ.SRS-006.RBAC.Privileges.Sources.S3', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support the use of `S3` source by a user if and only if\n' + 'the user has `S3` or `SOURCES` privileges granted to them directly or through a role.\n' + '\n' + ), + link=None, + level=3, + num='5.35.9') + +RQ_SRS_006_RBAC_Privileges_GrantOption = Requirement( + name='RQ.SRS-006.RBAC.Privileges.GrantOption', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL successfully execute `GRANT` or `REVOKE` privilege statements by a user if and only if\n' + 'the user has that privilege with `GRANT OPTION`, either directly or through a role.\n' + '\n' + ), + link=None, + level=2, + num='5.36') + +RQ_SRS_006_RBAC_Privileges_All = Requirement( + name='RQ.SRS-006.RBAC.Privileges.All', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking `ALL` privilege\n' + 'using `GRANT ALL ON *.* TO user`.\n' + '\n' + ), + link=None, + level=2, + num='5.37') + +RQ_SRS_006_RBAC_Privileges_RoleAll = Requirement( + name='RQ.SRS-006.RBAC.Privileges.RoleAll', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting a role named `ALL` using `GRANT ALL TO user`.\n' + 'This shall only grant the user the privileges that have been granted to the role.\n' + '\n' + ), + link=None, + level=2, + num='5.38') + +RQ_SRS_006_RBAC_Privileges_None = Requirement( + name='RQ.SRS-006.RBAC.Privileges.None', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support granting or revoking `NONE` privilege\n' + 'using `GRANT NONE TO user` or `GRANT USAGE ON *.* TO user`.\n' + '\n' + ), + link=None, + level=2, + num='5.39') + +RQ_SRS_006_RBAC_Privileges_AdminOption = Requirement( + name='RQ.SRS-006.RBAC.Privileges.AdminOption', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support a user granting or revoking a role if and only if\n' + 'the user has that role with `ADMIN OPTION` privilege.\n' + '\n' + ), + link=None, + level=2, + num='5.40') + SRS_006_ClickHouse_Role_Based_Access_Control = Specification( - name='SRS-006 ClickHouse Role Based Access Control', - description=None, - author=None, - date=None, - status=None, - approved_by=None, - approved_date=None, - approved_version=None, - version=None, - group=None, - type=None, - link=None, - uid=None, - parent=None, - children=None, - content=''' + name='SRS-006 ClickHouse Role Based Access Control', + description=None, + author=None, + date=None, + status=None, + approved_by=None, + approved_date=None, + approved_version=None, + version=None, + group=None, + type=None, + link=None, + uid=None, + parent=None, + children=None, + headings=( + Heading(name='Revision History', level=1, num='1'), + Heading(name='Introduction', level=1, num='2'), + Heading(name='Terminology', level=1, num='3'), + Heading(name='Privilege Definitions', level=1, num='4'), + Heading(name='Requirements', level=1, num='5'), + Heading(name='Generic', level=2, num='5.1'), + Heading(name='RQ.SRS-006.RBAC', level=3, num='5.1.1'), + Heading(name='Login', level=2, num='5.2'), + Heading(name='RQ.SRS-006.RBAC.Login', level=3, num='5.2.1'), + Heading(name='RQ.SRS-006.RBAC.Login.DefaultUser', level=3, num='5.2.2'), + Heading(name='User', level=2, num='5.3'), + Heading(name='RQ.SRS-006.RBAC.User', level=3, num='5.3.1'), + Heading(name='RQ.SRS-006.RBAC.User.Roles', level=3, num='5.3.2'), + Heading(name='RQ.SRS-006.RBAC.User.Privileges', level=3, num='5.3.3'), + Heading(name='RQ.SRS-006.RBAC.User.Variables', level=3, num='5.3.4'), + Heading(name='RQ.SRS-006.RBAC.User.Variables.Constraints', level=3, num='5.3.5'), + Heading(name='RQ.SRS-006.RBAC.User.SettingsProfile', level=3, num='5.3.6'), + Heading(name='RQ.SRS-006.RBAC.User.Quotas', level=3, num='5.3.7'), + Heading(name='RQ.SRS-006.RBAC.User.RowPolicies', level=3, num='5.3.8'), + Heading(name='RQ.SRS-006.RBAC.User.DefaultRole', level=3, num='5.3.9'), + Heading(name='RQ.SRS-006.RBAC.User.RoleSelection', level=3, num='5.3.10'), + Heading(name='RQ.SRS-006.RBAC.User.ShowCreate', level=3, num='5.3.11'), + Heading(name='RQ.SRS-006.RBAC.User.ShowPrivileges', level=3, num='5.3.12'), + Heading(name='RQ.SRS-006.RBAC.User.Use.DefaultRole', level=3, num='5.3.13'), + Heading(name='RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole', level=3, num='5.3.14'), + Heading(name='Create User', level=3, num='5.3.15'), + Heading(name='RQ.SRS-006.RBAC.User.Create', level=4, num='5.3.15.1'), + Heading(name='RQ.SRS-006.RBAC.User.Create.IfNotExists', level=4, num='5.3.15.2'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Replace', level=4, num='5.3.15.3'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.NoPassword', level=4, num='5.3.15.4'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.NoPassword.Login', level=4, num='5.3.15.5'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.PlainText', level=4, num='5.3.15.6'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.PlainText.Login', level=4, num='5.3.15.7'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Password', level=4, num='5.3.15.8'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Password.Login', level=4, num='5.3.15.9'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash', level=4, num='5.3.15.10'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash.Login', level=4, num='5.3.15.11'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password', level=4, num='5.3.15.12'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password.Login', level=4, num='5.3.15.13'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash', level=4, num='5.3.15.14'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash.Login', level=4, num='5.3.15.15'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Host.Name', level=4, num='5.3.15.16'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Host.Regexp', level=4, num='5.3.15.17'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Host.IP', level=4, num='5.3.15.18'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Host.Any', level=4, num='5.3.15.19'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Host.None', level=4, num='5.3.15.20'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Host.Local', level=4, num='5.3.15.21'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Host.Like', level=4, num='5.3.15.22'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Host.Default', level=4, num='5.3.15.23'), + Heading(name='RQ.SRS-006.RBAC.User.Create.DefaultRole', level=4, num='5.3.15.24'), + Heading(name='RQ.SRS-006.RBAC.User.Create.DefaultRole.None', level=4, num='5.3.15.25'), + Heading(name='RQ.SRS-006.RBAC.User.Create.DefaultRole.All', level=4, num='5.3.15.26'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Settings', level=4, num='5.3.15.27'), + Heading(name='RQ.SRS-006.RBAC.User.Create.OnCluster', level=4, num='5.3.15.28'), + Heading(name='RQ.SRS-006.RBAC.User.Create.Syntax', level=4, num='5.3.15.29'), + Heading(name='Alter User', level=3, num='5.3.16'), + Heading(name='RQ.SRS-006.RBAC.User.Alter', level=4, num='5.3.16.1'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.OrderOfEvaluation', level=4, num='5.3.16.2'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.IfExists', level=4, num='5.3.16.3'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Cluster', level=4, num='5.3.16.4'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Rename', level=4, num='5.3.16.5'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Password.PlainText', level=4, num='5.3.16.6'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Password.Sha256Password', level=4, num='5.3.16.7'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Password.DoubleSha1Password', level=4, num='5.3.16.8'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Host.AddDrop', level=4, num='5.3.16.9'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Host.Local', level=4, num='5.3.16.10'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Host.Name', level=4, num='5.3.16.11'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Host.Regexp', level=4, num='5.3.16.12'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Host.IP', level=4, num='5.3.16.13'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Host.Like', level=4, num='5.3.16.14'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Host.Any', level=4, num='5.3.16.15'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Host.None', level=4, num='5.3.16.16'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.DefaultRole', level=4, num='5.3.16.17'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.DefaultRole.All', level=4, num='5.3.16.18'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.DefaultRole.AllExcept', level=4, num='5.3.16.19'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Settings', level=4, num='5.3.16.20'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Settings.Min', level=4, num='5.3.16.21'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Settings.Max', level=4, num='5.3.16.22'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Settings.Profile', level=4, num='5.3.16.23'), + Heading(name='RQ.SRS-006.RBAC.User.Alter.Syntax', level=4, num='5.3.16.24'), + Heading(name='Show Create User', level=3, num='5.3.17'), + Heading(name='RQ.SRS-006.RBAC.User.ShowCreateUser', level=4, num='5.3.17.1'), + Heading(name='RQ.SRS-006.RBAC.User.ShowCreateUser.For', level=4, num='5.3.17.2'), + Heading(name='RQ.SRS-006.RBAC.User.ShowCreateUser.Syntax', level=4, num='5.3.17.3'), + Heading(name='Drop User', level=3, num='5.3.18'), + Heading(name='RQ.SRS-006.RBAC.User.Drop', level=4, num='5.3.18.1'), + Heading(name='RQ.SRS-006.RBAC.User.Drop.IfExists', level=4, num='5.3.18.2'), + Heading(name='RQ.SRS-006.RBAC.User.Drop.OnCluster', level=4, num='5.3.18.3'), + Heading(name='RQ.SRS-006.RBAC.User.Drop.Syntax', level=4, num='5.3.18.4'), + Heading(name='Role', level=2, num='5.4'), + Heading(name='RQ.SRS-006.RBAC.Role', level=3, num='5.4.1'), + Heading(name='RQ.SRS-006.RBAC.Role.Privileges', level=3, num='5.4.2'), + Heading(name='RQ.SRS-006.RBAC.Role.Variables', level=3, num='5.4.3'), + Heading(name='RQ.SRS-006.RBAC.Role.SettingsProfile', level=3, num='5.4.4'), + Heading(name='RQ.SRS-006.RBAC.Role.Quotas', level=3, num='5.4.5'), + Heading(name='RQ.SRS-006.RBAC.Role.RowPolicies', level=3, num='5.4.6'), + Heading(name='Create Role', level=3, num='5.4.7'), + Heading(name='RQ.SRS-006.RBAC.Role.Create', level=4, num='5.4.7.1'), + Heading(name='RQ.SRS-006.RBAC.Role.Create.IfNotExists', level=4, num='5.4.7.2'), + Heading(name='RQ.SRS-006.RBAC.Role.Create.Replace', level=4, num='5.4.7.3'), + Heading(name='RQ.SRS-006.RBAC.Role.Create.Settings', level=4, num='5.4.7.4'), + Heading(name='RQ.SRS-006.RBAC.Role.Create.Syntax', level=4, num='5.4.7.5'), + Heading(name='Alter Role', level=3, num='5.4.8'), + Heading(name='RQ.SRS-006.RBAC.Role.Alter', level=4, num='5.4.8.1'), + Heading(name='RQ.SRS-006.RBAC.Role.Alter.IfExists', level=4, num='5.4.8.2'), + Heading(name='RQ.SRS-006.RBAC.Role.Alter.Cluster', level=4, num='5.4.8.3'), + Heading(name='RQ.SRS-006.RBAC.Role.Alter.Rename', level=4, num='5.4.8.4'), + Heading(name='RQ.SRS-006.RBAC.Role.Alter.Settings', level=4, num='5.4.8.5'), + Heading(name='RQ.SRS-006.RBAC.Role.Alter.Syntax', level=4, num='5.4.8.6'), + Heading(name='Drop Role', level=3, num='5.4.9'), + Heading(name='RQ.SRS-006.RBAC.Role.Drop', level=4, num='5.4.9.1'), + Heading(name='RQ.SRS-006.RBAC.Role.Drop.IfExists', level=4, num='5.4.9.2'), + Heading(name='RQ.SRS-006.RBAC.Role.Drop.Cluster', level=4, num='5.4.9.3'), + Heading(name='RQ.SRS-006.RBAC.Role.Drop.Syntax', level=4, num='5.4.9.4'), + Heading(name='Show Create Role', level=3, num='5.4.10'), + Heading(name='RQ.SRS-006.RBAC.Role.ShowCreate', level=4, num='5.4.10.1'), + Heading(name='RQ.SRS-006.RBAC.Role.ShowCreate.Syntax', level=4, num='5.4.10.2'), + Heading(name='Partial Revokes', level=2, num='5.5'), + Heading(name='RQ.SRS-006.RBAC.PartialRevokes', level=3, num='5.5.1'), + Heading(name='RQ.SRS-006.RBAC.PartialRevoke.Syntax', level=3, num='5.5.2'), + Heading(name='Settings Profile', level=2, num='5.6'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile', level=3, num='5.6.1'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Constraints', level=3, num='5.6.2'), + Heading(name='Create Settings Profile', level=3, num='5.6.3'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create', level=4, num='5.6.3.1'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.IfNotExists', level=4, num='5.6.3.2'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Replace', level=4, num='5.6.3.3'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Variables', level=4, num='5.6.3.4'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Value', level=4, num='5.6.3.5'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Constraints', level=4, num='5.6.3.6'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment', level=4, num='5.6.3.7'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.None', level=4, num='5.6.3.8'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.All', level=4, num='5.6.3.9'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.AllExcept', level=4, num='5.6.3.10'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Inherit', level=4, num='5.6.3.11'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.OnCluster', level=4, num='5.6.3.12'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Create.Syntax', level=4, num='5.6.3.13'), + Heading(name='Alter Settings Profile', level=3, num='5.6.4'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter', level=4, num='5.6.4.1'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.IfExists', level=4, num='5.6.4.2'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Rename', level=4, num='5.6.4.3'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables', level=4, num='5.6.4.4'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Value', level=4, num='5.6.4.5'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Constraints', level=4, num='5.6.4.6'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment', level=4, num='5.6.4.7'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.None', level=4, num='5.6.4.8'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.All', level=4, num='5.6.4.9'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.AllExcept', level=4, num='5.6.4.10'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.Inherit', level=4, num='5.6.4.11'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.OnCluster', level=4, num='5.6.4.12'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Syntax', level=4, num='5.6.4.13'), + Heading(name='Drop Settings Profile', level=3, num='5.6.5'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Drop', level=4, num='5.6.5.1'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Drop.IfExists', level=4, num='5.6.5.2'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Drop.OnCluster', level=4, num='5.6.5.3'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.Drop.Syntax', level=4, num='5.6.5.4'), + Heading(name='Show Create Settings Profile', level=3, num='5.6.6'), + Heading(name='RQ.SRS-006.RBAC.SettingsProfile.ShowCreateSettingsProfile', level=4, num='5.6.6.1'), + Heading(name='Quotas', level=2, num='5.7'), + Heading(name='RQ.SRS-006.RBAC.Quotas', level=3, num='5.7.1'), + Heading(name='RQ.SRS-006.RBAC.Quotas.Keyed', level=3, num='5.7.2'), + Heading(name='RQ.SRS-006.RBAC.Quotas.Queries', level=3, num='5.7.3'), + Heading(name='RQ.SRS-006.RBAC.Quotas.Errors', level=3, num='5.7.4'), + Heading(name='RQ.SRS-006.RBAC.Quotas.ResultRows', level=3, num='5.7.5'), + Heading(name='RQ.SRS-006.RBAC.Quotas.ReadRows', level=3, num='5.7.6'), + Heading(name='RQ.SRS-006.RBAC.Quotas.ResultBytes', level=3, num='5.7.7'), + Heading(name='RQ.SRS-006.RBAC.Quotas.ReadBytes', level=3, num='5.7.8'), + Heading(name='RQ.SRS-006.RBAC.Quotas.ExecutionTime', level=3, num='5.7.9'), + Heading(name='Create Quotas', level=3, num='5.7.10'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create', level=4, num='5.7.10.1'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.IfNotExists', level=4, num='5.7.10.2'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Replace', level=4, num='5.7.10.3'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Cluster', level=4, num='5.7.10.4'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Interval', level=4, num='5.7.10.5'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Interval.Randomized', level=4, num='5.7.10.6'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Queries', level=4, num='5.7.10.7'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Errors', level=4, num='5.7.10.8'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.ResultRows', level=4, num='5.7.10.9'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.ReadRows', level=4, num='5.7.10.10'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.ResultBytes', level=4, num='5.7.10.11'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.ReadBytes', level=4, num='5.7.10.12'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.ExecutionTime', level=4, num='5.7.10.13'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.NoLimits', level=4, num='5.7.10.14'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.TrackingOnly', level=4, num='5.7.10.15'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.KeyedBy', level=4, num='5.7.10.16'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.KeyedByOptions', level=4, num='5.7.10.17'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Assignment', level=4, num='5.7.10.18'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Assignment.None', level=4, num='5.7.10.19'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Assignment.All', level=4, num='5.7.10.20'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Assignment.Except', level=4, num='5.7.10.21'), + Heading(name='RQ.SRS-006.RBAC.Quota.Create.Syntax', level=4, num='5.7.10.22'), + Heading(name='Alter Quota', level=3, num='5.7.11'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter', level=4, num='5.7.11.1'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.IfExists', level=4, num='5.7.11.2'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Rename', level=4, num='5.7.11.3'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Cluster', level=4, num='5.7.11.4'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Interval', level=4, num='5.7.11.5'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Interval.Randomized', level=4, num='5.7.11.6'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Queries', level=4, num='5.7.11.7'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Errors', level=4, num='5.7.11.8'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.ResultRows', level=4, num='5.7.11.9'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.ReadRows', level=4, num='5.7.11.10'), + Heading(name='RQ.SRS-006.RBAC.Quota.ALter.ResultBytes', level=4, num='5.7.11.11'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.ReadBytes', level=4, num='5.7.11.12'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.ExecutionTime', level=4, num='5.7.11.13'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.NoLimits', level=4, num='5.7.11.14'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.TrackingOnly', level=4, num='5.7.11.15'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.KeyedBy', level=4, num='5.7.11.16'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.KeyedByOptions', level=4, num='5.7.11.17'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Assignment', level=4, num='5.7.11.18'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Assignment.None', level=4, num='5.7.11.19'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Assignment.All', level=4, num='5.7.11.20'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Assignment.Except', level=4, num='5.7.11.21'), + Heading(name='RQ.SRS-006.RBAC.Quota.Alter.Syntax', level=4, num='5.7.11.22'), + Heading(name='Drop Quota', level=3, num='5.7.12'), + Heading(name='RQ.SRS-006.RBAC.Quota.Drop', level=4, num='5.7.12.1'), + Heading(name='RQ.SRS-006.RBAC.Quota.Drop.IfExists', level=4, num='5.7.12.2'), + Heading(name='RQ.SRS-006.RBAC.Quota.Drop.Cluster', level=4, num='5.7.12.3'), + Heading(name='RQ.SRS-006.RBAC.Quota.Drop.Syntax', level=4, num='5.7.12.4'), + Heading(name='Show Quotas', level=3, num='5.7.13'), + Heading(name='RQ.SRS-006.RBAC.Quota.ShowQuotas', level=4, num='5.7.13.1'), + Heading(name='RQ.SRS-006.RBAC.Quota.ShowQuotas.IntoOutfile', level=4, num='5.7.13.2'), + Heading(name='RQ.SRS-006.RBAC.Quota.ShowQuotas.Format', level=4, num='5.7.13.3'), + Heading(name='RQ.SRS-006.RBAC.Quota.ShowQuotas.Settings', level=4, num='5.7.13.4'), + Heading(name='RQ.SRS-006.RBAC.Quota.ShowQuotas.Syntax', level=4, num='5.7.13.5'), + Heading(name='Show Create Quota', level=3, num='5.7.14'), + Heading(name='RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Name', level=4, num='5.7.14.1'), + Heading(name='RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Current', level=4, num='5.7.14.2'), + Heading(name='RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Syntax', level=4, num='5.7.14.3'), + Heading(name='Row Policy', level=2, num='5.8'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy', level=3, num='5.8.1'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Condition', level=3, num='5.8.2'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Restriction', level=3, num='5.8.3'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Nesting', level=3, num='5.8.4'), + Heading(name='Create Row Policy', level=3, num='5.8.5'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create', level=4, num='5.8.5.1'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.IfNotExists', level=4, num='5.8.5.2'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Replace', level=4, num='5.8.5.3'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.OnCluster', level=4, num='5.8.5.4'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.On', level=4, num='5.8.5.5'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Access', level=4, num='5.8.5.6'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Access.Permissive', level=4, num='5.8.5.7'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Access.Restrictive', level=4, num='5.8.5.8'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.ForSelect', level=4, num='5.8.5.9'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Condition', level=4, num='5.8.5.10'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment', level=4, num='5.8.5.11'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.None', level=4, num='5.8.5.12'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.All', level=4, num='5.8.5.13'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.AllExcept', level=4, num='5.8.5.14'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Create.Syntax', level=4, num='5.8.5.15'), + Heading(name='Alter Row Policy', level=3, num='5.8.6'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter', level=4, num='5.8.6.1'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.IfExists', level=4, num='5.8.6.2'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.ForSelect', level=4, num='5.8.6.3'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.OnCluster', level=4, num='5.8.6.4'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.On', level=4, num='5.8.6.5'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Rename', level=4, num='5.8.6.6'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Access', level=4, num='5.8.6.7'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Permissive', level=4, num='5.8.6.8'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Restrictive', level=4, num='5.8.6.9'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Condition', level=4, num='5.8.6.10'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Condition.None', level=4, num='5.8.6.11'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment', level=4, num='5.8.6.12'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.None', level=4, num='5.8.6.13'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.All', level=4, num='5.8.6.14'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.AllExcept', level=4, num='5.8.6.15'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Alter.Syntax', level=4, num='5.8.6.16'), + Heading(name='Drop Row Policy', level=3, num='5.8.7'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Drop', level=4, num='5.8.7.1'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Drop.IfExists', level=4, num='5.8.7.2'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Drop.On', level=4, num='5.8.7.3'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Drop.OnCluster', level=4, num='5.8.7.4'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.Drop.Syntax', level=4, num='5.8.7.5'), + Heading(name='Show Create Row Policy', level=3, num='5.8.8'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy', level=4, num='5.8.8.1'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.On', level=4, num='5.8.8.2'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.Syntax', level=4, num='5.8.8.3'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies', level=4, num='5.8.8.4'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.On', level=4, num='5.8.8.5'), + Heading(name='RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.Syntax', level=4, num='5.8.8.6'), + Heading(name='Set Default Role', level=2, num='5.9'), + Heading(name='RQ.SRS-006.RBAC.SetDefaultRole', level=3, num='5.9.1'), + Heading(name='RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser', level=3, num='5.9.2'), + Heading(name='RQ.SRS-006.RBAC.SetDefaultRole.All', level=3, num='5.9.3'), + Heading(name='RQ.SRS-006.RBAC.SetDefaultRole.AllExcept', level=3, num='5.9.4'), + Heading(name='RQ.SRS-006.RBAC.SetDefaultRole.None', level=3, num='5.9.5'), + Heading(name='RQ.SRS-006.RBAC.SetDefaultRole.Syntax', level=3, num='5.9.6'), + Heading(name='Set Role', level=2, num='5.10'), + Heading(name='RQ.SRS-006.RBAC.SetRole', level=3, num='5.10.1'), + Heading(name='RQ.SRS-006.RBAC.SetRole.Default', level=3, num='5.10.2'), + Heading(name='RQ.SRS-006.RBAC.SetRole.None', level=3, num='5.10.3'), + Heading(name='RQ.SRS-006.RBAC.SetRole.All', level=3, num='5.10.4'), + Heading(name='RQ.SRS-006.RBAC.SetRole.AllExcept', level=3, num='5.10.5'), + Heading(name='RQ.SRS-006.RBAC.SetRole.Syntax', level=3, num='5.10.6'), + Heading(name='Grant', level=2, num='5.11'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.To', level=3, num='5.11.1'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser', level=3, num='5.11.2'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Select', level=3, num='5.11.3'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Insert', level=3, num='5.11.4'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Alter', level=3, num='5.11.5'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Create', level=3, num='5.11.6'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Drop', level=3, num='5.11.7'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Truncate', level=3, num='5.11.8'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Optimize', level=3, num='5.11.9'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Show', level=3, num='5.11.10'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.KillQuery', level=3, num='5.11.11'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement', level=3, num='5.11.12'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.System', level=3, num='5.11.13'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Introspection', level=3, num='5.11.14'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Sources', level=3, num='5.11.15'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.DictGet', level=3, num='5.11.16'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.None', level=3, num='5.11.17'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.All', level=3, num='5.11.18'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.GrantOption', level=3, num='5.11.19'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.On', level=3, num='5.11.20'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns', level=3, num='5.11.21'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.OnCluster', level=3, num='5.11.22'), + Heading(name='RQ.SRS-006.RBAC.Grant.Privilege.Syntax', level=3, num='5.11.23'), + Heading(name='Revoke', level=2, num='5.12'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Cluster', level=3, num='5.12.1'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Select', level=3, num='5.12.2'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Insert', level=3, num='5.12.3'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Alter', level=3, num='5.12.4'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Create', level=3, num='5.12.5'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Drop', level=3, num='5.12.6'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Truncate', level=3, num='5.12.7'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Optimize', level=3, num='5.12.8'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Show', level=3, num='5.12.9'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery', level=3, num='5.12.10'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement', level=3, num='5.12.11'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.System', level=3, num='5.12.12'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Introspection', level=3, num='5.12.13'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Sources', level=3, num='5.12.14'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.DictGet', level=3, num='5.12.15'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.PrivilegeColumns', level=3, num='5.12.16'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Multiple', level=3, num='5.12.17'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.All', level=3, num='5.12.18'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.None', level=3, num='5.12.19'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.On', level=3, num='5.12.20'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.From', level=3, num='5.12.21'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Privilege.Syntax', level=3, num='5.12.22'), + Heading(name='Grant Role', level=2, num='5.13'), + Heading(name='RQ.SRS-006.RBAC.Grant.Role', level=3, num='5.13.1'), + Heading(name='RQ.SRS-006.RBAC.Grant.Role.CurrentUser', level=3, num='5.13.2'), + Heading(name='RQ.SRS-006.RBAC.Grant.Role.AdminOption', level=3, num='5.13.3'), + Heading(name='RQ.SRS-006.RBAC.Grant.Role.OnCluster', level=3, num='5.13.4'), + Heading(name='RQ.SRS-006.RBAC.Grant.Role.Syntax', level=3, num='5.13.5'), + Heading(name='Revoke Role', level=2, num='5.14'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Role', level=3, num='5.14.1'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Role.Keywords', level=3, num='5.14.2'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Role.Cluster', level=3, num='5.14.3'), + Heading(name='RQ.SRS-006.RBAC.Revoke.AdminOption', level=3, num='5.14.4'), + Heading(name='RQ.SRS-006.RBAC.Revoke.Role.Syntax', level=3, num='5.14.5'), + Heading(name='Show Grants', level=2, num='5.15'), + Heading(name='RQ.SRS-006.RBAC.Show.Grants', level=3, num='5.15.1'), + Heading(name='RQ.SRS-006.RBAC.Show.Grants.For', level=3, num='5.15.2'), + Heading(name='RQ.SRS-006.RBAC.Show.Grants.Syntax', level=3, num='5.15.3'), + Heading(name='Table Privileges', level=2, num='5.16'), + Heading(name='RQ.SRS-006.RBAC.Table.PublicTables', level=3, num='5.16.1'), + Heading(name='RQ.SRS-006.RBAC.Table.SensitiveTables', level=3, num='5.16.2'), + Heading(name='Distributed Tables', level=2, num='5.17'), + Heading(name='RQ.SRS-006.RBAC.DistributedTable.Create', level=3, num='5.17.1'), + Heading(name='RQ.SRS-006.RBAC.DistributedTable.Select', level=3, num='5.17.2'), + Heading(name='RQ.SRS-006.RBAC.DistributedTable.Insert', level=3, num='5.17.3'), + Heading(name='RQ.SRS-006.RBAC.DistributedTable.SpecialTables', level=3, num='5.17.4'), + Heading(name='RQ.SRS-006.RBAC.DistributedTable.LocalUser', level=3, num='5.17.5'), + Heading(name='RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges', level=3, num='5.17.6'), + Heading(name='Views', level=2, num='5.18'), + Heading(name='View', level=3, num='5.18.1'), + Heading(name='RQ.SRS-006.RBAC.View', level=4, num='5.18.1.1'), + Heading(name='RQ.SRS-006.RBAC.View.Create', level=4, num='5.18.1.2'), + Heading(name='RQ.SRS-006.RBAC.View.Select', level=4, num='5.18.1.3'), + Heading(name='RQ.SRS-006.RBAC.View.Drop', level=4, num='5.18.1.4'), + Heading(name='Materialized View', level=3, num='5.18.2'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView', level=4, num='5.18.2.1'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView.Create', level=4, num='5.18.2.2'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView.Select', level=4, num='5.18.2.3'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable', level=4, num='5.18.2.4'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable', level=4, num='5.18.2.5'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView.Drop', level=4, num='5.18.2.6'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView.ModifyQuery', level=4, num='5.18.2.7'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView.Insert', level=4, num='5.18.2.8'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable', level=4, num='5.18.2.9'), + Heading(name='RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable', level=4, num='5.18.2.10'), + Heading(name='Live View', level=3, num='5.18.3'), + Heading(name='RQ.SRS-006.RBAC.LiveView', level=4, num='5.18.3.1'), + Heading(name='RQ.SRS-006.RBAC.LiveView.Create', level=4, num='5.18.3.2'), + Heading(name='RQ.SRS-006.RBAC.LiveView.Select', level=4, num='5.18.3.3'), + Heading(name='RQ.SRS-006.RBAC.LiveView.Drop', level=4, num='5.18.3.4'), + Heading(name='RQ.SRS-006.RBAC.LiveView.Refresh', level=4, num='5.18.3.5'), + Heading(name='Select', level=2, num='5.19'), + Heading(name='RQ.SRS-006.RBAC.Select', level=3, num='5.19.1'), + Heading(name='RQ.SRS-006.RBAC.Select.Column', level=3, num='5.19.2'), + Heading(name='RQ.SRS-006.RBAC.Select.Cluster', level=3, num='5.19.3'), + Heading(name='RQ.SRS-006.RBAC.Select.TableEngines', level=3, num='5.19.4'), + Heading(name='Insert', level=2, num='5.20'), + Heading(name='RQ.SRS-006.RBAC.Insert', level=3, num='5.20.1'), + Heading(name='RQ.SRS-006.RBAC.Insert.Column', level=3, num='5.20.2'), + Heading(name='RQ.SRS-006.RBAC.Insert.Cluster', level=3, num='5.20.3'), + Heading(name='RQ.SRS-006.RBAC.Insert.TableEngines', level=3, num='5.20.4'), + Heading(name='Alter', level=2, num='5.21'), + Heading(name='Alter Column', level=3, num='5.21.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterColumn', level=4, num='5.21.1.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant', level=4, num='5.21.1.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke', level=4, num='5.21.1.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Column', level=4, num='5.21.1.4'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster', level=4, num='5.21.1.5'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines', level=4, num='5.21.1.6'), + Heading(name='Alter Index', level=3, num='5.21.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterIndex', level=4, num='5.21.2.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant', level=4, num='5.21.2.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke', level=4, num='5.21.2.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster', level=4, num='5.21.2.4'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines', level=4, num='5.21.2.5'), + Heading(name='Alter Constraint', level=3, num='5.21.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterConstraint', level=4, num='5.21.3.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant', level=4, num='5.21.3.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke', level=4, num='5.21.3.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster', level=4, num='5.21.3.4'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines', level=4, num='5.21.3.5'), + Heading(name='Alter TTL', level=3, num='5.21.4'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterTTL', level=4, num='5.21.4.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant', level=4, num='5.21.4.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke', level=4, num='5.21.4.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster', level=4, num='5.21.4.4'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines', level=4, num='5.21.4.5'), + Heading(name='Alter Settings', level=3, num='5.21.5'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterSettings', level=4, num='5.21.5.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant', level=4, num='5.21.5.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke', level=4, num='5.21.5.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster', level=4, num='5.21.5.4'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines', level=4, num='5.21.5.5'), + Heading(name='Alter Update', level=3, num='5.21.6'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterUpdate', level=4, num='5.21.6.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant', level=4, num='5.21.6.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke', level=4, num='5.21.6.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines', level=4, num='5.21.6.4'), + Heading(name='Alter Delete', level=3, num='5.21.7'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterDelete', level=4, num='5.21.7.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant', level=4, num='5.21.7.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke', level=4, num='5.21.7.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines', level=4, num='5.21.7.4'), + Heading(name='Alter Freeze Partition', level=3, num='5.21.8'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterFreeze', level=4, num='5.21.8.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant', level=4, num='5.21.8.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke', level=4, num='5.21.8.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines', level=4, num='5.21.8.4'), + Heading(name='Alter Fetch Partition', level=3, num='5.21.9'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterFetch', level=4, num='5.21.9.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant', level=4, num='5.21.9.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke', level=4, num='5.21.9.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines', level=4, num='5.21.9.4'), + Heading(name='Alter Move Partition', level=3, num='5.21.10'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterMove', level=4, num='5.21.10.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterMove.Grant', level=4, num='5.21.10.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke', level=4, num='5.21.10.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines', level=4, num='5.21.10.4'), + Heading(name='Create', level=2, num='5.22'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateTable', level=3, num='5.22.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateDatabase', level=3, num='5.22.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateDictionary', level=3, num='5.22.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateTemporaryTable', level=3, num='5.22.4'), + Heading(name='Attach', level=2, num='5.23'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AttachDatabase', level=3, num='5.23.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AttachDictionary', level=3, num='5.23.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AttachTemporaryTable', level=3, num='5.23.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AttachTable', level=3, num='5.23.4'), + Heading(name='Drop', level=2, num='5.24'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DropTable', level=3, num='5.24.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DropDatabase', level=3, num='5.24.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DropDictionary', level=3, num='5.24.3'), + Heading(name='Detach', level=2, num='5.25'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DetachTable', level=3, num='5.25.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DetachView', level=3, num='5.25.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DetachDatabase', level=3, num='5.25.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DetachDictionary', level=3, num='5.25.4'), + Heading(name='Truncate', level=2, num='5.26'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Truncate', level=3, num='5.26.1'), + Heading(name='Optimize', level=2, num='5.27'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Optimize', level=3, num='5.27.1'), + Heading(name='Kill Query', level=2, num='5.28'), + Heading(name='RQ.SRS-006.RBAC.Privileges.KillQuery', level=3, num='5.28.1'), + Heading(name='Kill Mutation', level=2, num='5.29'), + Heading(name='RQ.SRS-006.RBAC.Privileges.KillMutation', level=3, num='5.29.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate', level=3, num='5.29.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete', level=3, num='5.29.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn', level=3, num='5.29.4'), + Heading(name='Show', level=2, num='5.30'), + Heading(name='RQ.SRS-006.RBAC.ShowTables.Privilege', level=3, num='5.30.1'), + Heading(name='RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege', level=3, num='5.30.2'), + Heading(name='RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege', level=3, num='5.30.3'), + Heading(name='RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege', level=3, num='5.30.4'), + Heading(name='RQ.SRS-006.RBAC.ShowDatabases.Privilege', level=3, num='5.30.5'), + Heading(name='RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege', level=3, num='5.30.6'), + Heading(name='RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege', level=3, num='5.30.7'), + Heading(name='RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege', level=3, num='5.30.8'), + Heading(name='RQ.SRS-006.RBAC.ShowColumns.Privilege', level=3, num='5.30.9'), + Heading(name='RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege', level=3, num='5.30.10'), + Heading(name='RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege', level=3, num='5.30.11'), + Heading(name='RQ.SRS-006.RBAC.ShowDictionaries.Privilege', level=3, num='5.30.12'), + Heading(name='RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege', level=3, num='5.30.13'), + Heading(name='RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege', level=3, num='5.30.14'), + Heading(name='RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege', level=3, num='5.30.15'), + Heading(name='Access Management', level=2, num='5.31'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateUser', level=3, num='5.31.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole', level=3, num='5.31.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterUser', level=3, num='5.31.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DropUser', level=3, num='5.31.4'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateRole', level=3, num='5.31.5'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterRole', level=3, num='5.31.6'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DropRole', level=3, num='5.31.7'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateRowPolicy', level=3, num='5.31.8'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterRowPolicy', level=3, num='5.31.9'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DropRowPolicy', level=3, num='5.31.10'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateQuota', level=3, num='5.31.11'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterQuota', level=3, num='5.31.12'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DropQuota', level=3, num='5.31.13'), + Heading(name='RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile', level=3, num='5.31.14'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile', level=3, num='5.31.15'), + Heading(name='RQ.SRS-006.RBAC.Privileges.DropSettingsProfile', level=3, num='5.31.16'), + Heading(name='RQ.SRS-006.RBAC.Privileges.RoleAdmin', level=3, num='5.31.17'), + Heading(name='Show Access', level=3, num='5.31.18'), + Heading(name='RQ.SRS-006.RBAC.ShowUsers.Privilege', level=4, num='5.31.18.1'), + Heading(name='RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege', level=4, num='5.31.18.2'), + Heading(name='RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege', level=4, num='5.31.18.3'), + Heading(name='RQ.SRS-006.RBAC.ShowRoles.Privilege', level=4, num='5.31.18.4'), + Heading(name='RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege', level=4, num='5.31.18.5'), + Heading(name='RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege', level=4, num='5.31.18.6'), + Heading(name='RQ.SRS-006.RBAC.ShowRowPolicies.Privilege', level=4, num='5.31.18.7'), + Heading(name='RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege', level=4, num='5.31.18.8'), + Heading(name='RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege', level=4, num='5.31.18.9'), + Heading(name='RQ.SRS-006.RBAC.ShowQuotas.Privilege', level=4, num='5.31.18.10'), + Heading(name='RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege', level=4, num='5.31.18.11'), + Heading(name='RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege', level=4, num='5.31.18.12'), + Heading(name='RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege', level=4, num='5.31.18.13'), + Heading(name='RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege', level=4, num='5.31.18.14'), + Heading(name='RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege', level=4, num='5.31.18.15'), + Heading(name='dictGet', level=2, num='5.32'), + Heading(name='RQ.SRS-006.RBAC.dictGet.Privilege', level=3, num='5.32.1'), + Heading(name='RQ.SRS-006.RBAC.dictGet.RequiredPrivilege', level=3, num='5.32.2'), + Heading(name='RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege', level=3, num='5.32.3'), + Heading(name='RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege', level=3, num='5.32.4'), + Heading(name='RQ.SRS-006.RBAC.dictHas.RequiredPrivilege', level=3, num='5.32.5'), + Heading(name='RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege', level=3, num='5.32.6'), + Heading(name='RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege', level=3, num='5.32.7'), + Heading(name='Introspection', level=2, num='5.33'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Introspection', level=3, num='5.33.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine', level=3, num='5.33.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol', level=3, num='5.33.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Introspection.demangle', level=3, num='5.33.4'), + Heading(name='System', level=2, num='5.34'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Shutdown', level=3, num='5.34.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.DropCache', level=3, num='5.34.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS', level=3, num='5.34.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark', level=3, num='5.34.4'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed', level=3, num='5.34.5'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Reload', level=3, num='5.34.6'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Reload.Config', level=3, num='5.34.7'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary', level=3, num='5.34.8'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries', level=3, num='5.34.9'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries', level=3, num='5.34.10'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Merges', level=3, num='5.34.11'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.TTLMerges', level=3, num='5.34.12'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Fetches', level=3, num='5.34.13'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Moves', level=3, num='5.34.14'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Sends', level=3, num='5.34.15'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed', level=3, num='5.34.16'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated', level=3, num='5.34.17'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues', level=3, num='5.34.18'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.SyncReplica', level=3, num='5.34.19'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.RestartReplica', level=3, num='5.34.20'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Flush', level=3, num='5.34.21'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed', level=3, num='5.34.22'), + Heading(name='RQ.SRS-006.RBAC.Privileges.System.Flush.Logs', level=3, num='5.34.23'), + Heading(name='Sources', level=2, num='5.35'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Sources', level=3, num='5.35.1'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Sources.File', level=3, num='5.35.2'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Sources.URL', level=3, num='5.35.3'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Sources.Remote', level=3, num='5.35.4'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Sources.MySQL', level=3, num='5.35.5'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Sources.ODBC', level=3, num='5.35.6'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Sources.JDBC', level=3, num='5.35.7'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Sources.HDFS', level=3, num='5.35.8'), + Heading(name='RQ.SRS-006.RBAC.Privileges.Sources.S3', level=3, num='5.35.9'), + Heading(name='RQ.SRS-006.RBAC.Privileges.GrantOption', level=2, num='5.36'), + Heading(name='RQ.SRS-006.RBAC.Privileges.All', level=2, num='5.37'), + Heading(name='RQ.SRS-006.RBAC.Privileges.RoleAll', level=2, num='5.38'), + Heading(name='RQ.SRS-006.RBAC.Privileges.None', level=2, num='5.39'), + Heading(name='RQ.SRS-006.RBAC.Privileges.AdminOption', level=2, num='5.40'), + Heading(name='References', level=1, num='6'), + ), + requirements=( + RQ_SRS_006_RBAC, + RQ_SRS_006_RBAC_Login, + RQ_SRS_006_RBAC_Login_DefaultUser, + RQ_SRS_006_RBAC_User, + RQ_SRS_006_RBAC_User_Roles, + RQ_SRS_006_RBAC_User_Privileges, + RQ_SRS_006_RBAC_User_Variables, + RQ_SRS_006_RBAC_User_Variables_Constraints, + RQ_SRS_006_RBAC_User_SettingsProfile, + RQ_SRS_006_RBAC_User_Quotas, + RQ_SRS_006_RBAC_User_RowPolicies, + RQ_SRS_006_RBAC_User_DefaultRole, + RQ_SRS_006_RBAC_User_RoleSelection, + RQ_SRS_006_RBAC_User_ShowCreate, + RQ_SRS_006_RBAC_User_ShowPrivileges, + RQ_SRS_006_RBAC_User_Use_DefaultRole, + RQ_SRS_006_RBAC_User_Use_AllRolesWhenNoDefaultRole, + RQ_SRS_006_RBAC_User_Create, + RQ_SRS_006_RBAC_User_Create_IfNotExists, + RQ_SRS_006_RBAC_User_Create_Replace, + RQ_SRS_006_RBAC_User_Create_Password_NoPassword, + RQ_SRS_006_RBAC_User_Create_Password_NoPassword_Login, + RQ_SRS_006_RBAC_User_Create_Password_PlainText, + RQ_SRS_006_RBAC_User_Create_Password_PlainText_Login, + RQ_SRS_006_RBAC_User_Create_Password_Sha256Password, + RQ_SRS_006_RBAC_User_Create_Password_Sha256Password_Login, + RQ_SRS_006_RBAC_User_Create_Password_Sha256Hash, + RQ_SRS_006_RBAC_User_Create_Password_Sha256Hash_Login, + RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Password, + RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Password_Login, + RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Hash, + RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Hash_Login, + RQ_SRS_006_RBAC_User_Create_Host_Name, + RQ_SRS_006_RBAC_User_Create_Host_Regexp, + RQ_SRS_006_RBAC_User_Create_Host_IP, + RQ_SRS_006_RBAC_User_Create_Host_Any, + RQ_SRS_006_RBAC_User_Create_Host_None, + RQ_SRS_006_RBAC_User_Create_Host_Local, + RQ_SRS_006_RBAC_User_Create_Host_Like, + RQ_SRS_006_RBAC_User_Create_Host_Default, + RQ_SRS_006_RBAC_User_Create_DefaultRole, + RQ_SRS_006_RBAC_User_Create_DefaultRole_None, + RQ_SRS_006_RBAC_User_Create_DefaultRole_All, + RQ_SRS_006_RBAC_User_Create_Settings, + RQ_SRS_006_RBAC_User_Create_OnCluster, + RQ_SRS_006_RBAC_User_Create_Syntax, + RQ_SRS_006_RBAC_User_Alter, + RQ_SRS_006_RBAC_User_Alter_OrderOfEvaluation, + RQ_SRS_006_RBAC_User_Alter_IfExists, + RQ_SRS_006_RBAC_User_Alter_Cluster, + RQ_SRS_006_RBAC_User_Alter_Rename, + RQ_SRS_006_RBAC_User_Alter_Password_PlainText, + RQ_SRS_006_RBAC_User_Alter_Password_Sha256Password, + RQ_SRS_006_RBAC_User_Alter_Password_DoubleSha1Password, + RQ_SRS_006_RBAC_User_Alter_Host_AddDrop, + RQ_SRS_006_RBAC_User_Alter_Host_Local, + RQ_SRS_006_RBAC_User_Alter_Host_Name, + RQ_SRS_006_RBAC_User_Alter_Host_Regexp, + RQ_SRS_006_RBAC_User_Alter_Host_IP, + RQ_SRS_006_RBAC_User_Alter_Host_Like, + RQ_SRS_006_RBAC_User_Alter_Host_Any, + RQ_SRS_006_RBAC_User_Alter_Host_None, + RQ_SRS_006_RBAC_User_Alter_DefaultRole, + RQ_SRS_006_RBAC_User_Alter_DefaultRole_All, + RQ_SRS_006_RBAC_User_Alter_DefaultRole_AllExcept, + RQ_SRS_006_RBAC_User_Alter_Settings, + RQ_SRS_006_RBAC_User_Alter_Settings_Min, + RQ_SRS_006_RBAC_User_Alter_Settings_Max, + RQ_SRS_006_RBAC_User_Alter_Settings_Profile, + RQ_SRS_006_RBAC_User_Alter_Syntax, + RQ_SRS_006_RBAC_User_ShowCreateUser, + RQ_SRS_006_RBAC_User_ShowCreateUser_For, + RQ_SRS_006_RBAC_User_ShowCreateUser_Syntax, + RQ_SRS_006_RBAC_User_Drop, + RQ_SRS_006_RBAC_User_Drop_IfExists, + RQ_SRS_006_RBAC_User_Drop_OnCluster, + RQ_SRS_006_RBAC_User_Drop_Syntax, + RQ_SRS_006_RBAC_Role, + RQ_SRS_006_RBAC_Role_Privileges, + RQ_SRS_006_RBAC_Role_Variables, + RQ_SRS_006_RBAC_Role_SettingsProfile, + RQ_SRS_006_RBAC_Role_Quotas, + RQ_SRS_006_RBAC_Role_RowPolicies, + RQ_SRS_006_RBAC_Role_Create, + RQ_SRS_006_RBAC_Role_Create_IfNotExists, + RQ_SRS_006_RBAC_Role_Create_Replace, + RQ_SRS_006_RBAC_Role_Create_Settings, + RQ_SRS_006_RBAC_Role_Create_Syntax, + RQ_SRS_006_RBAC_Role_Alter, + RQ_SRS_006_RBAC_Role_Alter_IfExists, + RQ_SRS_006_RBAC_Role_Alter_Cluster, + RQ_SRS_006_RBAC_Role_Alter_Rename, + RQ_SRS_006_RBAC_Role_Alter_Settings, + RQ_SRS_006_RBAC_Role_Alter_Syntax, + RQ_SRS_006_RBAC_Role_Drop, + RQ_SRS_006_RBAC_Role_Drop_IfExists, + RQ_SRS_006_RBAC_Role_Drop_Cluster, + RQ_SRS_006_RBAC_Role_Drop_Syntax, + RQ_SRS_006_RBAC_Role_ShowCreate, + RQ_SRS_006_RBAC_Role_ShowCreate_Syntax, + RQ_SRS_006_RBAC_PartialRevokes, + RQ_SRS_006_RBAC_PartialRevoke_Syntax, + RQ_SRS_006_RBAC_SettingsProfile, + RQ_SRS_006_RBAC_SettingsProfile_Constraints, + RQ_SRS_006_RBAC_SettingsProfile_Create, + RQ_SRS_006_RBAC_SettingsProfile_Create_IfNotExists, + RQ_SRS_006_RBAC_SettingsProfile_Create_Replace, + RQ_SRS_006_RBAC_SettingsProfile_Create_Variables, + RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Value, + RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints, + RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment, + RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_None, + RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_All, + RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_AllExcept, + RQ_SRS_006_RBAC_SettingsProfile_Create_Inherit, + RQ_SRS_006_RBAC_SettingsProfile_Create_OnCluster, + RQ_SRS_006_RBAC_SettingsProfile_Create_Syntax, + RQ_SRS_006_RBAC_SettingsProfile_Alter, + RQ_SRS_006_RBAC_SettingsProfile_Alter_IfExists, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Rename, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_None, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_All, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_AllExcept, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_Inherit, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_OnCluster, + RQ_SRS_006_RBAC_SettingsProfile_Alter_Syntax, + RQ_SRS_006_RBAC_SettingsProfile_Drop, + RQ_SRS_006_RBAC_SettingsProfile_Drop_IfExists, + RQ_SRS_006_RBAC_SettingsProfile_Drop_OnCluster, + RQ_SRS_006_RBAC_SettingsProfile_Drop_Syntax, + RQ_SRS_006_RBAC_SettingsProfile_ShowCreateSettingsProfile, + RQ_SRS_006_RBAC_Quotas, + RQ_SRS_006_RBAC_Quotas_Keyed, + RQ_SRS_006_RBAC_Quotas_Queries, + RQ_SRS_006_RBAC_Quotas_Errors, + RQ_SRS_006_RBAC_Quotas_ResultRows, + RQ_SRS_006_RBAC_Quotas_ReadRows, + RQ_SRS_006_RBAC_Quotas_ResultBytes, + RQ_SRS_006_RBAC_Quotas_ReadBytes, + RQ_SRS_006_RBAC_Quotas_ExecutionTime, + RQ_SRS_006_RBAC_Quota_Create, + RQ_SRS_006_RBAC_Quota_Create_IfNotExists, + RQ_SRS_006_RBAC_Quota_Create_Replace, + RQ_SRS_006_RBAC_Quota_Create_Cluster, + RQ_SRS_006_RBAC_Quota_Create_Interval, + RQ_SRS_006_RBAC_Quota_Create_Interval_Randomized, + RQ_SRS_006_RBAC_Quota_Create_Queries, + RQ_SRS_006_RBAC_Quota_Create_Errors, + RQ_SRS_006_RBAC_Quota_Create_ResultRows, + RQ_SRS_006_RBAC_Quota_Create_ReadRows, + RQ_SRS_006_RBAC_Quota_Create_ResultBytes, + RQ_SRS_006_RBAC_Quota_Create_ReadBytes, + RQ_SRS_006_RBAC_Quota_Create_ExecutionTime, + RQ_SRS_006_RBAC_Quota_Create_NoLimits, + RQ_SRS_006_RBAC_Quota_Create_TrackingOnly, + RQ_SRS_006_RBAC_Quota_Create_KeyedBy, + RQ_SRS_006_RBAC_Quota_Create_KeyedByOptions, + RQ_SRS_006_RBAC_Quota_Create_Assignment, + RQ_SRS_006_RBAC_Quota_Create_Assignment_None, + RQ_SRS_006_RBAC_Quota_Create_Assignment_All, + RQ_SRS_006_RBAC_Quota_Create_Assignment_Except, + RQ_SRS_006_RBAC_Quota_Create_Syntax, + RQ_SRS_006_RBAC_Quota_Alter, + RQ_SRS_006_RBAC_Quota_Alter_IfExists, + RQ_SRS_006_RBAC_Quota_Alter_Rename, + RQ_SRS_006_RBAC_Quota_Alter_Cluster, + RQ_SRS_006_RBAC_Quota_Alter_Interval, + RQ_SRS_006_RBAC_Quota_Alter_Interval_Randomized, + RQ_SRS_006_RBAC_Quota_Alter_Queries, + RQ_SRS_006_RBAC_Quota_Alter_Errors, + RQ_SRS_006_RBAC_Quota_Alter_ResultRows, + RQ_SRS_006_RBAC_Quota_Alter_ReadRows, + RQ_SRS_006_RBAC_Quota_ALter_ResultBytes, + RQ_SRS_006_RBAC_Quota_Alter_ReadBytes, + RQ_SRS_006_RBAC_Quota_Alter_ExecutionTime, + RQ_SRS_006_RBAC_Quota_Alter_NoLimits, + RQ_SRS_006_RBAC_Quota_Alter_TrackingOnly, + RQ_SRS_006_RBAC_Quota_Alter_KeyedBy, + RQ_SRS_006_RBAC_Quota_Alter_KeyedByOptions, + RQ_SRS_006_RBAC_Quota_Alter_Assignment, + RQ_SRS_006_RBAC_Quota_Alter_Assignment_None, + RQ_SRS_006_RBAC_Quota_Alter_Assignment_All, + RQ_SRS_006_RBAC_Quota_Alter_Assignment_Except, + RQ_SRS_006_RBAC_Quota_Alter_Syntax, + RQ_SRS_006_RBAC_Quota_Drop, + RQ_SRS_006_RBAC_Quota_Drop_IfExists, + RQ_SRS_006_RBAC_Quota_Drop_Cluster, + RQ_SRS_006_RBAC_Quota_Drop_Syntax, + RQ_SRS_006_RBAC_Quota_ShowQuotas, + RQ_SRS_006_RBAC_Quota_ShowQuotas_IntoOutfile, + RQ_SRS_006_RBAC_Quota_ShowQuotas_Format, + RQ_SRS_006_RBAC_Quota_ShowQuotas_Settings, + RQ_SRS_006_RBAC_Quota_ShowQuotas_Syntax, + RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Name, + RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Current, + RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Syntax, + RQ_SRS_006_RBAC_RowPolicy, + RQ_SRS_006_RBAC_RowPolicy_Condition, + RQ_SRS_006_RBAC_RowPolicy_Restriction, + RQ_SRS_006_RBAC_RowPolicy_Nesting, + RQ_SRS_006_RBAC_RowPolicy_Create, + RQ_SRS_006_RBAC_RowPolicy_Create_IfNotExists, + RQ_SRS_006_RBAC_RowPolicy_Create_Replace, + RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster, + RQ_SRS_006_RBAC_RowPolicy_Create_On, + RQ_SRS_006_RBAC_RowPolicy_Create_Access, + RQ_SRS_006_RBAC_RowPolicy_Create_Access_Permissive, + RQ_SRS_006_RBAC_RowPolicy_Create_Access_Restrictive, + RQ_SRS_006_RBAC_RowPolicy_Create_ForSelect, + RQ_SRS_006_RBAC_RowPolicy_Create_Condition, + RQ_SRS_006_RBAC_RowPolicy_Create_Assignment, + RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_None, + RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_All, + RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_AllExcept, + RQ_SRS_006_RBAC_RowPolicy_Create_Syntax, + RQ_SRS_006_RBAC_RowPolicy_Alter, + RQ_SRS_006_RBAC_RowPolicy_Alter_IfExists, + RQ_SRS_006_RBAC_RowPolicy_Alter_ForSelect, + RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster, + RQ_SRS_006_RBAC_RowPolicy_Alter_On, + RQ_SRS_006_RBAC_RowPolicy_Alter_Rename, + RQ_SRS_006_RBAC_RowPolicy_Alter_Access, + RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Permissive, + RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Restrictive, + RQ_SRS_006_RBAC_RowPolicy_Alter_Condition, + RQ_SRS_006_RBAC_RowPolicy_Alter_Condition_None, + RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment, + RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_None, + RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_All, + RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_AllExcept, + RQ_SRS_006_RBAC_RowPolicy_Alter_Syntax, + RQ_SRS_006_RBAC_RowPolicy_Drop, + RQ_SRS_006_RBAC_RowPolicy_Drop_IfExists, + RQ_SRS_006_RBAC_RowPolicy_Drop_On, + RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster, + RQ_SRS_006_RBAC_RowPolicy_Drop_Syntax, + RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy, + RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_On, + RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_Syntax, + RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies, + RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_On, + RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_Syntax, + RQ_SRS_006_RBAC_SetDefaultRole, + RQ_SRS_006_RBAC_SetDefaultRole_CurrentUser, + RQ_SRS_006_RBAC_SetDefaultRole_All, + RQ_SRS_006_RBAC_SetDefaultRole_AllExcept, + RQ_SRS_006_RBAC_SetDefaultRole_None, + RQ_SRS_006_RBAC_SetDefaultRole_Syntax, + RQ_SRS_006_RBAC_SetRole, + RQ_SRS_006_RBAC_SetRole_Default, + RQ_SRS_006_RBAC_SetRole_None, + RQ_SRS_006_RBAC_SetRole_All, + RQ_SRS_006_RBAC_SetRole_AllExcept, + RQ_SRS_006_RBAC_SetRole_Syntax, + RQ_SRS_006_RBAC_Grant_Privilege_To, + RQ_SRS_006_RBAC_Grant_Privilege_ToCurrentUser, + RQ_SRS_006_RBAC_Grant_Privilege_Select, + RQ_SRS_006_RBAC_Grant_Privilege_Insert, + RQ_SRS_006_RBAC_Grant_Privilege_Alter, + RQ_SRS_006_RBAC_Grant_Privilege_Create, + RQ_SRS_006_RBAC_Grant_Privilege_Drop, + RQ_SRS_006_RBAC_Grant_Privilege_Truncate, + RQ_SRS_006_RBAC_Grant_Privilege_Optimize, + RQ_SRS_006_RBAC_Grant_Privilege_Show, + RQ_SRS_006_RBAC_Grant_Privilege_KillQuery, + RQ_SRS_006_RBAC_Grant_Privilege_AccessManagement, + RQ_SRS_006_RBAC_Grant_Privilege_System, + RQ_SRS_006_RBAC_Grant_Privilege_Introspection, + RQ_SRS_006_RBAC_Grant_Privilege_Sources, + RQ_SRS_006_RBAC_Grant_Privilege_DictGet, + RQ_SRS_006_RBAC_Grant_Privilege_None, + RQ_SRS_006_RBAC_Grant_Privilege_All, + RQ_SRS_006_RBAC_Grant_Privilege_GrantOption, + RQ_SRS_006_RBAC_Grant_Privilege_On, + RQ_SRS_006_RBAC_Grant_Privilege_PrivilegeColumns, + RQ_SRS_006_RBAC_Grant_Privilege_OnCluster, + RQ_SRS_006_RBAC_Grant_Privilege_Syntax, + RQ_SRS_006_RBAC_Revoke_Privilege_Cluster, + RQ_SRS_006_RBAC_Revoke_Privilege_Select, + RQ_SRS_006_RBAC_Revoke_Privilege_Insert, + RQ_SRS_006_RBAC_Revoke_Privilege_Alter, + RQ_SRS_006_RBAC_Revoke_Privilege_Create, + RQ_SRS_006_RBAC_Revoke_Privilege_Drop, + RQ_SRS_006_RBAC_Revoke_Privilege_Truncate, + RQ_SRS_006_RBAC_Revoke_Privilege_Optimize, + RQ_SRS_006_RBAC_Revoke_Privilege_Show, + RQ_SRS_006_RBAC_Revoke_Privilege_KillQuery, + RQ_SRS_006_RBAC_Revoke_Privilege_AccessManagement, + RQ_SRS_006_RBAC_Revoke_Privilege_System, + RQ_SRS_006_RBAC_Revoke_Privilege_Introspection, + RQ_SRS_006_RBAC_Revoke_Privilege_Sources, + RQ_SRS_006_RBAC_Revoke_Privilege_DictGet, + RQ_SRS_006_RBAC_Revoke_Privilege_PrivilegeColumns, + RQ_SRS_006_RBAC_Revoke_Privilege_Multiple, + RQ_SRS_006_RBAC_Revoke_Privilege_All, + RQ_SRS_006_RBAC_Revoke_Privilege_None, + RQ_SRS_006_RBAC_Revoke_Privilege_On, + RQ_SRS_006_RBAC_Revoke_Privilege_From, + RQ_SRS_006_RBAC_Revoke_Privilege_Syntax, + RQ_SRS_006_RBAC_Grant_Role, + RQ_SRS_006_RBAC_Grant_Role_CurrentUser, + RQ_SRS_006_RBAC_Grant_Role_AdminOption, + RQ_SRS_006_RBAC_Grant_Role_OnCluster, + RQ_SRS_006_RBAC_Grant_Role_Syntax, + RQ_SRS_006_RBAC_Revoke_Role, + RQ_SRS_006_RBAC_Revoke_Role_Keywords, + RQ_SRS_006_RBAC_Revoke_Role_Cluster, + RQ_SRS_006_RBAC_Revoke_AdminOption, + RQ_SRS_006_RBAC_Revoke_Role_Syntax, + RQ_SRS_006_RBAC_Show_Grants, + RQ_SRS_006_RBAC_Show_Grants_For, + RQ_SRS_006_RBAC_Show_Grants_Syntax, + RQ_SRS_006_RBAC_Table_PublicTables, + RQ_SRS_006_RBAC_Table_SensitiveTables, + RQ_SRS_006_RBAC_DistributedTable_Create, + RQ_SRS_006_RBAC_DistributedTable_Select, + RQ_SRS_006_RBAC_DistributedTable_Insert, + RQ_SRS_006_RBAC_DistributedTable_SpecialTables, + RQ_SRS_006_RBAC_DistributedTable_LocalUser, + RQ_SRS_006_RBAC_DistributedTable_SameUserDifferentNodesDifferentPrivileges, + RQ_SRS_006_RBAC_View, + RQ_SRS_006_RBAC_View_Create, + RQ_SRS_006_RBAC_View_Select, + RQ_SRS_006_RBAC_View_Drop, + RQ_SRS_006_RBAC_MaterializedView, + RQ_SRS_006_RBAC_MaterializedView_Create, + RQ_SRS_006_RBAC_MaterializedView_Select, + RQ_SRS_006_RBAC_MaterializedView_Select_TargetTable, + RQ_SRS_006_RBAC_MaterializedView_Select_SourceTable, + RQ_SRS_006_RBAC_MaterializedView_Drop, + RQ_SRS_006_RBAC_MaterializedView_ModifyQuery, + RQ_SRS_006_RBAC_MaterializedView_Insert, + RQ_SRS_006_RBAC_MaterializedView_Insert_SourceTable, + RQ_SRS_006_RBAC_MaterializedView_Insert_TargetTable, + RQ_SRS_006_RBAC_LiveView, + RQ_SRS_006_RBAC_LiveView_Create, + RQ_SRS_006_RBAC_LiveView_Select, + RQ_SRS_006_RBAC_LiveView_Drop, + RQ_SRS_006_RBAC_LiveView_Refresh, + RQ_SRS_006_RBAC_Select, + RQ_SRS_006_RBAC_Select_Column, + RQ_SRS_006_RBAC_Select_Cluster, + RQ_SRS_006_RBAC_Select_TableEngines, + RQ_SRS_006_RBAC_Insert, + RQ_SRS_006_RBAC_Insert_Column, + RQ_SRS_006_RBAC_Insert_Cluster, + RQ_SRS_006_RBAC_Insert_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterColumn, + RQ_SRS_006_RBAC_Privileges_AlterColumn_Grant, + RQ_SRS_006_RBAC_Privileges_AlterColumn_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterColumn_Column, + RQ_SRS_006_RBAC_Privileges_AlterColumn_Cluster, + RQ_SRS_006_RBAC_Privileges_AlterColumn_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterIndex, + RQ_SRS_006_RBAC_Privileges_AlterIndex_Grant, + RQ_SRS_006_RBAC_Privileges_AlterIndex_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterIndex_Cluster, + RQ_SRS_006_RBAC_Privileges_AlterIndex_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterConstraint, + RQ_SRS_006_RBAC_Privileges_AlterConstraint_Grant, + RQ_SRS_006_RBAC_Privileges_AlterConstraint_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterConstraint_Cluster, + RQ_SRS_006_RBAC_Privileges_AlterConstraint_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterTTL, + RQ_SRS_006_RBAC_Privileges_AlterTTL_Grant, + RQ_SRS_006_RBAC_Privileges_AlterTTL_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterTTL_Cluster, + RQ_SRS_006_RBAC_Privileges_AlterTTL_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterSettings, + RQ_SRS_006_RBAC_Privileges_AlterSettings_Grant, + RQ_SRS_006_RBAC_Privileges_AlterSettings_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterSettings_Cluster, + RQ_SRS_006_RBAC_Privileges_AlterSettings_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterUpdate, + RQ_SRS_006_RBAC_Privileges_AlterUpdate_Grant, + RQ_SRS_006_RBAC_Privileges_AlterUpdate_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterUpdate_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterDelete, + RQ_SRS_006_RBAC_Privileges_AlterDelete_Grant, + RQ_SRS_006_RBAC_Privileges_AlterDelete_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterDelete_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterFreeze, + RQ_SRS_006_RBAC_Privileges_AlterFreeze_Grant, + RQ_SRS_006_RBAC_Privileges_AlterFreeze_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterFreeze_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterFetch, + RQ_SRS_006_RBAC_Privileges_AlterFetch_Grant, + RQ_SRS_006_RBAC_Privileges_AlterFetch_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterFetch_TableEngines, + RQ_SRS_006_RBAC_Privileges_AlterMove, + RQ_SRS_006_RBAC_Privileges_AlterMove_Grant, + RQ_SRS_006_RBAC_Privileges_AlterMove_Revoke, + RQ_SRS_006_RBAC_Privileges_AlterMove_TableEngines, + RQ_SRS_006_RBAC_Privileges_CreateTable, + RQ_SRS_006_RBAC_Privileges_CreateDatabase, + RQ_SRS_006_RBAC_Privileges_CreateDictionary, + RQ_SRS_006_RBAC_Privileges_CreateTemporaryTable, + RQ_SRS_006_RBAC_Privileges_AttachDatabase, + RQ_SRS_006_RBAC_Privileges_AttachDictionary, + RQ_SRS_006_RBAC_Privileges_AttachTemporaryTable, + RQ_SRS_006_RBAC_Privileges_AttachTable, + RQ_SRS_006_RBAC_Privileges_DropTable, + RQ_SRS_006_RBAC_Privileges_DropDatabase, + RQ_SRS_006_RBAC_Privileges_DropDictionary, + RQ_SRS_006_RBAC_Privileges_DetachTable, + RQ_SRS_006_RBAC_Privileges_DetachView, + RQ_SRS_006_RBAC_Privileges_DetachDatabase, + RQ_SRS_006_RBAC_Privileges_DetachDictionary, + RQ_SRS_006_RBAC_Privileges_Truncate, + RQ_SRS_006_RBAC_Privileges_Optimize, + RQ_SRS_006_RBAC_Privileges_KillQuery, + RQ_SRS_006_RBAC_Privileges_KillMutation, + RQ_SRS_006_RBAC_Privileges_KillMutation_AlterUpdate, + RQ_SRS_006_RBAC_Privileges_KillMutation_AlterDelete, + RQ_SRS_006_RBAC_Privileges_KillMutation_AlterDropColumn, + RQ_SRS_006_RBAC_ShowTables_Privilege, + RQ_SRS_006_RBAC_ShowTables_RequiredPrivilege, + RQ_SRS_006_RBAC_ExistsTable_RequiredPrivilege, + RQ_SRS_006_RBAC_CheckTable_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowDatabases_Privilege, + RQ_SRS_006_RBAC_ShowDatabases_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowCreateDatabase_RequiredPrivilege, + RQ_SRS_006_RBAC_UseDatabase_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowColumns_Privilege, + RQ_SRS_006_RBAC_ShowCreateTable_RequiredPrivilege, + RQ_SRS_006_RBAC_DescribeTable_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowDictionaries_Privilege, + RQ_SRS_006_RBAC_ShowDictionaries_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowCreateDictionary_RequiredPrivilege, + RQ_SRS_006_RBAC_ExistsDictionary_RequiredPrivilege, + RQ_SRS_006_RBAC_Privileges_CreateUser, + RQ_SRS_006_RBAC_Privileges_CreateUser_DefaultRole, + RQ_SRS_006_RBAC_Privileges_AlterUser, + RQ_SRS_006_RBAC_Privileges_DropUser, + RQ_SRS_006_RBAC_Privileges_CreateRole, + RQ_SRS_006_RBAC_Privileges_AlterRole, + RQ_SRS_006_RBAC_Privileges_DropRole, + RQ_SRS_006_RBAC_Privileges_CreateRowPolicy, + RQ_SRS_006_RBAC_Privileges_AlterRowPolicy, + RQ_SRS_006_RBAC_Privileges_DropRowPolicy, + RQ_SRS_006_RBAC_Privileges_CreateQuota, + RQ_SRS_006_RBAC_Privileges_AlterQuota, + RQ_SRS_006_RBAC_Privileges_DropQuota, + RQ_SRS_006_RBAC_Privileges_CreateSettingsProfile, + RQ_SRS_006_RBAC_Privileges_AlterSettingsProfile, + RQ_SRS_006_RBAC_Privileges_DropSettingsProfile, + RQ_SRS_006_RBAC_Privileges_RoleAdmin, + RQ_SRS_006_RBAC_ShowUsers_Privilege, + RQ_SRS_006_RBAC_ShowUsers_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowCreateUser_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowRoles_Privilege, + RQ_SRS_006_RBAC_ShowRoles_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowCreateRole_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowRowPolicies_Privilege, + RQ_SRS_006_RBAC_ShowRowPolicies_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowCreateRowPolicy_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowQuotas_Privilege, + RQ_SRS_006_RBAC_ShowQuotas_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowCreateQuota_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowSettingsProfiles_Privilege, + RQ_SRS_006_RBAC_ShowSettingsProfiles_RequiredPrivilege, + RQ_SRS_006_RBAC_ShowCreateSettingsProfile_RequiredPrivilege, + RQ_SRS_006_RBAC_dictGet_Privilege, + RQ_SRS_006_RBAC_dictGet_RequiredPrivilege, + RQ_SRS_006_RBAC_dictGet_Type_RequiredPrivilege, + RQ_SRS_006_RBAC_dictGet_OrDefault_RequiredPrivilege, + RQ_SRS_006_RBAC_dictHas_RequiredPrivilege, + RQ_SRS_006_RBAC_dictGetHierarchy_RequiredPrivilege, + RQ_SRS_006_RBAC_dictIsIn_RequiredPrivilege, + RQ_SRS_006_RBAC_Privileges_Introspection, + RQ_SRS_006_RBAC_Privileges_Introspection_addressToLine, + RQ_SRS_006_RBAC_Privileges_Introspection_addressToSymbol, + RQ_SRS_006_RBAC_Privileges_Introspection_demangle, + RQ_SRS_006_RBAC_Privileges_System_Shutdown, + RQ_SRS_006_RBAC_Privileges_System_DropCache, + RQ_SRS_006_RBAC_Privileges_System_DropCache_DNS, + RQ_SRS_006_RBAC_Privileges_System_DropCache_Mark, + RQ_SRS_006_RBAC_Privileges_System_DropCache_Uncompressed, + RQ_SRS_006_RBAC_Privileges_System_Reload, + RQ_SRS_006_RBAC_Privileges_System_Reload_Config, + RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionary, + RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionaries, + RQ_SRS_006_RBAC_Privileges_System_Reload_EmbeddedDictionaries, + RQ_SRS_006_RBAC_Privileges_System_Merges, + RQ_SRS_006_RBAC_Privileges_System_TTLMerges, + RQ_SRS_006_RBAC_Privileges_System_Fetches, + RQ_SRS_006_RBAC_Privileges_System_Moves, + RQ_SRS_006_RBAC_Privileges_System_Sends, + RQ_SRS_006_RBAC_Privileges_System_Sends_Distributed, + RQ_SRS_006_RBAC_Privileges_System_Sends_Replicated, + RQ_SRS_006_RBAC_Privileges_System_ReplicationQueues, + RQ_SRS_006_RBAC_Privileges_System_SyncReplica, + RQ_SRS_006_RBAC_Privileges_System_RestartReplica, + RQ_SRS_006_RBAC_Privileges_System_Flush, + RQ_SRS_006_RBAC_Privileges_System_Flush_Distributed, + RQ_SRS_006_RBAC_Privileges_System_Flush_Logs, + RQ_SRS_006_RBAC_Privileges_Sources, + RQ_SRS_006_RBAC_Privileges_Sources_File, + RQ_SRS_006_RBAC_Privileges_Sources_URL, + RQ_SRS_006_RBAC_Privileges_Sources_Remote, + RQ_SRS_006_RBAC_Privileges_Sources_MySQL, + RQ_SRS_006_RBAC_Privileges_Sources_ODBC, + RQ_SRS_006_RBAC_Privileges_Sources_JDBC, + RQ_SRS_006_RBAC_Privileges_Sources_HDFS, + RQ_SRS_006_RBAC_Privileges_Sources_S3, + RQ_SRS_006_RBAC_Privileges_GrantOption, + RQ_SRS_006_RBAC_Privileges_All, + RQ_SRS_006_RBAC_Privileges_RoleAll, + RQ_SRS_006_RBAC_Privileges_None, + RQ_SRS_006_RBAC_Privileges_AdminOption, + ), + content=''' # SRS-006 ClickHouse Role Based Access Control # Software Requirements Specification @@ -34,556 +9989,588 @@ SRS_006_ClickHouse_Role_Based_Access_Control = Specification( * 5 [Requirements](#requirements) * 5.1 [Generic](#generic) * 5.1.1 [RQ.SRS-006.RBAC](#rqsrs-006rbac) - * 5.1.2 [Login](#login) - * 5.1.2.1 [RQ.SRS-006.RBAC.Login](#rqsrs-006rbaclogin) - * 5.1.2.2 [RQ.SRS-006.RBAC.Login.DefaultUser](#rqsrs-006rbaclogindefaultuser) - * 5.1.3 [User](#user) - * 5.1.3.1 [RQ.SRS-006.RBAC.User](#rqsrs-006rbacuser) - * 5.1.3.2 [RQ.SRS-006.RBAC.User.Roles](#rqsrs-006rbacuserroles) - * 5.1.3.3 [RQ.SRS-006.RBAC.User.Privileges](#rqsrs-006rbacuserprivileges) - * 5.1.3.4 [RQ.SRS-006.RBAC.User.Variables](#rqsrs-006rbacuservariables) - * 5.1.3.5 [RQ.SRS-006.RBAC.User.Variables.Constraints](#rqsrs-006rbacuservariablesconstraints) - * 5.1.3.6 [RQ.SRS-006.RBAC.User.SettingsProfile](#rqsrs-006rbacusersettingsprofile) - * 5.1.3.7 [RQ.SRS-006.RBAC.User.Quotas](#rqsrs-006rbacuserquotas) - * 5.1.3.8 [RQ.SRS-006.RBAC.User.RowPolicies](#rqsrs-006rbacuserrowpolicies) - * 5.1.3.9 [RQ.SRS-006.RBAC.User.AccountLock](#rqsrs-006rbacuseraccountlock) - * 5.1.3.10 [RQ.SRS-006.RBAC.User.AccountLock.DenyAccess](#rqsrs-006rbacuseraccountlockdenyaccess) - * 5.1.3.11 [RQ.SRS-006.RBAC.User.DefaultRole](#rqsrs-006rbacuserdefaultrole) - * 5.1.3.12 [RQ.SRS-006.RBAC.User.RoleSelection](#rqsrs-006rbacuserroleselection) - * 5.1.3.13 [RQ.SRS-006.RBAC.User.ShowCreate](#rqsrs-006rbacusershowcreate) - * 5.1.3.14 [RQ.SRS-006.RBAC.User.ShowPrivileges](#rqsrs-006rbacusershowprivileges) - * 5.1.4 [Role](#role) - * 5.1.4.1 [RQ.SRS-006.RBAC.Role](#rqsrs-006rbacrole) - * 5.1.4.2 [RQ.SRS-006.RBAC.Role.Privileges](#rqsrs-006rbacroleprivileges) - * 5.1.4.3 [RQ.SRS-006.RBAC.Role.Variables](#rqsrs-006rbacrolevariables) - * 5.1.4.4 [RQ.SRS-006.RBAC.Role.SettingsProfile](#rqsrs-006rbacrolesettingsprofile) - * 5.1.4.5 [RQ.SRS-006.RBAC.Role.Quotas](#rqsrs-006rbacrolequotas) - * 5.1.4.6 [RQ.SRS-006.RBAC.Role.RowPolicies](#rqsrs-006rbacrolerowpolicies) - * 5.1.5 [Partial Revokes](#partial-revokes) - * 5.1.5.1 [RQ.SRS-006.RBAC.PartialRevokes](#rqsrs-006rbacpartialrevokes) - * 5.1.6 [Settings Profile](#settings-profile) - * 5.1.6.1 [RQ.SRS-006.RBAC.SettingsProfile](#rqsrs-006rbacsettingsprofile) - * 5.1.6.2 [RQ.SRS-006.RBAC.SettingsProfile.Constraints](#rqsrs-006rbacsettingsprofileconstraints) - * 5.1.6.3 [RQ.SRS-006.RBAC.SettingsProfile.ShowCreate](#rqsrs-006rbacsettingsprofileshowcreate) - * 5.1.7 [Quotas](#quotas) - * 5.1.7.1 [RQ.SRS-006.RBAC.Quotas](#rqsrs-006rbacquotas) - * 5.1.7.2 [RQ.SRS-006.RBAC.Quotas.Keyed](#rqsrs-006rbacquotaskeyed) - * 5.1.7.3 [RQ.SRS-006.RBAC.Quotas.Queries](#rqsrs-006rbacquotasqueries) - * 5.1.7.4 [RQ.SRS-006.RBAC.Quotas.Errors](#rqsrs-006rbacquotaserrors) - * 5.1.7.5 [RQ.SRS-006.RBAC.Quotas.ResultRows](#rqsrs-006rbacquotasresultrows) - * 5.1.7.6 [RQ.SRS-006.RBAC.Quotas.ReadRows](#rqsrs-006rbacquotasreadrows) - * 5.1.7.7 [RQ.SRS-006.RBAC.Quotas.ResultBytes](#rqsrs-006rbacquotasresultbytes) - * 5.1.7.8 [RQ.SRS-006.RBAC.Quotas.ReadBytes](#rqsrs-006rbacquotasreadbytes) - * 5.1.7.9 [RQ.SRS-006.RBAC.Quotas.ExecutionTime](#rqsrs-006rbacquotasexecutiontime) - * 5.1.7.10 [RQ.SRS-006.RBAC.Quotas.ShowCreate](#rqsrs-006rbacquotasshowcreate) - * 5.1.8 [Row Policy](#row-policy) - * 5.1.8.1 [RQ.SRS-006.RBAC.RowPolicy](#rqsrs-006rbacrowpolicy) - * 5.1.8.2 [RQ.SRS-006.RBAC.RowPolicy.Condition](#rqsrs-006rbacrowpolicycondition) - * 5.1.8.3 [RQ.SRS-006.RBAC.RowPolicy.ShowCreate](#rqsrs-006rbacrowpolicyshowcreate) - * 5.2 [Specific](#specific) - * 5.2.8.1 [RQ.SRS-006.RBAC.User.Use.DefaultRole](#rqsrs-006rbacuserusedefaultrole) - * 5.2.8.2 [RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole](#rqsrs-006rbacuseruseallroleswhennodefaultrole) - * 5.2.8.3 [RQ.SRS-006.RBAC.User.Create](#rqsrs-006rbacusercreate) - * 5.2.8.4 [RQ.SRS-006.RBAC.User.Create.IfNotExists](#rqsrs-006rbacusercreateifnotexists) - * 5.2.8.5 [RQ.SRS-006.RBAC.User.Create.Replace](#rqsrs-006rbacusercreatereplace) - * 5.2.8.6 [RQ.SRS-006.RBAC.User.Create.Password.NoPassword](#rqsrs-006rbacusercreatepasswordnopassword) - * 5.2.8.7 [RQ.SRS-006.RBAC.User.Create.Password.NoPassword.Login](#rqsrs-006rbacusercreatepasswordnopasswordlogin) - * 5.2.8.8 [RQ.SRS-006.RBAC.User.Create.Password.PlainText](#rqsrs-006rbacusercreatepasswordplaintext) - * 5.2.8.9 [RQ.SRS-006.RBAC.User.Create.Password.PlainText.Login](#rqsrs-006rbacusercreatepasswordplaintextlogin) - * 5.2.8.10 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Password](#rqsrs-006rbacusercreatepasswordsha256password) - * 5.2.8.11 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Password.Login](#rqsrs-006rbacusercreatepasswordsha256passwordlogin) - * 5.2.8.12 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash](#rqsrs-006rbacusercreatepasswordsha256hash) - * 5.2.8.13 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash.Login](#rqsrs-006rbacusercreatepasswordsha256hashlogin) - * 5.2.8.14 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password](#rqsrs-006rbacusercreatepassworddoublesha1password) - * 5.2.8.15 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password.Login](#rqsrs-006rbacusercreatepassworddoublesha1passwordlogin) - * 5.2.8.16 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash](#rqsrs-006rbacusercreatepassworddoublesha1hash) - * 5.2.8.17 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash.Login](#rqsrs-006rbacusercreatepassworddoublesha1hashlogin) - * 5.2.8.18 [RQ.SRS-006.RBAC.User.Create.Host.Name](#rqsrs-006rbacusercreatehostname) - * 5.2.8.19 [RQ.SRS-006.RBAC.User.Create.Host.Regexp](#rqsrs-006rbacusercreatehostregexp) - * 5.2.8.20 [RQ.SRS-006.RBAC.User.Create.Host.IP](#rqsrs-006rbacusercreatehostip) - * 5.2.8.21 [RQ.SRS-006.RBAC.User.Create.Host.Any](#rqsrs-006rbacusercreatehostany) - * 5.2.8.22 [RQ.SRS-006.RBAC.User.Create.Host.None](#rqsrs-006rbacusercreatehostnone) - * 5.2.8.23 [RQ.SRS-006.RBAC.User.Create.Host.Local](#rqsrs-006rbacusercreatehostlocal) - * 5.2.8.24 [RQ.SRS-006.RBAC.User.Create.Host.Like](#rqsrs-006rbacusercreatehostlike) - * 5.2.8.25 [RQ.SRS-006.RBAC.User.Create.Host.Default](#rqsrs-006rbacusercreatehostdefault) - * 5.2.8.26 [RQ.SRS-006.RBAC.User.Create.DefaultRole](#rqsrs-006rbacusercreatedefaultrole) - * 5.2.8.27 [RQ.SRS-006.RBAC.User.Create.DefaultRole.None](#rqsrs-006rbacusercreatedefaultrolenone) - * 5.2.8.28 [RQ.SRS-006.RBAC.User.Create.DefaultRole.All](#rqsrs-006rbacusercreatedefaultroleall) - * 5.2.8.29 [RQ.SRS-006.RBAC.User.Create.Settings](#rqsrs-006rbacusercreatesettings) - * 5.2.8.30 [RQ.SRS-006.RBAC.User.Create.OnCluster](#rqsrs-006rbacusercreateoncluster) - * 5.2.8.31 [RQ.SRS-006.RBAC.User.Create.Syntax](#rqsrs-006rbacusercreatesyntax) - * 5.2.8.32 [RQ.SRS-006.RBAC.User.Alter](#rqsrs-006rbacuseralter) - * 5.2.8.33 [RQ.SRS-006.RBAC.User.Alter.OrderOfEvaluation](#rqsrs-006rbacuseralterorderofevaluation) - * 5.2.8.34 [RQ.SRS-006.RBAC.User.Alter.IfExists](#rqsrs-006rbacuseralterifexists) - * 5.2.8.35 [RQ.SRS-006.RBAC.User.Alter.Cluster](#rqsrs-006rbacuseraltercluster) - * 5.2.8.36 [RQ.SRS-006.RBAC.User.Alter.Rename](#rqsrs-006rbacuseralterrename) - * 5.2.8.37 [RQ.SRS-006.RBAC.User.Alter.Password.PlainText](#rqsrs-006rbacuseralterpasswordplaintext) - * 5.2.8.38 [RQ.SRS-006.RBAC.User.Alter.Password.Sha256Password](#rqsrs-006rbacuseralterpasswordsha256password) - * 5.2.8.39 [RQ.SRS-006.RBAC.User.Alter.Password.DoubleSha1Password](#rqsrs-006rbacuseralterpassworddoublesha1password) - * 5.2.8.40 [RQ.SRS-006.RBAC.User.Alter.Host.AddDrop](#rqsrs-006rbacuseralterhostadddrop) - * 5.2.8.41 [RQ.SRS-006.RBAC.User.Alter.Host.Local](#rqsrs-006rbacuseralterhostlocal) - * 5.2.8.42 [RQ.SRS-006.RBAC.User.Alter.Host.Name](#rqsrs-006rbacuseralterhostname) - * 5.2.8.43 [RQ.SRS-006.RBAC.User.Alter.Host.Regexp](#rqsrs-006rbacuseralterhostregexp) - * 5.2.8.44 [RQ.SRS-006.RBAC.User.Alter.Host.IP](#rqsrs-006rbacuseralterhostip) - * 5.2.8.45 [RQ.SRS-006.RBAC.User.Alter.Host.Like](#rqsrs-006rbacuseralterhostlike) - * 5.2.8.46 [RQ.SRS-006.RBAC.User.Alter.Host.Any](#rqsrs-006rbacuseralterhostany) - * 5.2.8.47 [RQ.SRS-006.RBAC.User.Alter.Host.None](#rqsrs-006rbacuseralterhostnone) - * 5.2.8.48 [RQ.SRS-006.RBAC.User.Alter.DefaultRole](#rqsrs-006rbacuseralterdefaultrole) - * 5.2.8.49 [RQ.SRS-006.RBAC.User.Alter.DefaultRole.All](#rqsrs-006rbacuseralterdefaultroleall) - * 5.2.8.50 [RQ.SRS-006.RBAC.User.Alter.DefaultRole.AllExcept](#rqsrs-006rbacuseralterdefaultroleallexcept) - * 5.2.8.51 [RQ.SRS-006.RBAC.User.Alter.Settings](#rqsrs-006rbacuseraltersettings) - * 5.2.8.52 [RQ.SRS-006.RBAC.User.Alter.Settings.Min](#rqsrs-006rbacuseraltersettingsmin) - * 5.2.8.53 [RQ.SRS-006.RBAC.User.Alter.Settings.Max](#rqsrs-006rbacuseraltersettingsmax) - * 5.2.8.54 [RQ.SRS-006.RBAC.User.Alter.Settings.Profile](#rqsrs-006rbacuseraltersettingsprofile) - * 5.2.8.55 [RQ.SRS-006.RBAC.User.Alter.Syntax](#rqsrs-006rbacuseraltersyntax) - * 5.2.8.56 [RQ.SRS-006.RBAC.SetDefaultRole](#rqsrs-006rbacsetdefaultrole) - * 5.2.8.57 [RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser](#rqsrs-006rbacsetdefaultrolecurrentuser) - * 5.2.8.58 [RQ.SRS-006.RBAC.SetDefaultRole.All](#rqsrs-006rbacsetdefaultroleall) - * 5.2.8.59 [RQ.SRS-006.RBAC.SetDefaultRole.AllExcept](#rqsrs-006rbacsetdefaultroleallexcept) - * 5.2.8.60 [RQ.SRS-006.RBAC.SetDefaultRole.None](#rqsrs-006rbacsetdefaultrolenone) - * 5.2.8.61 [RQ.SRS-006.RBAC.SetDefaultRole.Syntax](#rqsrs-006rbacsetdefaultrolesyntax) - * 5.2.8.62 [RQ.SRS-006.RBAC.SetRole](#rqsrs-006rbacsetrole) - * 5.2.8.63 [RQ.SRS-006.RBAC.SetRole.Default](#rqsrs-006rbacsetroledefault) - * 5.2.8.64 [RQ.SRS-006.RBAC.SetRole.None](#rqsrs-006rbacsetrolenone) - * 5.2.8.65 [RQ.SRS-006.RBAC.SetRole.All](#rqsrs-006rbacsetroleall) - * 5.2.8.66 [RQ.SRS-006.RBAC.SetRole.AllExcept](#rqsrs-006rbacsetroleallexcept) - * 5.2.8.67 [RQ.SRS-006.RBAC.SetRole.Syntax](#rqsrs-006rbacsetrolesyntax) - * 5.2.8.68 [RQ.SRS-006.RBAC.User.ShowCreateUser](#rqsrs-006rbacusershowcreateuser) - * 5.2.8.69 [RQ.SRS-006.RBAC.User.ShowCreateUser.For](#rqsrs-006rbacusershowcreateuserfor) - * 5.2.8.70 [RQ.SRS-006.RBAC.User.ShowCreateUser.Syntax](#rqsrs-006rbacusershowcreateusersyntax) - * 5.2.8.71 [RQ.SRS-006.RBAC.User.Drop](#rqsrs-006rbacuserdrop) - * 5.2.8.72 [RQ.SRS-006.RBAC.User.Drop.IfExists](#rqsrs-006rbacuserdropifexists) - * 5.2.8.73 [RQ.SRS-006.RBAC.User.Drop.OnCluster](#rqsrs-006rbacuserdroponcluster) - * 5.2.8.74 [RQ.SRS-006.RBAC.User.Drop.Syntax](#rqsrs-006rbacuserdropsyntax) - * 5.2.8.75 [RQ.SRS-006.RBAC.Role.Create](#rqsrs-006rbacrolecreate) - * 5.2.8.76 [RQ.SRS-006.RBAC.Role.Create.IfNotExists](#rqsrs-006rbacrolecreateifnotexists) - * 5.2.8.77 [RQ.SRS-006.RBAC.Role.Create.Replace](#rqsrs-006rbacrolecreatereplace) - * 5.2.8.78 [RQ.SRS-006.RBAC.Role.Create.Settings](#rqsrs-006rbacrolecreatesettings) - * 5.2.8.79 [RQ.SRS-006.RBAC.Role.Create.Syntax](#rqsrs-006rbacrolecreatesyntax) - * 5.2.8.80 [RQ.SRS-006.RBAC.Role.Alter](#rqsrs-006rbacrolealter) - * 5.2.8.81 [RQ.SRS-006.RBAC.Role.Alter.IfExists](#rqsrs-006rbacrolealterifexists) - * 5.2.8.82 [RQ.SRS-006.RBAC.Role.Alter.Cluster](#rqsrs-006rbacrolealtercluster) - * 5.2.8.83 [RQ.SRS-006.RBAC.Role.Alter.Rename](#rqsrs-006rbacrolealterrename) - * 5.2.8.84 [RQ.SRS-006.RBAC.Role.Alter.Settings](#rqsrs-006rbacrolealtersettings) - * 5.2.8.85 [RQ.SRS-006.RBAC.Role.Alter.Syntax](#rqsrs-006rbacrolealtersyntax) - * 5.2.8.86 [RQ.SRS-006.RBAC.Role.Drop](#rqsrs-006rbacroledrop) - * 5.2.8.87 [RQ.SRS-006.RBAC.Role.Drop.IfExists](#rqsrs-006rbacroledropifexists) - * 5.2.8.88 [RQ.SRS-006.RBAC.Role.Drop.Cluster](#rqsrs-006rbacroledropcluster) - * 5.2.8.89 [RQ.SRS-006.RBAC.Role.Drop.Syntax](#rqsrs-006rbacroledropsyntax) - * 5.2.8.90 [RQ.SRS-006.RBAC.Role.ShowCreate](#rqsrs-006rbacroleshowcreate) - * 5.2.8.91 [RQ.SRS-006.RBAC.Role.ShowCreate.Syntax](#rqsrs-006rbacroleshowcreatesyntax) - * 5.2.8.92 [RQ.SRS-006.RBAC.Grant.Privilege.To](#rqsrs-006rbacgrantprivilegeto) - * 5.2.8.93 [RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser](#rqsrs-006rbacgrantprivilegetocurrentuser) - * 5.2.8.94 [RQ.SRS-006.RBAC.Grant.Privilege.Select](#rqsrs-006rbacgrantprivilegeselect) - * 5.2.8.95 [RQ.SRS-006.RBAC.Grant.Privilege.Insert](#rqsrs-006rbacgrantprivilegeinsert) - * 5.2.8.96 [RQ.SRS-006.RBAC.Grant.Privilege.Alter](#rqsrs-006rbacgrantprivilegealter) - * 5.2.8.97 [RQ.SRS-006.RBAC.Grant.Privilege.Create](#rqsrs-006rbacgrantprivilegecreate) - * 5.2.8.98 [RQ.SRS-006.RBAC.Grant.Privilege.Drop](#rqsrs-006rbacgrantprivilegedrop) - * 5.2.8.99 [RQ.SRS-006.RBAC.Grant.Privilege.Truncate](#rqsrs-006rbacgrantprivilegetruncate) - * 5.2.8.100 [RQ.SRS-006.RBAC.Grant.Privilege.Optimize](#rqsrs-006rbacgrantprivilegeoptimize) - * 5.2.8.101 [RQ.SRS-006.RBAC.Grant.Privilege.Show](#rqsrs-006rbacgrantprivilegeshow) - * 5.2.8.102 [RQ.SRS-006.RBAC.Grant.Privilege.KillQuery](#rqsrs-006rbacgrantprivilegekillquery) - * 5.2.8.103 [RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement](#rqsrs-006rbacgrantprivilegeaccessmanagement) - * 5.2.8.104 [RQ.SRS-006.RBAC.Grant.Privilege.System](#rqsrs-006rbacgrantprivilegesystem) - * 5.2.8.105 [RQ.SRS-006.RBAC.Grant.Privilege.Introspection](#rqsrs-006rbacgrantprivilegeintrospection) - * 5.2.8.106 [RQ.SRS-006.RBAC.Grant.Privilege.Sources](#rqsrs-006rbacgrantprivilegesources) - * 5.2.8.107 [RQ.SRS-006.RBAC.Grant.Privilege.DictGet](#rqsrs-006rbacgrantprivilegedictget) - * 5.2.8.108 [RQ.SRS-006.RBAC.Grant.Privilege.None](#rqsrs-006rbacgrantprivilegenone) - * 5.2.8.109 [RQ.SRS-006.RBAC.Grant.Privilege.All](#rqsrs-006rbacgrantprivilegeall) - * 5.2.8.110 [RQ.SRS-006.RBAC.Grant.Privilege.GrantOption](#rqsrs-006rbacgrantprivilegegrantoption) - * 5.2.8.111 [RQ.SRS-006.RBAC.Grant.Privilege.On](#rqsrs-006rbacgrantprivilegeon) - * 5.2.8.112 [RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns](#rqsrs-006rbacgrantprivilegeprivilegecolumns) - * 5.2.8.113 [RQ.SRS-006.RBAC.Grant.Privilege.OnCluster](#rqsrs-006rbacgrantprivilegeoncluster) - * 5.2.8.114 [RQ.SRS-006.RBAC.Grant.Privilege.Syntax](#rqsrs-006rbacgrantprivilegesyntax) - * 5.2.8.115 [RQ.SRS-006.RBAC.Revoke.Privilege.Cluster](#rqsrs-006rbacrevokeprivilegecluster) - * 5.2.8.116 [RQ.SRS-006.RBAC.Revoke.Privilege.Any](#rqsrs-006rbacrevokeprivilegeany) - * 5.2.8.117 [RQ.SRS-006.RBAC.Revoke.Privilege.Select](#rqsrs-006rbacrevokeprivilegeselect) - * 5.2.8.118 [RQ.SRS-006.RBAC.Revoke.Privilege.Insert](#rqsrs-006rbacrevokeprivilegeinsert) - * 5.2.8.119 [RQ.SRS-006.RBAC.Revoke.Privilege.Alter](#rqsrs-006rbacrevokeprivilegealter) - * 5.2.8.120 [RQ.SRS-006.RBAC.Revoke.Privilege.Create](#rqsrs-006rbacrevokeprivilegecreate) - * 5.2.8.121 [RQ.SRS-006.RBAC.Revoke.Privilege.Drop](#rqsrs-006rbacrevokeprivilegedrop) - * 5.2.8.122 [RQ.SRS-006.RBAC.Revoke.Privilege.Truncate](#rqsrs-006rbacrevokeprivilegetruncate) - * 5.2.8.123 [RQ.SRS-006.RBAC.Revoke.Privilege.Optimize](#rqsrs-006rbacrevokeprivilegeoptimize) - * 5.2.8.124 [RQ.SRS-006.RBAC.Revoke.Privilege.Show](#rqsrs-006rbacrevokeprivilegeshow) - * 5.2.8.125 [RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery](#rqsrs-006rbacrevokeprivilegekillquery) - * 5.2.8.126 [RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement](#rqsrs-006rbacrevokeprivilegeaccessmanagement) - * 5.2.8.127 [RQ.SRS-006.RBAC.Revoke.Privilege.System](#rqsrs-006rbacrevokeprivilegesystem) - * 5.2.8.128 [RQ.SRS-006.RBAC.Revoke.Privilege.Introspection](#rqsrs-006rbacrevokeprivilegeintrospection) - * 5.2.8.129 [RQ.SRS-006.RBAC.Revoke.Privilege.Sources](#rqsrs-006rbacrevokeprivilegesources) - * 5.2.8.130 [RQ.SRS-006.RBAC.Revoke.Privilege.DictGet](#rqsrs-006rbacrevokeprivilegedictget) - * 5.2.8.131 [RQ.SRS-006.RBAC.Revoke.Privilege.PrivelegeColumns](#rqsrs-006rbacrevokeprivilegeprivelegecolumns) - * 5.2.8.132 [RQ.SRS-006.RBAC.Revoke.Privilege.Multiple](#rqsrs-006rbacrevokeprivilegemultiple) - * 5.2.8.133 [RQ.SRS-006.RBAC.Revoke.Privilege.All](#rqsrs-006rbacrevokeprivilegeall) - * 5.2.8.134 [RQ.SRS-006.RBAC.Revoke.Privilege.None](#rqsrs-006rbacrevokeprivilegenone) - * 5.2.8.135 [RQ.SRS-006.RBAC.Revoke.Privilege.On](#rqsrs-006rbacrevokeprivilegeon) - * 5.2.8.136 [RQ.SRS-006.RBAC.Revoke.Privilege.From](#rqsrs-006rbacrevokeprivilegefrom) - * 5.2.8.137 [RQ.SRS-006.RBAC.Revoke.Privilege.Syntax](#rqsrs-006rbacrevokeprivilegesyntax) - * 5.2.8.138 [RQ.SRS-006.RBAC.PartialRevoke.Syntax](#rqsrs-006rbacpartialrevokesyntax) - * 5.2.8.139 [RQ.SRS-006.RBAC.Grant.Role](#rqsrs-006rbacgrantrole) - * 5.2.8.140 [RQ.SRS-006.RBAC.Grant.Role.CurrentUser](#rqsrs-006rbacgrantrolecurrentuser) - * 5.2.8.141 [RQ.SRS-006.RBAC.Grant.Role.AdminOption](#rqsrs-006rbacgrantroleadminoption) - * 5.2.8.142 [RQ.SRS-006.RBAC.Grant.Role.OnCluster](#rqsrs-006rbacgrantroleoncluster) - * 5.2.8.143 [RQ.SRS-006.RBAC.Grant.Role.Syntax](#rqsrs-006rbacgrantrolesyntax) - * 5.2.8.144 [RQ.SRS-006.RBAC.Revoke.Role](#rqsrs-006rbacrevokerole) - * 5.2.8.145 [RQ.SRS-006.RBAC.Revoke.Role.Keywords](#rqsrs-006rbacrevokerolekeywords) - * 5.2.8.146 [RQ.SRS-006.RBAC.Revoke.Role.Cluster](#rqsrs-006rbacrevokerolecluster) - * 5.2.8.147 [RQ.SRS-006.RBAC.Revoke.AdminOption](#rqsrs-006rbacrevokeadminoption) - * 5.2.8.148 [RQ.SRS-006.RBAC.Revoke.Role.Syntax](#rqsrs-006rbacrevokerolesyntax) - * 5.2.8.149 [RQ.SRS-006.RBAC.Show.Grants](#rqsrs-006rbacshowgrants) - * 5.2.8.150 [RQ.SRS-006.RBAC.Show.Grants.For](#rqsrs-006rbacshowgrantsfor) - * 5.2.8.151 [RQ.SRS-006.RBAC.Show.Grants.Syntax](#rqsrs-006rbacshowgrantssyntax) - * 5.2.8.152 [RQ.SRS-006.RBAC.SettingsProfile.Create](#rqsrs-006rbacsettingsprofilecreate) - * 5.2.8.153 [RQ.SRS-006.RBAC.SettingsProfile.Create.IfNotExists](#rqsrs-006rbacsettingsprofilecreateifnotexists) - * 5.2.8.154 [RQ.SRS-006.RBAC.SettingsProfile.Create.Replace](#rqsrs-006rbacsettingsprofilecreatereplace) - * 5.2.8.155 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables](#rqsrs-006rbacsettingsprofilecreatevariables) - * 5.2.8.156 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Value](#rqsrs-006rbacsettingsprofilecreatevariablesvalue) - * 5.2.8.157 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Constraints](#rqsrs-006rbacsettingsprofilecreatevariablesconstraints) - * 5.2.8.158 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment](#rqsrs-006rbacsettingsprofilecreateassignment) - * 5.2.8.159 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.None](#rqsrs-006rbacsettingsprofilecreateassignmentnone) - * 5.2.8.160 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.All](#rqsrs-006rbacsettingsprofilecreateassignmentall) - * 5.2.8.161 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.AllExcept](#rqsrs-006rbacsettingsprofilecreateassignmentallexcept) - * 5.2.8.162 [RQ.SRS-006.RBAC.SettingsProfile.Create.Inherit](#rqsrs-006rbacsettingsprofilecreateinherit) - * 5.2.8.163 [RQ.SRS-006.RBAC.SettingsProfile.Create.OnCluster](#rqsrs-006rbacsettingsprofilecreateoncluster) - * 5.2.8.164 [RQ.SRS-006.RBAC.SettingsProfile.Create.Syntax](#rqsrs-006rbacsettingsprofilecreatesyntax) - * 5.2.8.165 [RQ.SRS-006.RBAC.SettingsProfile.Alter](#rqsrs-006rbacsettingsprofilealter) - * 5.2.8.166 [RQ.SRS-006.RBAC.SettingsProfile.Alter.IfExists](#rqsrs-006rbacsettingsprofilealterifexists) - * 5.2.8.167 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Rename](#rqsrs-006rbacsettingsprofilealterrename) - * 5.2.8.168 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables](#rqsrs-006rbacsettingsprofilealtervariables) - * 5.2.8.169 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Value](#rqsrs-006rbacsettingsprofilealtervariablesvalue) - * 5.2.8.170 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Constraints](#rqsrs-006rbacsettingsprofilealtervariablesconstraints) - * 5.2.8.171 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment](#rqsrs-006rbacsettingsprofilealterassignment) - * 5.2.8.172 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.None](#rqsrs-006rbacsettingsprofilealterassignmentnone) - * 5.2.8.173 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.All](#rqsrs-006rbacsettingsprofilealterassignmentall) - * 5.2.8.174 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.AllExcept](#rqsrs-006rbacsettingsprofilealterassignmentallexcept) - * 5.2.8.175 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.Inherit](#rqsrs-006rbacsettingsprofilealterassignmentinherit) - * 5.2.8.176 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.OnCluster](#rqsrs-006rbacsettingsprofilealterassignmentoncluster) - * 5.2.8.177 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Syntax](#rqsrs-006rbacsettingsprofilealtersyntax) - * 5.2.8.178 [RQ.SRS-006.RBAC.SettingsProfile.Drop](#rqsrs-006rbacsettingsprofiledrop) - * 5.2.8.179 [RQ.SRS-006.RBAC.SettingsProfile.Drop.IfExists](#rqsrs-006rbacsettingsprofiledropifexists) - * 5.2.8.180 [RQ.SRS-006.RBAC.SettingsProfile.Drop.OnCluster](#rqsrs-006rbacsettingsprofiledroponcluster) - * 5.2.8.181 [RQ.SRS-006.RBAC.SettingsProfile.Drop.Syntax](#rqsrs-006rbacsettingsprofiledropsyntax) - * 5.2.8.182 [RQ.SRS-006.RBAC.SettingsProfile.ShowCreateSettingsProfile](#rqsrs-006rbacsettingsprofileshowcreatesettingsprofile) - * 5.2.8.183 [RQ.SRS-006.RBAC.Quota.Create](#rqsrs-006rbacquotacreate) - * 5.2.8.184 [RQ.SRS-006.RBAC.Quota.Create.IfNotExists](#rqsrs-006rbacquotacreateifnotexists) - * 5.2.8.185 [RQ.SRS-006.RBAC.Quota.Create.Replace](#rqsrs-006rbacquotacreatereplace) - * 5.2.8.186 [RQ.SRS-006.RBAC.Quota.Create.Cluster](#rqsrs-006rbacquotacreatecluster) - * 5.2.8.187 [RQ.SRS-006.RBAC.Quota.Create.Interval](#rqsrs-006rbacquotacreateinterval) - * 5.2.8.188 [RQ.SRS-006.RBAC.Quota.Create.Interval.Randomized](#rqsrs-006rbacquotacreateintervalrandomized) - * 5.2.8.189 [RQ.SRS-006.RBAC.Quota.Create.Queries](#rqsrs-006rbacquotacreatequeries) - * 5.2.8.190 [RQ.SRS-006.RBAC.Quota.Create.Errors](#rqsrs-006rbacquotacreateerrors) - * 5.2.8.191 [RQ.SRS-006.RBAC.Quota.Create.ResultRows](#rqsrs-006rbacquotacreateresultrows) - * 5.2.8.192 [RQ.SRS-006.RBAC.Quota.Create.ReadRows](#rqsrs-006rbacquotacreatereadrows) - * 5.2.8.193 [RQ.SRS-006.RBAC.Quota.Create.ResultBytes](#rqsrs-006rbacquotacreateresultbytes) - * 5.2.8.194 [RQ.SRS-006.RBAC.Quota.Create.ReadBytes](#rqsrs-006rbacquotacreatereadbytes) - * 5.2.8.195 [RQ.SRS-006.RBAC.Quota.Create.ExecutionTime](#rqsrs-006rbacquotacreateexecutiontime) - * 5.2.8.196 [RQ.SRS-006.RBAC.Quota.Create.NoLimits](#rqsrs-006rbacquotacreatenolimits) - * 5.2.8.197 [RQ.SRS-006.RBAC.Quota.Create.TrackingOnly](#rqsrs-006rbacquotacreatetrackingonly) - * 5.2.8.198 [RQ.SRS-006.RBAC.Quota.Create.KeyedBy](#rqsrs-006rbacquotacreatekeyedby) - * 5.2.8.199 [RQ.SRS-006.RBAC.Quota.Create.KeyedByOptions](#rqsrs-006rbacquotacreatekeyedbyoptions) - * 5.2.8.200 [RQ.SRS-006.RBAC.Quota.Create.Assignment](#rqsrs-006rbacquotacreateassignment) - * 5.2.8.201 [RQ.SRS-006.RBAC.Quota.Create.Assignment.None](#rqsrs-006rbacquotacreateassignmentnone) - * 5.2.8.202 [RQ.SRS-006.RBAC.Quota.Create.Assignment.All](#rqsrs-006rbacquotacreateassignmentall) - * 5.2.8.203 [RQ.SRS-006.RBAC.Quota.Create.Assignment.Except](#rqsrs-006rbacquotacreateassignmentexcept) - * 5.2.8.204 [RQ.SRS-006.RBAC.Quota.Create.Syntax](#rqsrs-006rbacquotacreatesyntax) - * 5.2.8.205 [RQ.SRS-006.RBAC.Quota.Alter](#rqsrs-006rbacquotaalter) - * 5.2.8.206 [RQ.SRS-006.RBAC.Quota.Alter.IfExists](#rqsrs-006rbacquotaalterifexists) - * 5.2.8.207 [RQ.SRS-006.RBAC.Quota.Alter.Rename](#rqsrs-006rbacquotaalterrename) - * 5.2.8.208 [RQ.SRS-006.RBAC.Quota.Alter.Cluster](#rqsrs-006rbacquotaaltercluster) - * 5.2.8.209 [RQ.SRS-006.RBAC.Quota.Alter.Interval](#rqsrs-006rbacquotaalterinterval) - * 5.2.8.210 [RQ.SRS-006.RBAC.Quota.Alter.Interval.Randomized](#rqsrs-006rbacquotaalterintervalrandomized) - * 5.2.8.211 [RQ.SRS-006.RBAC.Quota.Alter.Queries](#rqsrs-006rbacquotaalterqueries) - * 5.2.8.212 [RQ.SRS-006.RBAC.Quota.Alter.Errors](#rqsrs-006rbacquotaaltererrors) - * 5.2.8.213 [RQ.SRS-006.RBAC.Quota.Alter.ResultRows](#rqsrs-006rbacquotaalterresultrows) - * 5.2.8.214 [RQ.SRS-006.RBAC.Quota.Alter.ReadRows](#rqsrs-006rbacquotaalterreadrows) - * 5.2.8.215 [RQ.SRS-006.RBAC.Quota.ALter.ResultBytes](#rqsrs-006rbacquotaalterresultbytes) - * 5.2.8.216 [RQ.SRS-006.RBAC.Quota.Alter.ReadBytes](#rqsrs-006rbacquotaalterreadbytes) - * 5.2.8.217 [RQ.SRS-006.RBAC.Quota.Alter.ExecutionTime](#rqsrs-006rbacquotaalterexecutiontime) - * 5.2.8.218 [RQ.SRS-006.RBAC.Quota.Alter.NoLimits](#rqsrs-006rbacquotaalternolimits) - * 5.2.8.219 [RQ.SRS-006.RBAC.Quota.Alter.TrackingOnly](#rqsrs-006rbacquotaaltertrackingonly) - * 5.2.8.220 [RQ.SRS-006.RBAC.Quota.Alter.KeyedBy](#rqsrs-006rbacquotaalterkeyedby) - * 5.2.8.221 [RQ.SRS-006.RBAC.Quota.Alter.KeyedByOptions](#rqsrs-006rbacquotaalterkeyedbyoptions) - * 5.2.8.222 [RQ.SRS-006.RBAC.Quota.Alter.Assignment](#rqsrs-006rbacquotaalterassignment) - * 5.2.8.223 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.None](#rqsrs-006rbacquotaalterassignmentnone) - * 5.2.8.224 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.All](#rqsrs-006rbacquotaalterassignmentall) - * 5.2.8.225 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.Except](#rqsrs-006rbacquotaalterassignmentexcept) - * 5.2.8.226 [RQ.SRS-006.RBAC.Quota.Alter.Syntax](#rqsrs-006rbacquotaaltersyntax) - * 5.2.8.227 [RQ.SRS-006.RBAC.Quota.Drop](#rqsrs-006rbacquotadrop) - * 5.2.8.228 [RQ.SRS-006.RBAC.Quota.Drop.IfExists](#rqsrs-006rbacquotadropifexists) - * 5.2.8.229 [RQ.SRS-006.RBAC.Quota.Drop.Cluster](#rqsrs-006rbacquotadropcluster) - * 5.2.8.230 [RQ.SRS-006.RBAC.Quota.Drop.Syntax](#rqsrs-006rbacquotadropsyntax) - * 5.2.8.231 [RQ.SRS-006.RBAC.Quota.ShowQuotas](#rqsrs-006rbacquotashowquotas) - * 5.2.8.232 [RQ.SRS-006.RBAC.Quota.ShowQuotas.IntoOutfile](#rqsrs-006rbacquotashowquotasintooutfile) - * 5.2.8.233 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Format](#rqsrs-006rbacquotashowquotasformat) - * 5.2.8.234 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Settings](#rqsrs-006rbacquotashowquotassettings) - * 5.2.8.235 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Syntax](#rqsrs-006rbacquotashowquotassyntax) - * 5.2.8.236 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Name](#rqsrs-006rbacquotashowcreatequotaname) - * 5.2.8.237 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Current](#rqsrs-006rbacquotashowcreatequotacurrent) - * 5.2.8.238 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Syntax](#rqsrs-006rbacquotashowcreatequotasyntax) - * 5.2.8.239 [RQ.SRS-006.RBAC.RowPolicy.Create](#rqsrs-006rbacrowpolicycreate) - * 5.2.8.240 [RQ.SRS-006.RBAC.RowPolicy.Create.IfNotExists](#rqsrs-006rbacrowpolicycreateifnotexists) - * 5.2.8.241 [RQ.SRS-006.RBAC.RowPolicy.Create.Replace](#rqsrs-006rbacrowpolicycreatereplace) - * 5.2.8.242 [RQ.SRS-006.RBAC.RowPolicy.Create.OnCluster](#rqsrs-006rbacrowpolicycreateoncluster) - * 5.2.8.243 [RQ.SRS-006.RBAC.RowPolicy.Create.On](#rqsrs-006rbacrowpolicycreateon) - * 5.2.8.244 [RQ.SRS-006.RBAC.RowPolicy.Create.Access](#rqsrs-006rbacrowpolicycreateaccess) - * 5.2.8.245 [RQ.SRS-006.RBAC.RowPolicy.Create.Access.Permissive](#rqsrs-006rbacrowpolicycreateaccesspermissive) - * 5.2.8.246 [RQ.SRS-006.RBAC.RowPolicy.Create.Access.Restrictive](#rqsrs-006rbacrowpolicycreateaccessrestrictive) - * 5.2.8.247 [RQ.SRS-006.RBAC.RowPolicy.Create.ForSelect](#rqsrs-006rbacrowpolicycreateforselect) - * 5.2.8.248 [RQ.SRS-006.RBAC.RowPolicy.Create.Condition](#rqsrs-006rbacrowpolicycreatecondition) - * 5.2.8.249 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment](#rqsrs-006rbacrowpolicycreateassignment) - * 5.2.8.250 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.None](#rqsrs-006rbacrowpolicycreateassignmentnone) - * 5.2.8.251 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.All](#rqsrs-006rbacrowpolicycreateassignmentall) - * 5.2.8.252 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.AllExcept](#rqsrs-006rbacrowpolicycreateassignmentallexcept) - * 5.2.8.253 [RQ.SRS-006.RBAC.RowPolicy.Create.Syntax](#rqsrs-006rbacrowpolicycreatesyntax) - * 5.2.8.254 [RQ.SRS-006.RBAC.RowPolicy.Alter](#rqsrs-006rbacrowpolicyalter) - * 5.2.8.255 [RQ.SRS-006.RBAC.RowPolicy.Alter.IfExists](#rqsrs-006rbacrowpolicyalterifexists) - * 5.2.8.256 [RQ.SRS-006.RBAC.RowPolicy.Alter.ForSelect](#rqsrs-006rbacrowpolicyalterforselect) - * 5.2.8.257 [RQ.SRS-006.RBAC.RowPolicy.Alter.OnCluster](#rqsrs-006rbacrowpolicyalteroncluster) - * 5.2.8.258 [RQ.SRS-006.RBAC.RowPolicy.Alter.On](#rqsrs-006rbacrowpolicyalteron) - * 5.2.8.259 [RQ.SRS-006.RBAC.RowPolicy.Alter.Rename](#rqsrs-006rbacrowpolicyalterrename) - * 5.2.8.260 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access](#rqsrs-006rbacrowpolicyalteraccess) - * 5.2.8.261 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Permissive](#rqsrs-006rbacrowpolicyalteraccesspermissive) - * 5.2.8.262 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Restrictive](#rqsrs-006rbacrowpolicyalteraccessrestrictive) - * 5.2.8.263 [RQ.SRS-006.RBAC.RowPolicy.Alter.Condition](#rqsrs-006rbacrowpolicyaltercondition) - * 5.2.8.264 [RQ.SRS-006.RBAC.RowPolicy.Alter.Condition.None](#rqsrs-006rbacrowpolicyalterconditionnone) - * 5.2.8.265 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment](#rqsrs-006rbacrowpolicyalterassignment) - * 5.2.8.266 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.None](#rqsrs-006rbacrowpolicyalterassignmentnone) - * 5.2.8.267 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.All](#rqsrs-006rbacrowpolicyalterassignmentall) - * 5.2.8.268 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.AllExcept](#rqsrs-006rbacrowpolicyalterassignmentallexcept) - * 5.2.8.269 [RQ.SRS-006.RBAC.RowPolicy.Alter.Syntax](#rqsrs-006rbacrowpolicyaltersyntax) - * 5.2.8.270 [RQ.SRS-006.RBAC.RowPolicy.Drop](#rqsrs-006rbacrowpolicydrop) - * 5.2.8.271 [RQ.SRS-006.RBAC.RowPolicy.Drop.IfExists](#rqsrs-006rbacrowpolicydropifexists) - * 5.2.8.272 [RQ.SRS-006.RBAC.RowPolicy.Drop.On](#rqsrs-006rbacrowpolicydropon) - * 5.2.8.273 [RQ.SRS-006.RBAC.RowPolicy.Drop.OnCluster](#rqsrs-006rbacrowpolicydroponcluster) - * 5.2.8.274 [RQ.SRS-006.RBAC.RowPolicy.Drop.Syntax](#rqsrs-006rbacrowpolicydropsyntax) - * 5.2.8.275 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy](#rqsrs-006rbacrowpolicyshowcreaterowpolicy) - * 5.2.8.276 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.On](#rqsrs-006rbacrowpolicyshowcreaterowpolicyon) - * 5.2.8.277 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.Syntax](#rqsrs-006rbacrowpolicyshowcreaterowpolicysyntax) - * 5.2.8.278 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies](#rqsrs-006rbacrowpolicyshowrowpolicies) - * 5.2.8.279 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.On](#rqsrs-006rbacrowpolicyshowrowpolicieson) - * 5.2.8.280 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.Syntax](#rqsrs-006rbacrowpolicyshowrowpoliciessyntax) - * 5.2.9 [Table Privileges](#table-privileges) - * 5.2.9.1 [RQ.SRS-006.RBAC.Table.PublicTables](#rqsrs-006rbactablepublictables) - * 5.2.9.2 [RQ.SRS-006.RBAC.Table.SensitiveTables](#rqsrs-006rbactablesensitivetables) - * 5.2.10 [Distributed Tables](#distributed-tables) - * 5.2.10.1 [RQ.SRS-006.RBAC.DistributedTable.Create](#rqsrs-006rbacdistributedtablecreate) - * 5.2.10.2 [RQ.SRS-006.RBAC.DistributedTable.Select](#rqsrs-006rbacdistributedtableselect) - * 5.2.10.3 [RQ.SRS-006.RBAC.DistributedTable.Insert](#rqsrs-006rbacdistributedtableinsert) - * 5.2.10.4 [RQ.SRS-006.RBAC.DistributedTable.SpecialTables](#rqsrs-006rbacdistributedtablespecialtables) - * 5.2.10.5 [RQ.SRS-006.RBAC.DistributedTable.LocalUser](#rqsrs-006rbacdistributedtablelocaluser) - * 5.2.10.6 [RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges](#rqsrs-006rbacdistributedtablesameuserdifferentnodesdifferentprivileges) - * 5.2.11 [Views](#views) - * 5.2.11.1 [View](#view) - * 5.2.11.1.1 [RQ.SRS-006.RBAC.View](#rqsrs-006rbacview) - * 5.2.11.1.2 [RQ.SRS-006.RBAC.View.Create](#rqsrs-006rbacviewcreate) - * 5.2.11.1.3 [RQ.SRS-006.RBAC.View.Select](#rqsrs-006rbacviewselect) - * 5.2.11.1.4 [RQ.SRS-006.RBAC.View.Drop](#rqsrs-006rbacviewdrop) - * 5.2.11.2 [Materialized View](#materialized-view) - * 5.2.11.2.1 [RQ.SRS-006.RBAC.MaterializedView](#rqsrs-006rbacmaterializedview) - * 5.2.11.2.2 [RQ.SRS-006.RBAC.MaterializedView.Create](#rqsrs-006rbacmaterializedviewcreate) - * 5.2.11.2.3 [RQ.SRS-006.RBAC.MaterializedView.Select](#rqsrs-006rbacmaterializedviewselect) - * 5.2.11.2.4 [RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable](#rqsrs-006rbacmaterializedviewselecttargettable) - * 5.2.11.2.5 [RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable](#rqsrs-006rbacmaterializedviewselectsourcetable) - * 5.2.11.2.6 [RQ.SRS-006.RBAC.MaterializedView.Drop](#rqsrs-006rbacmaterializedviewdrop) - * 5.2.11.2.7 [RQ.SRS-006.RBAC.MaterializedView.ModifyQuery](#rqsrs-006rbacmaterializedviewmodifyquery) - * 5.2.11.2.8 [RQ.SRS-006.RBAC.MaterializedView.Insert](#rqsrs-006rbacmaterializedviewinsert) - * 5.2.11.2.9 [RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable](#rqsrs-006rbacmaterializedviewinsertsourcetable) - * 5.2.11.2.10 [RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable](#rqsrs-006rbacmaterializedviewinserttargettable) - * 5.2.11.3 [Live View](#live-view) - * 5.2.11.3.1 [RQ.SRS-006.RBAC.LiveView](#rqsrs-006rbacliveview) - * 5.2.11.3.2 [RQ.SRS-006.RBAC.LiveView.Create](#rqsrs-006rbacliveviewcreate) - * 5.2.11.3.3 [RQ.SRS-006.RBAC.LiveView.Select](#rqsrs-006rbacliveviewselect) - * 5.2.11.3.4 [RQ.SRS-006.RBAC.LiveView.Drop](#rqsrs-006rbacliveviewdrop) - * 5.2.11.3.5 [RQ.SRS-006.RBAC.LiveView.Refresh](#rqsrs-006rbacliveviewrefresh) - * 5.2.12 [Select](#select) - * 5.2.12.1 [RQ.SRS-006.RBAC.Select](#rqsrs-006rbacselect) - * 5.2.12.2 [RQ.SRS-006.RBAC.Select.Column](#rqsrs-006rbacselectcolumn) - * 5.2.12.3 [RQ.SRS-006.RBAC.Select.Cluster](#rqsrs-006rbacselectcluster) - * 5.2.12.4 [RQ.SRS-006.RBAC.Select.TableEngines](#rqsrs-006rbacselecttableengines) - * 5.2.13 [Insert](#insert) - * 5.2.13.1 [RQ.SRS-006.RBAC.Insert](#rqsrs-006rbacinsert) - * 5.2.13.2 [RQ.SRS-006.RBAC.Insert.Column](#rqsrs-006rbacinsertcolumn) - * 5.2.13.3 [RQ.SRS-006.RBAC.Insert.Cluster](#rqsrs-006rbacinsertcluster) - * 5.2.13.4 [RQ.SRS-006.RBAC.Insert.TableEngines](#rqsrs-006rbacinserttableengines) - * 5.2.14 [Alter](#alter) - * 5.2.14.1 [Alter Column](#alter-column) - * 5.2.14.1.1 [RQ.SRS-006.RBAC.Privileges.AlterColumn](#rqsrs-006rbacprivilegesaltercolumn) - * 5.2.14.1.2 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant](#rqsrs-006rbacprivilegesaltercolumngrant) - * 5.2.14.1.3 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke](#rqsrs-006rbacprivilegesaltercolumnrevoke) - * 5.2.14.1.4 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Column](#rqsrs-006rbacprivilegesaltercolumncolumn) - * 5.2.14.1.5 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster](#rqsrs-006rbacprivilegesaltercolumncluster) - * 5.2.14.1.6 [RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines](#rqsrs-006rbacprivilegesaltercolumntableengines) - * 5.2.14.2 [Alter Index](#alter-index) - * 5.2.14.2.1 [RQ.SRS-006.RBAC.Privileges.AlterIndex](#rqsrs-006rbacprivilegesalterindex) - * 5.2.14.2.2 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant](#rqsrs-006rbacprivilegesalterindexgrant) - * 5.2.14.2.3 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke](#rqsrs-006rbacprivilegesalterindexrevoke) - * 5.2.14.2.4 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster](#rqsrs-006rbacprivilegesalterindexcluster) - * 5.2.14.2.5 [RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines](#rqsrs-006rbacprivilegesalterindextableengines) - * 5.2.14.3 [Alter Constraint](#alter-constraint) - * 5.2.14.3.1 [RQ.SRS-006.RBAC.Privileges.AlterConstraint](#rqsrs-006rbacprivilegesalterconstraint) - * 5.2.14.3.2 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant](#rqsrs-006rbacprivilegesalterconstraintgrant) - * 5.2.14.3.3 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke](#rqsrs-006rbacprivilegesalterconstraintrevoke) - * 5.2.14.3.4 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster](#rqsrs-006rbacprivilegesalterconstraintcluster) - * 5.2.14.3.5 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines](#rqsrs-006rbacprivilegesalterconstrainttableengines) - * 5.2.14.4 [Alter TTL](#alter-ttl) - * 5.2.14.4.1 [RQ.SRS-006.RBAC.Privileges.AlterTTL](#rqsrs-006rbacprivilegesalterttl) - * 5.2.14.4.2 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant](#rqsrs-006rbacprivilegesalterttlgrant) - * 5.2.14.4.3 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke](#rqsrs-006rbacprivilegesalterttlrevoke) - * 5.2.14.4.4 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster](#rqsrs-006rbacprivilegesalterttlcluster) - * 5.2.14.4.5 [RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines](#rqsrs-006rbacprivilegesalterttltableengines) - * 5.2.14.5 [Alter Settings](#alter-settings) - * 5.2.14.5.1 [RQ.SRS-006.RBAC.Privileges.AlterSettings](#rqsrs-006rbacprivilegesaltersettings) - * 5.2.14.5.2 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant](#rqsrs-006rbacprivilegesaltersettingsgrant) - * 5.2.14.5.3 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke](#rqsrs-006rbacprivilegesaltersettingsrevoke) - * 5.2.14.5.4 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster](#rqsrs-006rbacprivilegesaltersettingscluster) - * 5.2.14.5.5 [RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines](#rqsrs-006rbacprivilegesaltersettingstableengines) - * 5.2.14.6 [Alter Update](#alter-update) - * 5.2.14.6.1 [RQ.SRS-006.RBAC.Privileges.AlterUpdate](#rqsrs-006rbacprivilegesalterupdate) - * 5.2.14.6.2 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant](#rqsrs-006rbacprivilegesalterupdategrant) - * 5.2.14.6.3 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke](#rqsrs-006rbacprivilegesalterupdaterevoke) - * 5.2.14.6.4 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines](#rqsrs-006rbacprivilegesalterupdatetableengines) - * 5.2.14.7 [Alter Delete](#alter-delete) - * 5.2.14.7.1 [RQ.SRS-006.RBAC.Privileges.AlterDelete](#rqsrs-006rbacprivilegesalterdelete) - * 5.2.14.7.2 [RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant](#rqsrs-006rbacprivilegesalterdeletegrant) - * 5.2.14.7.3 [RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke](#rqsrs-006rbacprivilegesalterdeleterevoke) - * 5.2.14.7.4 [RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines](#rqsrs-006rbacprivilegesalterdeletetableengines) - * 5.2.14.8 [Alter Freeze Partition](#alter-freeze-partition) - * 5.2.14.8.1 [RQ.SRS-006.RBAC.Privileges.AlterFreeze](#rqsrs-006rbacprivilegesalterfreeze) - * 5.2.14.8.2 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant](#rqsrs-006rbacprivilegesalterfreezegrant) - * 5.2.14.8.3 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke](#rqsrs-006rbacprivilegesalterfreezerevoke) - * 5.2.14.8.4 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines](#rqsrs-006rbacprivilegesalterfreezetableengines) - * 5.2.14.9 [Alter Fetch Partition](#alter-fetch-partition) - * 5.2.14.9.1 [RQ.SRS-006.RBAC.Privileges.AlterFetch](#rqsrs-006rbacprivilegesalterfetch) - * 5.2.14.9.2 [RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant](#rqsrs-006rbacprivilegesalterfetchgrant) - * 5.2.14.9.3 [RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke](#rqsrs-006rbacprivilegesalterfetchrevoke) - * 5.2.14.9.4 [RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines](#rqsrs-006rbacprivilegesalterfetchtableengines) - * 5.2.14.10 [Alter Move Partition](#alter-move-partition) - * 5.2.14.10.1 [RQ.SRS-006.RBAC.Privileges.AlterMove](#rqsrs-006rbacprivilegesaltermove) - * 5.2.14.10.2 [RQ.SRS-006.RBAC.Privileges.AlterMove.Grant](#rqsrs-006rbacprivilegesaltermovegrant) - * 5.2.14.10.3 [RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke](#rqsrs-006rbacprivilegesaltermoverevoke) - * 5.2.14.10.4 [RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines](#rqsrs-006rbacprivilegesaltermovetableengines) - * 5.2.15 [RQ.SRS-006.RBAC.Privileges.CreateTable](#rqsrs-006rbacprivilegescreatetable) - * 5.2.16 [RQ.SRS-006.RBAC.Privileges.CreateDatabase](#rqsrs-006rbacprivilegescreatedatabase) - * 5.2.17 [RQ.SRS-006.RBAC.Privileges.CreateDictionary](#rqsrs-006rbacprivilegescreatedictionary) - * 5.2.18 [RQ.SRS-006.RBAC.Privileges.CreateTemporaryTable](#rqsrs-006rbacprivilegescreatetemporarytable) - * 5.2.19 [RQ.SRS-006.RBAC.Privileges.AttachDatabase](#rqsrs-006rbacprivilegesattachdatabase) - * 5.2.20 [RQ.SRS-006.RBAC.Privileges.AttachDictionary](#rqsrs-006rbacprivilegesattachdictionary) - * 5.2.21 [RQ.SRS-006.RBAC.Privileges.AttachTemporaryTable](#rqsrs-006rbacprivilegesattachtemporarytable) - * 5.2.22 [RQ.SRS-006.RBAC.Privileges.AttachTable](#rqsrs-006rbacprivilegesattachtable) - * 5.2.23 [RQ.SRS-006.RBAC.Privileges.DropTable](#rqsrs-006rbacprivilegesdroptable) - * 5.2.24 [RQ.SRS-006.RBAC.Privileges.DropDatabase](#rqsrs-006rbacprivilegesdropdatabase) - * 5.2.25 [RQ.SRS-006.RBAC.Privileges.DropDictionary](#rqsrs-006rbacprivilegesdropdictionary) - * 5.2.26 [RQ.SRS-006.RBAC.Privileges.DetachTable](#rqsrs-006rbacprivilegesdetachtable) - * 5.2.27 [RQ.SRS-006.RBAC.Privileges.DetachView](#rqsrs-006rbacprivilegesdetachview) - * 5.2.28 [RQ.SRS-006.RBAC.Privileges.DetachDatabase](#rqsrs-006rbacprivilegesdetachdatabase) - * 5.2.29 [RQ.SRS-006.RBAC.Privileges.DetachDictionary](#rqsrs-006rbacprivilegesdetachdictionary) - * 5.2.30 [RQ.SRS-006.RBAC.Privileges.Truncate](#rqsrs-006rbacprivilegestruncate) - * 5.2.31 [RQ.SRS-006.RBAC.Privileges.Optimize](#rqsrs-006rbacprivilegesoptimize) - * 5.2.32 [RQ.SRS-006.RBAC.Privileges.KillQuery](#rqsrs-006rbacprivilegeskillquery) - * 5.2.33 [Kill Mutation](#kill-mutation) - * 5.2.33.1 [RQ.SRS-006.RBAC.Privileges.KillMutation](#rqsrs-006rbacprivilegeskillmutation) - * 5.2.33.2 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate](#rqsrs-006rbacprivilegeskillmutationalterupdate) - * 5.2.33.3 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete](#rqsrs-006rbacprivilegeskillmutationalterdelete) - * 5.2.33.4 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn](#rqsrs-006rbacprivilegeskillmutationalterdropcolumn) - * 5.2.34 [Show](#show) - * 5.2.34.1 [RQ.SRS-006.RBAC.ShowTables.Privilege](#rqsrs-006rbacshowtablesprivilege) - * 5.2.34.2 [RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege](#rqsrs-006rbacshowtablesrequiredprivilege) - * 5.2.34.3 [RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege](#rqsrs-006rbacexiststablerequiredprivilege) - * 5.2.34.4 [RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege](#rqsrs-006rbacchecktablerequiredprivilege) - * 5.2.34.5 [RQ.SRS-006.RBAC.ShowDatabases.Privilege](#rqsrs-006rbacshowdatabasesprivilege) - * 5.2.34.6 [RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege](#rqsrs-006rbacshowdatabasesrequiredprivilege) - * 5.2.34.7 [RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege](#rqsrs-006rbacshowcreatedatabaserequiredprivilege) - * 5.2.34.8 [RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege](#rqsrs-006rbacusedatabaserequiredprivilege) - * 5.2.34.9 [RQ.SRS-006.RBAC.ShowColumns.Privilege](#rqsrs-006rbacshowcolumnsprivilege) - * 5.2.34.10 [RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege](#rqsrs-006rbacshowcreatetablerequiredprivilege) - * 5.2.34.11 [RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege](#rqsrs-006rbacdescribetablerequiredprivilege) - * 5.2.34.12 [RQ.SRS-006.RBAC.ShowDictionaries.Privilege](#rqsrs-006rbacshowdictionariesprivilege) - * 5.2.34.13 [RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege](#rqsrs-006rbacshowdictionariesrequiredprivilege) - * 5.2.34.14 [RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege](#rqsrs-006rbacshowcreatedictionaryrequiredprivilege) - * 5.2.34.15 [RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege](#rqsrs-006rbacexistsdictionaryrequiredprivilege) - * 5.2.35 [Access Management](#access-management) - * 5.2.35.1 [RQ.SRS-006.RBAC.Privileges.CreateUser](#rqsrs-006rbacprivilegescreateuser) - * 5.2.35.2 [RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole](#rqsrs-006rbacprivilegescreateuserdefaultrole) - * 5.2.35.3 [RQ.SRS-006.RBAC.Privileges.AlterUser](#rqsrs-006rbacprivilegesalteruser) - * 5.2.35.4 [RQ.SRS-006.RBAC.Privileges.DropUser](#rqsrs-006rbacprivilegesdropuser) - * 5.2.35.5 [RQ.SRS-006.RBAC.Privileges.CreateRole](#rqsrs-006rbacprivilegescreaterole) - * 5.2.35.6 [RQ.SRS-006.RBAC.Privileges.AlterRole](#rqsrs-006rbacprivilegesalterrole) - * 5.2.35.7 [RQ.SRS-006.RBAC.Privileges.DropRole](#rqsrs-006rbacprivilegesdroprole) - * 5.2.35.8 [RQ.SRS-006.RBAC.Privileges.CreateRowPolicy](#rqsrs-006rbacprivilegescreaterowpolicy) - * 5.2.35.9 [RQ.SRS-006.RBAC.Privileges.AlterRowPolicy](#rqsrs-006rbacprivilegesalterrowpolicy) - * 5.2.35.10 [RQ.SRS-006.RBAC.Privileges.DropRowPolicy](#rqsrs-006rbacprivilegesdroprowpolicy) - * 5.2.35.11 [RQ.SRS-006.RBAC.Privileges.CreateQuota](#rqsrs-006rbacprivilegescreatequota) - * 5.2.35.12 [RQ.SRS-006.RBAC.Privileges.AlterQuota](#rqsrs-006rbacprivilegesalterquota) - * 5.2.35.13 [RQ.SRS-006.RBAC.Privileges.DropQuota](#rqsrs-006rbacprivilegesdropquota) - * 5.2.35.14 [RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile](#rqsrs-006rbacprivilegescreatesettingsprofile) - * 5.2.35.15 [RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile](#rqsrs-006rbacprivilegesaltersettingsprofile) - * 5.2.35.16 [RQ.SRS-006.RBAC.Privileges.DropSettingsProfile](#rqsrs-006rbacprivilegesdropsettingsprofile) - * 5.2.35.17 [RQ.SRS-006.RBAC.Privileges.RoleAdmin](#rqsrs-006rbacprivilegesroleadmin) - * 5.2.35.18 [Show Access](#show-access) - * 5.2.35.18.1 [RQ.SRS-006.RBAC.ShowUsers.Privilege](#rqsrs-006rbacshowusersprivilege) - * 5.2.35.18.2 [RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege](#rqsrs-006rbacshowusersrequiredprivilege) - * 5.2.35.18.3 [RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege](#rqsrs-006rbacshowcreateuserrequiredprivilege) - * 5.2.35.18.4 [RQ.SRS-006.RBAC.ShowRoles.Privilege](#rqsrs-006rbacshowrolesprivilege) - * 5.2.35.18.5 [RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege](#rqsrs-006rbacshowrolesrequiredprivilege) - * 5.2.35.18.6 [RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege](#rqsrs-006rbacshowcreaterolerequiredprivilege) - * 5.2.35.18.7 [RQ.SRS-006.RBAC.ShowRowPolicies.Privilege](#rqsrs-006rbacshowrowpoliciesprivilege) - * 5.2.35.18.8 [RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege](#rqsrs-006rbacshowrowpoliciesrequiredprivilege) - * 5.2.35.18.9 [RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege](#rqsrs-006rbacshowcreaterowpolicyrequiredprivilege) - * 5.2.35.18.10 [RQ.SRS-006.RBAC.ShowQuotas.Privilege](#rqsrs-006rbacshowquotasprivilege) - * 5.2.35.18.11 [RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege](#rqsrs-006rbacshowquotasrequiredprivilege) - * 5.2.35.18.12 [RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege](#rqsrs-006rbacshowcreatequotarequiredprivilege) - * 5.2.35.18.13 [RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege](#rqsrs-006rbacshowsettingsprofilesprivilege) - * 5.2.35.18.14 [RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege](#rqsrs-006rbacshowsettingsprofilesrequiredprivilege) - * 5.2.35.18.15 [RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege](#rqsrs-006rbacshowcreatesettingsprofilerequiredprivilege) - * 5.2.36 [dictGet](#dictget) - * 5.2.36.1 [RQ.SRS-006.RBAC.dictGet.Privilege](#rqsrs-006rbacdictgetprivilege) - * 5.2.36.2 [RQ.SRS-006.RBAC.dictGet.RequiredPrivilege](#rqsrs-006rbacdictgetrequiredprivilege) - * 5.2.36.3 [RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege](#rqsrs-006rbacdictgettyperequiredprivilege) - * 5.2.36.4 [RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege](#rqsrs-006rbacdictgetordefaultrequiredprivilege) - * 5.2.36.5 [RQ.SRS-006.RBAC.dictHas.RequiredPrivilege](#rqsrs-006rbacdicthasrequiredprivilege) - * 5.2.36.6 [RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege](#rqsrs-006rbacdictgethierarchyrequiredprivilege) - * 5.2.36.7 [RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege](#rqsrs-006rbacdictisinrequiredprivilege) - * 5.2.37 [Introspection](#introspection) - * 5.2.37.1 [RQ.SRS-006.RBAC.Privileges.Introspection](#rqsrs-006rbacprivilegesintrospection) - * 5.2.37.2 [RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine](#rqsrs-006rbacprivilegesintrospectionaddresstoline) - * 5.2.37.3 [RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol](#rqsrs-006rbacprivilegesintrospectionaddresstosymbol) - * 5.2.37.4 [RQ.SRS-006.RBAC.Privileges.Introspection.demangle](#rqsrs-006rbacprivilegesintrospectiondemangle) - * 5.2.38 [System](#system) - * 5.2.38.1 [RQ.SRS-006.RBAC.Privileges.System.Shutdown](#rqsrs-006rbacprivilegessystemshutdown) - * 5.2.38.2 [RQ.SRS-006.RBAC.Privileges.System.DropCache](#rqsrs-006rbacprivilegessystemdropcache) - * 5.2.38.3 [RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS](#rqsrs-006rbacprivilegessystemdropcachedns) - * 5.2.38.4 [RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark](#rqsrs-006rbacprivilegessystemdropcachemark) - * 5.2.38.5 [RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed](#rqsrs-006rbacprivilegessystemdropcacheuncompressed) - * 5.2.38.6 [RQ.SRS-006.RBAC.Privileges.System.Reload](#rqsrs-006rbacprivilegessystemreload) - * 5.2.38.7 [RQ.SRS-006.RBAC.Privileges.System.Reload.Config](#rqsrs-006rbacprivilegessystemreloadconfig) - * 5.2.38.8 [RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary](#rqsrs-006rbacprivilegessystemreloaddictionary) - * 5.2.38.9 [RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries](#rqsrs-006rbacprivilegessystemreloaddictionaries) - * 5.2.38.10 [RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries](#rqsrs-006rbacprivilegessystemreloadembeddeddictionaries) - * 5.2.38.11 [RQ.SRS-006.RBAC.Privileges.System.Merges](#rqsrs-006rbacprivilegessystemmerges) - * 5.2.38.12 [RQ.SRS-006.RBAC.Privileges.System.TTLMerges](#rqsrs-006rbacprivilegessystemttlmerges) - * 5.2.38.13 [RQ.SRS-006.RBAC.Privileges.System.Fetches](#rqsrs-006rbacprivilegessystemfetches) - * 5.2.38.14 [RQ.SRS-006.RBAC.Privileges.System.Moves](#rqsrs-006rbacprivilegessystemmoves) - * 5.2.38.15 [RQ.SRS-006.RBAC.Privileges.System.Sends](#rqsrs-006rbacprivilegessystemsends) - * 5.2.38.16 [RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed](#rqsrs-006rbacprivilegessystemsendsdistributed) - * 5.2.38.17 [RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated](#rqsrs-006rbacprivilegessystemsendsreplicated) - * 5.2.38.18 [RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues](#rqsrs-006rbacprivilegessystemreplicationqueues) - * 5.2.38.19 [RQ.SRS-006.RBAC.Privileges.System.SyncReplica](#rqsrs-006rbacprivilegessystemsyncreplica) - * 5.2.38.20 [RQ.SRS-006.RBAC.Privileges.System.RestartReplica](#rqsrs-006rbacprivilegessystemrestartreplica) - * 5.2.38.21 [RQ.SRS-006.RBAC.Privileges.System.Flush](#rqsrs-006rbacprivilegessystemflush) - * 5.2.38.22 [RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed](#rqsrs-006rbacprivilegessystemflushdistributed) - * 5.2.38.23 [RQ.SRS-006.RBAC.Privileges.System.Flush.Logs](#rqsrs-006rbacprivilegessystemflushlogs) - * 5.2.39 [Sources](#sources) - * 5.2.39.1 [RQ.SRS-006.RBAC.Privileges.Sources](#rqsrs-006rbacprivilegessources) - * 5.2.39.2 [RQ.SRS-006.RBAC.Privileges.Sources.File](#rqsrs-006rbacprivilegessourcesfile) - * 5.2.39.3 [RQ.SRS-006.RBAC.Privileges.Sources.URL](#rqsrs-006rbacprivilegessourcesurl) - * 5.2.39.4 [RQ.SRS-006.RBAC.Privileges.Sources.Remote](#rqsrs-006rbacprivilegessourcesremote) - * 5.2.39.5 [RQ.SRS-006.RBAC.Privileges.Sources.MySQL](#rqsrs-006rbacprivilegessourcesmysql) - * 5.2.39.6 [RQ.SRS-006.RBAC.Privileges.Sources.ODBC](#rqsrs-006rbacprivilegessourcesodbc) - * 5.2.39.7 [RQ.SRS-006.RBAC.Privileges.Sources.JDBC](#rqsrs-006rbacprivilegessourcesjdbc) - * 5.2.39.8 [RQ.SRS-006.RBAC.Privileges.Sources.HDFS](#rqsrs-006rbacprivilegessourceshdfs) - * 5.2.39.9 [RQ.SRS-006.RBAC.Privileges.Sources.S3](#rqsrs-006rbacprivilegessourcess3) - * 5.2.40 [RQ.SRS-006.RBAC.Privileges.GrantOption](#rqsrs-006rbacprivilegesgrantoption) - * 5.2.41 [RQ.SRS-006.RBAC.Privileges.All](#rqsrs-006rbacprivilegesall) - * 5.2.42 [RQ.SRS-006.RBAC.Privileges.AdminOption](#rqsrs-006rbacprivilegesadminoption) + * 5.2 [Login](#login) + * 5.2.1 [RQ.SRS-006.RBAC.Login](#rqsrs-006rbaclogin) + * 5.2.2 [RQ.SRS-006.RBAC.Login.DefaultUser](#rqsrs-006rbaclogindefaultuser) + * 5.3 [User](#user) + * 5.3.1 [RQ.SRS-006.RBAC.User](#rqsrs-006rbacuser) + * 5.3.2 [RQ.SRS-006.RBAC.User.Roles](#rqsrs-006rbacuserroles) + * 5.3.3 [RQ.SRS-006.RBAC.User.Privileges](#rqsrs-006rbacuserprivileges) + * 5.3.4 [RQ.SRS-006.RBAC.User.Variables](#rqsrs-006rbacuservariables) + * 5.3.5 [RQ.SRS-006.RBAC.User.Variables.Constraints](#rqsrs-006rbacuservariablesconstraints) + * 5.3.6 [RQ.SRS-006.RBAC.User.SettingsProfile](#rqsrs-006rbacusersettingsprofile) + * 5.3.7 [RQ.SRS-006.RBAC.User.Quotas](#rqsrs-006rbacuserquotas) + * 5.3.8 [RQ.SRS-006.RBAC.User.RowPolicies](#rqsrs-006rbacuserrowpolicies) + * 5.3.9 [RQ.SRS-006.RBAC.User.DefaultRole](#rqsrs-006rbacuserdefaultrole) + * 5.3.10 [RQ.SRS-006.RBAC.User.RoleSelection](#rqsrs-006rbacuserroleselection) + * 5.3.11 [RQ.SRS-006.RBAC.User.ShowCreate](#rqsrs-006rbacusershowcreate) + * 5.3.12 [RQ.SRS-006.RBAC.User.ShowPrivileges](#rqsrs-006rbacusershowprivileges) + * 5.3.13 [RQ.SRS-006.RBAC.User.Use.DefaultRole](#rqsrs-006rbacuserusedefaultrole) + * 5.3.14 [RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole](#rqsrs-006rbacuseruseallroleswhennodefaultrole) + * 5.3.15 [Create User](#create-user) + * 5.3.15.1 [RQ.SRS-006.RBAC.User.Create](#rqsrs-006rbacusercreate) + * 5.3.15.2 [RQ.SRS-006.RBAC.User.Create.IfNotExists](#rqsrs-006rbacusercreateifnotexists) + * 5.3.15.3 [RQ.SRS-006.RBAC.User.Create.Replace](#rqsrs-006rbacusercreatereplace) + * 5.3.15.4 [RQ.SRS-006.RBAC.User.Create.Password.NoPassword](#rqsrs-006rbacusercreatepasswordnopassword) + * 5.3.15.5 [RQ.SRS-006.RBAC.User.Create.Password.NoPassword.Login](#rqsrs-006rbacusercreatepasswordnopasswordlogin) + * 5.3.15.6 [RQ.SRS-006.RBAC.User.Create.Password.PlainText](#rqsrs-006rbacusercreatepasswordplaintext) + * 5.3.15.7 [RQ.SRS-006.RBAC.User.Create.Password.PlainText.Login](#rqsrs-006rbacusercreatepasswordplaintextlogin) + * 5.3.15.8 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Password](#rqsrs-006rbacusercreatepasswordsha256password) + * 5.3.15.9 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Password.Login](#rqsrs-006rbacusercreatepasswordsha256passwordlogin) + * 5.3.15.10 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash](#rqsrs-006rbacusercreatepasswordsha256hash) + * 5.3.15.11 [RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash.Login](#rqsrs-006rbacusercreatepasswordsha256hashlogin) + * 5.3.15.12 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password](#rqsrs-006rbacusercreatepassworddoublesha1password) + * 5.3.15.13 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password.Login](#rqsrs-006rbacusercreatepassworddoublesha1passwordlogin) + * 5.3.15.14 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash](#rqsrs-006rbacusercreatepassworddoublesha1hash) + * 5.3.15.15 [RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash.Login](#rqsrs-006rbacusercreatepassworddoublesha1hashlogin) + * 5.3.15.16 [RQ.SRS-006.RBAC.User.Create.Host.Name](#rqsrs-006rbacusercreatehostname) + * 5.3.15.17 [RQ.SRS-006.RBAC.User.Create.Host.Regexp](#rqsrs-006rbacusercreatehostregexp) + * 5.3.15.18 [RQ.SRS-006.RBAC.User.Create.Host.IP](#rqsrs-006rbacusercreatehostip) + * 5.3.15.19 [RQ.SRS-006.RBAC.User.Create.Host.Any](#rqsrs-006rbacusercreatehostany) + * 5.3.15.20 [RQ.SRS-006.RBAC.User.Create.Host.None](#rqsrs-006rbacusercreatehostnone) + * 5.3.15.21 [RQ.SRS-006.RBAC.User.Create.Host.Local](#rqsrs-006rbacusercreatehostlocal) + * 5.3.15.22 [RQ.SRS-006.RBAC.User.Create.Host.Like](#rqsrs-006rbacusercreatehostlike) + * 5.3.15.23 [RQ.SRS-006.RBAC.User.Create.Host.Default](#rqsrs-006rbacusercreatehostdefault) + * 5.3.15.24 [RQ.SRS-006.RBAC.User.Create.DefaultRole](#rqsrs-006rbacusercreatedefaultrole) + * 5.3.15.25 [RQ.SRS-006.RBAC.User.Create.DefaultRole.None](#rqsrs-006rbacusercreatedefaultrolenone) + * 5.3.15.26 [RQ.SRS-006.RBAC.User.Create.DefaultRole.All](#rqsrs-006rbacusercreatedefaultroleall) + * 5.3.15.27 [RQ.SRS-006.RBAC.User.Create.Settings](#rqsrs-006rbacusercreatesettings) + * 5.3.15.28 [RQ.SRS-006.RBAC.User.Create.OnCluster](#rqsrs-006rbacusercreateoncluster) + * 5.3.15.29 [RQ.SRS-006.RBAC.User.Create.Syntax](#rqsrs-006rbacusercreatesyntax) + * 5.3.16 [Alter User](#alter-user) + * 5.3.16.1 [RQ.SRS-006.RBAC.User.Alter](#rqsrs-006rbacuseralter) + * 5.3.16.2 [RQ.SRS-006.RBAC.User.Alter.OrderOfEvaluation](#rqsrs-006rbacuseralterorderofevaluation) + * 5.3.16.3 [RQ.SRS-006.RBAC.User.Alter.IfExists](#rqsrs-006rbacuseralterifexists) + * 5.3.16.4 [RQ.SRS-006.RBAC.User.Alter.Cluster](#rqsrs-006rbacuseraltercluster) + * 5.3.16.5 [RQ.SRS-006.RBAC.User.Alter.Rename](#rqsrs-006rbacuseralterrename) + * 5.3.16.6 [RQ.SRS-006.RBAC.User.Alter.Password.PlainText](#rqsrs-006rbacuseralterpasswordplaintext) + * 5.3.16.7 [RQ.SRS-006.RBAC.User.Alter.Password.Sha256Password](#rqsrs-006rbacuseralterpasswordsha256password) + * 5.3.16.8 [RQ.SRS-006.RBAC.User.Alter.Password.DoubleSha1Password](#rqsrs-006rbacuseralterpassworddoublesha1password) + * 5.3.16.9 [RQ.SRS-006.RBAC.User.Alter.Host.AddDrop](#rqsrs-006rbacuseralterhostadddrop) + * 5.3.16.10 [RQ.SRS-006.RBAC.User.Alter.Host.Local](#rqsrs-006rbacuseralterhostlocal) + * 5.3.16.11 [RQ.SRS-006.RBAC.User.Alter.Host.Name](#rqsrs-006rbacuseralterhostname) + * 5.3.16.12 [RQ.SRS-006.RBAC.User.Alter.Host.Regexp](#rqsrs-006rbacuseralterhostregexp) + * 5.3.16.13 [RQ.SRS-006.RBAC.User.Alter.Host.IP](#rqsrs-006rbacuseralterhostip) + * 5.3.16.14 [RQ.SRS-006.RBAC.User.Alter.Host.Like](#rqsrs-006rbacuseralterhostlike) + * 5.3.16.15 [RQ.SRS-006.RBAC.User.Alter.Host.Any](#rqsrs-006rbacuseralterhostany) + * 5.3.16.16 [RQ.SRS-006.RBAC.User.Alter.Host.None](#rqsrs-006rbacuseralterhostnone) + * 5.3.16.17 [RQ.SRS-006.RBAC.User.Alter.DefaultRole](#rqsrs-006rbacuseralterdefaultrole) + * 5.3.16.18 [RQ.SRS-006.RBAC.User.Alter.DefaultRole.All](#rqsrs-006rbacuseralterdefaultroleall) + * 5.3.16.19 [RQ.SRS-006.RBAC.User.Alter.DefaultRole.AllExcept](#rqsrs-006rbacuseralterdefaultroleallexcept) + * 5.3.16.20 [RQ.SRS-006.RBAC.User.Alter.Settings](#rqsrs-006rbacuseraltersettings) + * 5.3.16.21 [RQ.SRS-006.RBAC.User.Alter.Settings.Min](#rqsrs-006rbacuseraltersettingsmin) + * 5.3.16.22 [RQ.SRS-006.RBAC.User.Alter.Settings.Max](#rqsrs-006rbacuseraltersettingsmax) + * 5.3.16.23 [RQ.SRS-006.RBAC.User.Alter.Settings.Profile](#rqsrs-006rbacuseraltersettingsprofile) + * 5.3.16.24 [RQ.SRS-006.RBAC.User.Alter.Syntax](#rqsrs-006rbacuseraltersyntax) + * 5.3.17 [Show Create User](#show-create-user) + * 5.3.17.1 [RQ.SRS-006.RBAC.User.ShowCreateUser](#rqsrs-006rbacusershowcreateuser) + * 5.3.17.2 [RQ.SRS-006.RBAC.User.ShowCreateUser.For](#rqsrs-006rbacusershowcreateuserfor) + * 5.3.17.3 [RQ.SRS-006.RBAC.User.ShowCreateUser.Syntax](#rqsrs-006rbacusershowcreateusersyntax) + * 5.3.18 [Drop User](#drop-user) + * 5.3.18.1 [RQ.SRS-006.RBAC.User.Drop](#rqsrs-006rbacuserdrop) + * 5.3.18.2 [RQ.SRS-006.RBAC.User.Drop.IfExists](#rqsrs-006rbacuserdropifexists) + * 5.3.18.3 [RQ.SRS-006.RBAC.User.Drop.OnCluster](#rqsrs-006rbacuserdroponcluster) + * 5.3.18.4 [RQ.SRS-006.RBAC.User.Drop.Syntax](#rqsrs-006rbacuserdropsyntax) + * 5.4 [Role](#role) + * 5.4.1 [RQ.SRS-006.RBAC.Role](#rqsrs-006rbacrole) + * 5.4.2 [RQ.SRS-006.RBAC.Role.Privileges](#rqsrs-006rbacroleprivileges) + * 5.4.3 [RQ.SRS-006.RBAC.Role.Variables](#rqsrs-006rbacrolevariables) + * 5.4.4 [RQ.SRS-006.RBAC.Role.SettingsProfile](#rqsrs-006rbacrolesettingsprofile) + * 5.4.5 [RQ.SRS-006.RBAC.Role.Quotas](#rqsrs-006rbacrolequotas) + * 5.4.6 [RQ.SRS-006.RBAC.Role.RowPolicies](#rqsrs-006rbacrolerowpolicies) + * 5.4.7 [Create Role](#create-role) + * 5.4.7.1 [RQ.SRS-006.RBAC.Role.Create](#rqsrs-006rbacrolecreate) + * 5.4.7.2 [RQ.SRS-006.RBAC.Role.Create.IfNotExists](#rqsrs-006rbacrolecreateifnotexists) + * 5.4.7.3 [RQ.SRS-006.RBAC.Role.Create.Replace](#rqsrs-006rbacrolecreatereplace) + * 5.4.7.4 [RQ.SRS-006.RBAC.Role.Create.Settings](#rqsrs-006rbacrolecreatesettings) + * 5.4.7.5 [RQ.SRS-006.RBAC.Role.Create.Syntax](#rqsrs-006rbacrolecreatesyntax) + * 5.4.8 [Alter Role](#alter-role) + * 5.4.8.1 [RQ.SRS-006.RBAC.Role.Alter](#rqsrs-006rbacrolealter) + * 5.4.8.2 [RQ.SRS-006.RBAC.Role.Alter.IfExists](#rqsrs-006rbacrolealterifexists) + * 5.4.8.3 [RQ.SRS-006.RBAC.Role.Alter.Cluster](#rqsrs-006rbacrolealtercluster) + * 5.4.8.4 [RQ.SRS-006.RBAC.Role.Alter.Rename](#rqsrs-006rbacrolealterrename) + * 5.4.8.5 [RQ.SRS-006.RBAC.Role.Alter.Settings](#rqsrs-006rbacrolealtersettings) + * 5.4.8.6 [RQ.SRS-006.RBAC.Role.Alter.Syntax](#rqsrs-006rbacrolealtersyntax) + * 5.4.9 [Drop Role](#drop-role) + * 5.4.9.1 [RQ.SRS-006.RBAC.Role.Drop](#rqsrs-006rbacroledrop) + * 5.4.9.2 [RQ.SRS-006.RBAC.Role.Drop.IfExists](#rqsrs-006rbacroledropifexists) + * 5.4.9.3 [RQ.SRS-006.RBAC.Role.Drop.Cluster](#rqsrs-006rbacroledropcluster) + * 5.4.9.4 [RQ.SRS-006.RBAC.Role.Drop.Syntax](#rqsrs-006rbacroledropsyntax) + * 5.4.10 [Show Create Role](#show-create-role) + * 5.4.10.1 [RQ.SRS-006.RBAC.Role.ShowCreate](#rqsrs-006rbacroleshowcreate) + * 5.4.10.2 [RQ.SRS-006.RBAC.Role.ShowCreate.Syntax](#rqsrs-006rbacroleshowcreatesyntax) + * 5.5 [Partial Revokes](#partial-revokes) + * 5.5.1 [RQ.SRS-006.RBAC.PartialRevokes](#rqsrs-006rbacpartialrevokes) + * 5.5.2 [RQ.SRS-006.RBAC.PartialRevoke.Syntax](#rqsrs-006rbacpartialrevokesyntax) + * 5.6 [Settings Profile](#settings-profile) + * 5.6.1 [RQ.SRS-006.RBAC.SettingsProfile](#rqsrs-006rbacsettingsprofile) + * 5.6.2 [RQ.SRS-006.RBAC.SettingsProfile.Constraints](#rqsrs-006rbacsettingsprofileconstraints) + * 5.6.3 [Create Settings Profile](#create-settings-profile) + * 5.6.3.1 [RQ.SRS-006.RBAC.SettingsProfile.Create](#rqsrs-006rbacsettingsprofilecreate) + * 5.6.3.2 [RQ.SRS-006.RBAC.SettingsProfile.Create.IfNotExists](#rqsrs-006rbacsettingsprofilecreateifnotexists) + * 5.6.3.3 [RQ.SRS-006.RBAC.SettingsProfile.Create.Replace](#rqsrs-006rbacsettingsprofilecreatereplace) + * 5.6.3.4 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables](#rqsrs-006rbacsettingsprofilecreatevariables) + * 5.6.3.5 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Value](#rqsrs-006rbacsettingsprofilecreatevariablesvalue) + * 5.6.3.6 [RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Constraints](#rqsrs-006rbacsettingsprofilecreatevariablesconstraints) + * 5.6.3.7 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment](#rqsrs-006rbacsettingsprofilecreateassignment) + * 5.6.3.8 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.None](#rqsrs-006rbacsettingsprofilecreateassignmentnone) + * 5.6.3.9 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.All](#rqsrs-006rbacsettingsprofilecreateassignmentall) + * 5.6.3.10 [RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.AllExcept](#rqsrs-006rbacsettingsprofilecreateassignmentallexcept) + * 5.6.3.11 [RQ.SRS-006.RBAC.SettingsProfile.Create.Inherit](#rqsrs-006rbacsettingsprofilecreateinherit) + * 5.6.3.12 [RQ.SRS-006.RBAC.SettingsProfile.Create.OnCluster](#rqsrs-006rbacsettingsprofilecreateoncluster) + * 5.6.3.13 [RQ.SRS-006.RBAC.SettingsProfile.Create.Syntax](#rqsrs-006rbacsettingsprofilecreatesyntax) + * 5.6.4 [Alter Settings Profile](#alter-settings-profile) + * 5.6.4.1 [RQ.SRS-006.RBAC.SettingsProfile.Alter](#rqsrs-006rbacsettingsprofilealter) + * 5.6.4.2 [RQ.SRS-006.RBAC.SettingsProfile.Alter.IfExists](#rqsrs-006rbacsettingsprofilealterifexists) + * 5.6.4.3 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Rename](#rqsrs-006rbacsettingsprofilealterrename) + * 5.6.4.4 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables](#rqsrs-006rbacsettingsprofilealtervariables) + * 5.6.4.5 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Value](#rqsrs-006rbacsettingsprofilealtervariablesvalue) + * 5.6.4.6 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Constraints](#rqsrs-006rbacsettingsprofilealtervariablesconstraints) + * 5.6.4.7 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment](#rqsrs-006rbacsettingsprofilealterassignment) + * 5.6.4.8 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.None](#rqsrs-006rbacsettingsprofilealterassignmentnone) + * 5.6.4.9 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.All](#rqsrs-006rbacsettingsprofilealterassignmentall) + * 5.6.4.10 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.AllExcept](#rqsrs-006rbacsettingsprofilealterassignmentallexcept) + * 5.6.4.11 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.Inherit](#rqsrs-006rbacsettingsprofilealterassignmentinherit) + * 5.6.4.12 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.OnCluster](#rqsrs-006rbacsettingsprofilealterassignmentoncluster) + * 5.6.4.13 [RQ.SRS-006.RBAC.SettingsProfile.Alter.Syntax](#rqsrs-006rbacsettingsprofilealtersyntax) + * 5.6.5 [Drop Settings Profile](#drop-settings-profile) + * 5.6.5.1 [RQ.SRS-006.RBAC.SettingsProfile.Drop](#rqsrs-006rbacsettingsprofiledrop) + * 5.6.5.2 [RQ.SRS-006.RBAC.SettingsProfile.Drop.IfExists](#rqsrs-006rbacsettingsprofiledropifexists) + * 5.6.5.3 [RQ.SRS-006.RBAC.SettingsProfile.Drop.OnCluster](#rqsrs-006rbacsettingsprofiledroponcluster) + * 5.6.5.4 [RQ.SRS-006.RBAC.SettingsProfile.Drop.Syntax](#rqsrs-006rbacsettingsprofiledropsyntax) + * 5.6.6 [Show Create Settings Profile](#show-create-settings-profile) + * 5.6.6.1 [RQ.SRS-006.RBAC.SettingsProfile.ShowCreateSettingsProfile](#rqsrs-006rbacsettingsprofileshowcreatesettingsprofile) + * 5.7 [Quotas](#quotas) + * 5.7.1 [RQ.SRS-006.RBAC.Quotas](#rqsrs-006rbacquotas) + * 5.7.2 [RQ.SRS-006.RBAC.Quotas.Keyed](#rqsrs-006rbacquotaskeyed) + * 5.7.3 [RQ.SRS-006.RBAC.Quotas.Queries](#rqsrs-006rbacquotasqueries) + * 5.7.4 [RQ.SRS-006.RBAC.Quotas.Errors](#rqsrs-006rbacquotaserrors) + * 5.7.5 [RQ.SRS-006.RBAC.Quotas.ResultRows](#rqsrs-006rbacquotasresultrows) + * 5.7.6 [RQ.SRS-006.RBAC.Quotas.ReadRows](#rqsrs-006rbacquotasreadrows) + * 5.7.7 [RQ.SRS-006.RBAC.Quotas.ResultBytes](#rqsrs-006rbacquotasresultbytes) + * 5.7.8 [RQ.SRS-006.RBAC.Quotas.ReadBytes](#rqsrs-006rbacquotasreadbytes) + * 5.7.9 [RQ.SRS-006.RBAC.Quotas.ExecutionTime](#rqsrs-006rbacquotasexecutiontime) + * 5.7.10 [Create Quotas](#create-quotas) + * 5.7.10.1 [RQ.SRS-006.RBAC.Quota.Create](#rqsrs-006rbacquotacreate) + * 5.7.10.2 [RQ.SRS-006.RBAC.Quota.Create.IfNotExists](#rqsrs-006rbacquotacreateifnotexists) + * 5.7.10.3 [RQ.SRS-006.RBAC.Quota.Create.Replace](#rqsrs-006rbacquotacreatereplace) + * 5.7.10.4 [RQ.SRS-006.RBAC.Quota.Create.Cluster](#rqsrs-006rbacquotacreatecluster) + * 5.7.10.5 [RQ.SRS-006.RBAC.Quota.Create.Interval](#rqsrs-006rbacquotacreateinterval) + * 5.7.10.6 [RQ.SRS-006.RBAC.Quota.Create.Interval.Randomized](#rqsrs-006rbacquotacreateintervalrandomized) + * 5.7.10.7 [RQ.SRS-006.RBAC.Quota.Create.Queries](#rqsrs-006rbacquotacreatequeries) + * 5.7.10.8 [RQ.SRS-006.RBAC.Quota.Create.Errors](#rqsrs-006rbacquotacreateerrors) + * 5.7.10.9 [RQ.SRS-006.RBAC.Quota.Create.ResultRows](#rqsrs-006rbacquotacreateresultrows) + * 5.7.10.10 [RQ.SRS-006.RBAC.Quota.Create.ReadRows](#rqsrs-006rbacquotacreatereadrows) + * 5.7.10.11 [RQ.SRS-006.RBAC.Quota.Create.ResultBytes](#rqsrs-006rbacquotacreateresultbytes) + * 5.7.10.12 [RQ.SRS-006.RBAC.Quota.Create.ReadBytes](#rqsrs-006rbacquotacreatereadbytes) + * 5.7.10.13 [RQ.SRS-006.RBAC.Quota.Create.ExecutionTime](#rqsrs-006rbacquotacreateexecutiontime) + * 5.7.10.14 [RQ.SRS-006.RBAC.Quota.Create.NoLimits](#rqsrs-006rbacquotacreatenolimits) + * 5.7.10.15 [RQ.SRS-006.RBAC.Quota.Create.TrackingOnly](#rqsrs-006rbacquotacreatetrackingonly) + * 5.7.10.16 [RQ.SRS-006.RBAC.Quota.Create.KeyedBy](#rqsrs-006rbacquotacreatekeyedby) + * 5.7.10.17 [RQ.SRS-006.RBAC.Quota.Create.KeyedByOptions](#rqsrs-006rbacquotacreatekeyedbyoptions) + * 5.7.10.18 [RQ.SRS-006.RBAC.Quota.Create.Assignment](#rqsrs-006rbacquotacreateassignment) + * 5.7.10.19 [RQ.SRS-006.RBAC.Quota.Create.Assignment.None](#rqsrs-006rbacquotacreateassignmentnone) + * 5.7.10.20 [RQ.SRS-006.RBAC.Quota.Create.Assignment.All](#rqsrs-006rbacquotacreateassignmentall) + * 5.7.10.21 [RQ.SRS-006.RBAC.Quota.Create.Assignment.Except](#rqsrs-006rbacquotacreateassignmentexcept) + * 5.7.10.22 [RQ.SRS-006.RBAC.Quota.Create.Syntax](#rqsrs-006rbacquotacreatesyntax) + * 5.7.11 [Alter Quota](#alter-quota) + * 5.7.11.1 [RQ.SRS-006.RBAC.Quota.Alter](#rqsrs-006rbacquotaalter) + * 5.7.11.2 [RQ.SRS-006.RBAC.Quota.Alter.IfExists](#rqsrs-006rbacquotaalterifexists) + * 5.7.11.3 [RQ.SRS-006.RBAC.Quota.Alter.Rename](#rqsrs-006rbacquotaalterrename) + * 5.7.11.4 [RQ.SRS-006.RBAC.Quota.Alter.Cluster](#rqsrs-006rbacquotaaltercluster) + * 5.7.11.5 [RQ.SRS-006.RBAC.Quota.Alter.Interval](#rqsrs-006rbacquotaalterinterval) + * 5.7.11.6 [RQ.SRS-006.RBAC.Quota.Alter.Interval.Randomized](#rqsrs-006rbacquotaalterintervalrandomized) + * 5.7.11.7 [RQ.SRS-006.RBAC.Quota.Alter.Queries](#rqsrs-006rbacquotaalterqueries) + * 5.7.11.8 [RQ.SRS-006.RBAC.Quota.Alter.Errors](#rqsrs-006rbacquotaaltererrors) + * 5.7.11.9 [RQ.SRS-006.RBAC.Quota.Alter.ResultRows](#rqsrs-006rbacquotaalterresultrows) + * 5.7.11.10 [RQ.SRS-006.RBAC.Quota.Alter.ReadRows](#rqsrs-006rbacquotaalterreadrows) + * 5.7.11.11 [RQ.SRS-006.RBAC.Quota.ALter.ResultBytes](#rqsrs-006rbacquotaalterresultbytes) + * 5.7.11.12 [RQ.SRS-006.RBAC.Quota.Alter.ReadBytes](#rqsrs-006rbacquotaalterreadbytes) + * 5.7.11.13 [RQ.SRS-006.RBAC.Quota.Alter.ExecutionTime](#rqsrs-006rbacquotaalterexecutiontime) + * 5.7.11.14 [RQ.SRS-006.RBAC.Quota.Alter.NoLimits](#rqsrs-006rbacquotaalternolimits) + * 5.7.11.15 [RQ.SRS-006.RBAC.Quota.Alter.TrackingOnly](#rqsrs-006rbacquotaaltertrackingonly) + * 5.7.11.16 [RQ.SRS-006.RBAC.Quota.Alter.KeyedBy](#rqsrs-006rbacquotaalterkeyedby) + * 5.7.11.17 [RQ.SRS-006.RBAC.Quota.Alter.KeyedByOptions](#rqsrs-006rbacquotaalterkeyedbyoptions) + * 5.7.11.18 [RQ.SRS-006.RBAC.Quota.Alter.Assignment](#rqsrs-006rbacquotaalterassignment) + * 5.7.11.19 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.None](#rqsrs-006rbacquotaalterassignmentnone) + * 5.7.11.20 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.All](#rqsrs-006rbacquotaalterassignmentall) + * 5.7.11.21 [RQ.SRS-006.RBAC.Quota.Alter.Assignment.Except](#rqsrs-006rbacquotaalterassignmentexcept) + * 5.7.11.22 [RQ.SRS-006.RBAC.Quota.Alter.Syntax](#rqsrs-006rbacquotaaltersyntax) + * 5.7.12 [Drop Quota](#drop-quota) + * 5.7.12.1 [RQ.SRS-006.RBAC.Quota.Drop](#rqsrs-006rbacquotadrop) + * 5.7.12.2 [RQ.SRS-006.RBAC.Quota.Drop.IfExists](#rqsrs-006rbacquotadropifexists) + * 5.7.12.3 [RQ.SRS-006.RBAC.Quota.Drop.Cluster](#rqsrs-006rbacquotadropcluster) + * 5.7.12.4 [RQ.SRS-006.RBAC.Quota.Drop.Syntax](#rqsrs-006rbacquotadropsyntax) + * 5.7.13 [Show Quotas](#show-quotas) + * 5.7.13.1 [RQ.SRS-006.RBAC.Quota.ShowQuotas](#rqsrs-006rbacquotashowquotas) + * 5.7.13.2 [RQ.SRS-006.RBAC.Quota.ShowQuotas.IntoOutfile](#rqsrs-006rbacquotashowquotasintooutfile) + * 5.7.13.3 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Format](#rqsrs-006rbacquotashowquotasformat) + * 5.7.13.4 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Settings](#rqsrs-006rbacquotashowquotassettings) + * 5.7.13.5 [RQ.SRS-006.RBAC.Quota.ShowQuotas.Syntax](#rqsrs-006rbacquotashowquotassyntax) + * 5.7.14 [Show Create Quota](#show-create-quota) + * 5.7.14.1 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Name](#rqsrs-006rbacquotashowcreatequotaname) + * 5.7.14.2 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Current](#rqsrs-006rbacquotashowcreatequotacurrent) + * 5.7.14.3 [RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Syntax](#rqsrs-006rbacquotashowcreatequotasyntax) + * 5.8 [Row Policy](#row-policy) + * 5.8.1 [RQ.SRS-006.RBAC.RowPolicy](#rqsrs-006rbacrowpolicy) + * 5.8.2 [RQ.SRS-006.RBAC.RowPolicy.Condition](#rqsrs-006rbacrowpolicycondition) + * 5.8.3 [RQ.SRS-006.RBAC.RowPolicy.Restriction](#rqsrs-006rbacrowpolicyrestriction) + * 5.8.4 [RQ.SRS-006.RBAC.RowPolicy.Nesting](#rqsrs-006rbacrowpolicynesting) + * 5.8.5 [Create Row Policy](#create-row-policy) + * 5.8.5.1 [RQ.SRS-006.RBAC.RowPolicy.Create](#rqsrs-006rbacrowpolicycreate) + * 5.8.5.2 [RQ.SRS-006.RBAC.RowPolicy.Create.IfNotExists](#rqsrs-006rbacrowpolicycreateifnotexists) + * 5.8.5.3 [RQ.SRS-006.RBAC.RowPolicy.Create.Replace](#rqsrs-006rbacrowpolicycreatereplace) + * 5.8.5.4 [RQ.SRS-006.RBAC.RowPolicy.Create.OnCluster](#rqsrs-006rbacrowpolicycreateoncluster) + * 5.8.5.5 [RQ.SRS-006.RBAC.RowPolicy.Create.On](#rqsrs-006rbacrowpolicycreateon) + * 5.8.5.6 [RQ.SRS-006.RBAC.RowPolicy.Create.Access](#rqsrs-006rbacrowpolicycreateaccess) + * 5.8.5.7 [RQ.SRS-006.RBAC.RowPolicy.Create.Access.Permissive](#rqsrs-006rbacrowpolicycreateaccesspermissive) + * 5.8.5.8 [RQ.SRS-006.RBAC.RowPolicy.Create.Access.Restrictive](#rqsrs-006rbacrowpolicycreateaccessrestrictive) + * 5.8.5.9 [RQ.SRS-006.RBAC.RowPolicy.Create.ForSelect](#rqsrs-006rbacrowpolicycreateforselect) + * 5.8.5.10 [RQ.SRS-006.RBAC.RowPolicy.Create.Condition](#rqsrs-006rbacrowpolicycreatecondition) + * 5.8.5.11 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment](#rqsrs-006rbacrowpolicycreateassignment) + * 5.8.5.12 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.None](#rqsrs-006rbacrowpolicycreateassignmentnone) + * 5.8.5.13 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.All](#rqsrs-006rbacrowpolicycreateassignmentall) + * 5.8.5.14 [RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.AllExcept](#rqsrs-006rbacrowpolicycreateassignmentallexcept) + * 5.8.5.15 [RQ.SRS-006.RBAC.RowPolicy.Create.Syntax](#rqsrs-006rbacrowpolicycreatesyntax) + * 5.8.6 [Alter Row Policy](#alter-row-policy) + * 5.8.6.1 [RQ.SRS-006.RBAC.RowPolicy.Alter](#rqsrs-006rbacrowpolicyalter) + * 5.8.6.2 [RQ.SRS-006.RBAC.RowPolicy.Alter.IfExists](#rqsrs-006rbacrowpolicyalterifexists) + * 5.8.6.3 [RQ.SRS-006.RBAC.RowPolicy.Alter.ForSelect](#rqsrs-006rbacrowpolicyalterforselect) + * 5.8.6.4 [RQ.SRS-006.RBAC.RowPolicy.Alter.OnCluster](#rqsrs-006rbacrowpolicyalteroncluster) + * 5.8.6.5 [RQ.SRS-006.RBAC.RowPolicy.Alter.On](#rqsrs-006rbacrowpolicyalteron) + * 5.8.6.6 [RQ.SRS-006.RBAC.RowPolicy.Alter.Rename](#rqsrs-006rbacrowpolicyalterrename) + * 5.8.6.7 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access](#rqsrs-006rbacrowpolicyalteraccess) + * 5.8.6.8 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Permissive](#rqsrs-006rbacrowpolicyalteraccesspermissive) + * 5.8.6.9 [RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Restrictive](#rqsrs-006rbacrowpolicyalteraccessrestrictive) + * 5.8.6.10 [RQ.SRS-006.RBAC.RowPolicy.Alter.Condition](#rqsrs-006rbacrowpolicyaltercondition) + * 5.8.6.11 [RQ.SRS-006.RBAC.RowPolicy.Alter.Condition.None](#rqsrs-006rbacrowpolicyalterconditionnone) + * 5.8.6.12 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment](#rqsrs-006rbacrowpolicyalterassignment) + * 5.8.6.13 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.None](#rqsrs-006rbacrowpolicyalterassignmentnone) + * 5.8.6.14 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.All](#rqsrs-006rbacrowpolicyalterassignmentall) + * 5.8.6.15 [RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.AllExcept](#rqsrs-006rbacrowpolicyalterassignmentallexcept) + * 5.8.6.16 [RQ.SRS-006.RBAC.RowPolicy.Alter.Syntax](#rqsrs-006rbacrowpolicyaltersyntax) + * 5.8.7 [Drop Row Policy](#drop-row-policy) + * 5.8.7.1 [RQ.SRS-006.RBAC.RowPolicy.Drop](#rqsrs-006rbacrowpolicydrop) + * 5.8.7.2 [RQ.SRS-006.RBAC.RowPolicy.Drop.IfExists](#rqsrs-006rbacrowpolicydropifexists) + * 5.8.7.3 [RQ.SRS-006.RBAC.RowPolicy.Drop.On](#rqsrs-006rbacrowpolicydropon) + * 5.8.7.4 [RQ.SRS-006.RBAC.RowPolicy.Drop.OnCluster](#rqsrs-006rbacrowpolicydroponcluster) + * 5.8.7.5 [RQ.SRS-006.RBAC.RowPolicy.Drop.Syntax](#rqsrs-006rbacrowpolicydropsyntax) + * 5.8.8 [Show Create Row Policy](#show-create-row-policy) + * 5.8.8.1 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy](#rqsrs-006rbacrowpolicyshowcreaterowpolicy) + * 5.8.8.2 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.On](#rqsrs-006rbacrowpolicyshowcreaterowpolicyon) + * 5.8.8.3 [RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.Syntax](#rqsrs-006rbacrowpolicyshowcreaterowpolicysyntax) + * 5.8.8.4 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies](#rqsrs-006rbacrowpolicyshowrowpolicies) + * 5.8.8.5 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.On](#rqsrs-006rbacrowpolicyshowrowpolicieson) + * 5.8.8.6 [RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.Syntax](#rqsrs-006rbacrowpolicyshowrowpoliciessyntax) + * 5.9 [Set Default Role](#set-default-role) + * 5.9.1 [RQ.SRS-006.RBAC.SetDefaultRole](#rqsrs-006rbacsetdefaultrole) + * 5.9.2 [RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser](#rqsrs-006rbacsetdefaultrolecurrentuser) + * 5.9.3 [RQ.SRS-006.RBAC.SetDefaultRole.All](#rqsrs-006rbacsetdefaultroleall) + * 5.9.4 [RQ.SRS-006.RBAC.SetDefaultRole.AllExcept](#rqsrs-006rbacsetdefaultroleallexcept) + * 5.9.5 [RQ.SRS-006.RBAC.SetDefaultRole.None](#rqsrs-006rbacsetdefaultrolenone) + * 5.9.6 [RQ.SRS-006.RBAC.SetDefaultRole.Syntax](#rqsrs-006rbacsetdefaultrolesyntax) + * 5.10 [Set Role](#set-role) + * 5.10.1 [RQ.SRS-006.RBAC.SetRole](#rqsrs-006rbacsetrole) + * 5.10.2 [RQ.SRS-006.RBAC.SetRole.Default](#rqsrs-006rbacsetroledefault) + * 5.10.3 [RQ.SRS-006.RBAC.SetRole.None](#rqsrs-006rbacsetrolenone) + * 5.10.4 [RQ.SRS-006.RBAC.SetRole.All](#rqsrs-006rbacsetroleall) + * 5.10.5 [RQ.SRS-006.RBAC.SetRole.AllExcept](#rqsrs-006rbacsetroleallexcept) + * 5.10.6 [RQ.SRS-006.RBAC.SetRole.Syntax](#rqsrs-006rbacsetrolesyntax) + * 5.11 [Grant](#grant) + * 5.11.1 [RQ.SRS-006.RBAC.Grant.Privilege.To](#rqsrs-006rbacgrantprivilegeto) + * 5.11.2 [RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser](#rqsrs-006rbacgrantprivilegetocurrentuser) + * 5.11.3 [RQ.SRS-006.RBAC.Grant.Privilege.Select](#rqsrs-006rbacgrantprivilegeselect) + * 5.11.4 [RQ.SRS-006.RBAC.Grant.Privilege.Insert](#rqsrs-006rbacgrantprivilegeinsert) + * 5.11.5 [RQ.SRS-006.RBAC.Grant.Privilege.Alter](#rqsrs-006rbacgrantprivilegealter) + * 5.11.6 [RQ.SRS-006.RBAC.Grant.Privilege.Create](#rqsrs-006rbacgrantprivilegecreate) + * 5.11.7 [RQ.SRS-006.RBAC.Grant.Privilege.Drop](#rqsrs-006rbacgrantprivilegedrop) + * 5.11.8 [RQ.SRS-006.RBAC.Grant.Privilege.Truncate](#rqsrs-006rbacgrantprivilegetruncate) + * 5.11.9 [RQ.SRS-006.RBAC.Grant.Privilege.Optimize](#rqsrs-006rbacgrantprivilegeoptimize) + * 5.11.10 [RQ.SRS-006.RBAC.Grant.Privilege.Show](#rqsrs-006rbacgrantprivilegeshow) + * 5.11.11 [RQ.SRS-006.RBAC.Grant.Privilege.KillQuery](#rqsrs-006rbacgrantprivilegekillquery) + * 5.11.12 [RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement](#rqsrs-006rbacgrantprivilegeaccessmanagement) + * 5.11.13 [RQ.SRS-006.RBAC.Grant.Privilege.System](#rqsrs-006rbacgrantprivilegesystem) + * 5.11.14 [RQ.SRS-006.RBAC.Grant.Privilege.Introspection](#rqsrs-006rbacgrantprivilegeintrospection) + * 5.11.15 [RQ.SRS-006.RBAC.Grant.Privilege.Sources](#rqsrs-006rbacgrantprivilegesources) + * 5.11.16 [RQ.SRS-006.RBAC.Grant.Privilege.DictGet](#rqsrs-006rbacgrantprivilegedictget) + * 5.11.17 [RQ.SRS-006.RBAC.Grant.Privilege.None](#rqsrs-006rbacgrantprivilegenone) + * 5.11.18 [RQ.SRS-006.RBAC.Grant.Privilege.All](#rqsrs-006rbacgrantprivilegeall) + * 5.11.19 [RQ.SRS-006.RBAC.Grant.Privilege.GrantOption](#rqsrs-006rbacgrantprivilegegrantoption) + * 5.11.20 [RQ.SRS-006.RBAC.Grant.Privilege.On](#rqsrs-006rbacgrantprivilegeon) + * 5.11.21 [RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns](#rqsrs-006rbacgrantprivilegeprivilegecolumns) + * 5.11.22 [RQ.SRS-006.RBAC.Grant.Privilege.OnCluster](#rqsrs-006rbacgrantprivilegeoncluster) + * 5.11.23 [RQ.SRS-006.RBAC.Grant.Privilege.Syntax](#rqsrs-006rbacgrantprivilegesyntax) + * 5.12 [Revoke](#revoke) + * 5.12.1 [RQ.SRS-006.RBAC.Revoke.Privilege.Cluster](#rqsrs-006rbacrevokeprivilegecluster) + * 5.12.2 [RQ.SRS-006.RBAC.Revoke.Privilege.Select](#rqsrs-006rbacrevokeprivilegeselect) + * 5.12.3 [RQ.SRS-006.RBAC.Revoke.Privilege.Insert](#rqsrs-006rbacrevokeprivilegeinsert) + * 5.12.4 [RQ.SRS-006.RBAC.Revoke.Privilege.Alter](#rqsrs-006rbacrevokeprivilegealter) + * 5.12.5 [RQ.SRS-006.RBAC.Revoke.Privilege.Create](#rqsrs-006rbacrevokeprivilegecreate) + * 5.12.6 [RQ.SRS-006.RBAC.Revoke.Privilege.Drop](#rqsrs-006rbacrevokeprivilegedrop) + * 5.12.7 [RQ.SRS-006.RBAC.Revoke.Privilege.Truncate](#rqsrs-006rbacrevokeprivilegetruncate) + * 5.12.8 [RQ.SRS-006.RBAC.Revoke.Privilege.Optimize](#rqsrs-006rbacrevokeprivilegeoptimize) + * 5.12.9 [RQ.SRS-006.RBAC.Revoke.Privilege.Show](#rqsrs-006rbacrevokeprivilegeshow) + * 5.12.10 [RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery](#rqsrs-006rbacrevokeprivilegekillquery) + * 5.12.11 [RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement](#rqsrs-006rbacrevokeprivilegeaccessmanagement) + * 5.12.12 [RQ.SRS-006.RBAC.Revoke.Privilege.System](#rqsrs-006rbacrevokeprivilegesystem) + * 5.12.13 [RQ.SRS-006.RBAC.Revoke.Privilege.Introspection](#rqsrs-006rbacrevokeprivilegeintrospection) + * 5.12.14 [RQ.SRS-006.RBAC.Revoke.Privilege.Sources](#rqsrs-006rbacrevokeprivilegesources) + * 5.12.15 [RQ.SRS-006.RBAC.Revoke.Privilege.DictGet](#rqsrs-006rbacrevokeprivilegedictget) + * 5.12.16 [RQ.SRS-006.RBAC.Revoke.Privilege.PrivilegeColumns](#rqsrs-006rbacrevokeprivilegeprivilegecolumns) + * 5.12.17 [RQ.SRS-006.RBAC.Revoke.Privilege.Multiple](#rqsrs-006rbacrevokeprivilegemultiple) + * 5.12.18 [RQ.SRS-006.RBAC.Revoke.Privilege.All](#rqsrs-006rbacrevokeprivilegeall) + * 5.12.19 [RQ.SRS-006.RBAC.Revoke.Privilege.None](#rqsrs-006rbacrevokeprivilegenone) + * 5.12.20 [RQ.SRS-006.RBAC.Revoke.Privilege.On](#rqsrs-006rbacrevokeprivilegeon) + * 5.12.21 [RQ.SRS-006.RBAC.Revoke.Privilege.From](#rqsrs-006rbacrevokeprivilegefrom) + * 5.12.22 [RQ.SRS-006.RBAC.Revoke.Privilege.Syntax](#rqsrs-006rbacrevokeprivilegesyntax) + * 5.13 [Grant Role](#grant-role) + * 5.13.1 [RQ.SRS-006.RBAC.Grant.Role](#rqsrs-006rbacgrantrole) + * 5.13.2 [RQ.SRS-006.RBAC.Grant.Role.CurrentUser](#rqsrs-006rbacgrantrolecurrentuser) + * 5.13.3 [RQ.SRS-006.RBAC.Grant.Role.AdminOption](#rqsrs-006rbacgrantroleadminoption) + * 5.13.4 [RQ.SRS-006.RBAC.Grant.Role.OnCluster](#rqsrs-006rbacgrantroleoncluster) + * 5.13.5 [RQ.SRS-006.RBAC.Grant.Role.Syntax](#rqsrs-006rbacgrantrolesyntax) + * 5.14 [Revoke Role](#revoke-role) + * 5.14.1 [RQ.SRS-006.RBAC.Revoke.Role](#rqsrs-006rbacrevokerole) + * 5.14.2 [RQ.SRS-006.RBAC.Revoke.Role.Keywords](#rqsrs-006rbacrevokerolekeywords) + * 5.14.3 [RQ.SRS-006.RBAC.Revoke.Role.Cluster](#rqsrs-006rbacrevokerolecluster) + * 5.14.4 [RQ.SRS-006.RBAC.Revoke.AdminOption](#rqsrs-006rbacrevokeadminoption) + * 5.14.5 [RQ.SRS-006.RBAC.Revoke.Role.Syntax](#rqsrs-006rbacrevokerolesyntax) + * 5.15 [Show Grants](#show-grants) + * 5.15.1 [RQ.SRS-006.RBAC.Show.Grants](#rqsrs-006rbacshowgrants) + * 5.15.2 [RQ.SRS-006.RBAC.Show.Grants.For](#rqsrs-006rbacshowgrantsfor) + * 5.15.3 [RQ.SRS-006.RBAC.Show.Grants.Syntax](#rqsrs-006rbacshowgrantssyntax) + * 5.16 [Table Privileges](#table-privileges) + * 5.16.1 [RQ.SRS-006.RBAC.Table.PublicTables](#rqsrs-006rbactablepublictables) + * 5.16.2 [RQ.SRS-006.RBAC.Table.SensitiveTables](#rqsrs-006rbactablesensitivetables) + * 5.17 [Distributed Tables](#distributed-tables) + * 5.17.1 [RQ.SRS-006.RBAC.DistributedTable.Create](#rqsrs-006rbacdistributedtablecreate) + * 5.17.2 [RQ.SRS-006.RBAC.DistributedTable.Select](#rqsrs-006rbacdistributedtableselect) + * 5.17.3 [RQ.SRS-006.RBAC.DistributedTable.Insert](#rqsrs-006rbacdistributedtableinsert) + * 5.17.4 [RQ.SRS-006.RBAC.DistributedTable.SpecialTables](#rqsrs-006rbacdistributedtablespecialtables) + * 5.17.5 [RQ.SRS-006.RBAC.DistributedTable.LocalUser](#rqsrs-006rbacdistributedtablelocaluser) + * 5.17.6 [RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges](#rqsrs-006rbacdistributedtablesameuserdifferentnodesdifferentprivileges) + * 5.18 [Views](#views) + * 5.18.1 [View](#view) + * 5.18.1.1 [RQ.SRS-006.RBAC.View](#rqsrs-006rbacview) + * 5.18.1.2 [RQ.SRS-006.RBAC.View.Create](#rqsrs-006rbacviewcreate) + * 5.18.1.3 [RQ.SRS-006.RBAC.View.Select](#rqsrs-006rbacviewselect) + * 5.18.1.4 [RQ.SRS-006.RBAC.View.Drop](#rqsrs-006rbacviewdrop) + * 5.18.2 [Materialized View](#materialized-view) + * 5.18.2.1 [RQ.SRS-006.RBAC.MaterializedView](#rqsrs-006rbacmaterializedview) + * 5.18.2.2 [RQ.SRS-006.RBAC.MaterializedView.Create](#rqsrs-006rbacmaterializedviewcreate) + * 5.18.2.3 [RQ.SRS-006.RBAC.MaterializedView.Select](#rqsrs-006rbacmaterializedviewselect) + * 5.18.2.4 [RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable](#rqsrs-006rbacmaterializedviewselecttargettable) + * 5.18.2.5 [RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable](#rqsrs-006rbacmaterializedviewselectsourcetable) + * 5.18.2.6 [RQ.SRS-006.RBAC.MaterializedView.Drop](#rqsrs-006rbacmaterializedviewdrop) + * 5.18.2.7 [RQ.SRS-006.RBAC.MaterializedView.ModifyQuery](#rqsrs-006rbacmaterializedviewmodifyquery) + * 5.18.2.8 [RQ.SRS-006.RBAC.MaterializedView.Insert](#rqsrs-006rbacmaterializedviewinsert) + * 5.18.2.9 [RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable](#rqsrs-006rbacmaterializedviewinsertsourcetable) + * 5.18.2.10 [RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable](#rqsrs-006rbacmaterializedviewinserttargettable) + * 5.18.3 [Live View](#live-view) + * 5.18.3.1 [RQ.SRS-006.RBAC.LiveView](#rqsrs-006rbacliveview) + * 5.18.3.2 [RQ.SRS-006.RBAC.LiveView.Create](#rqsrs-006rbacliveviewcreate) + * 5.18.3.3 [RQ.SRS-006.RBAC.LiveView.Select](#rqsrs-006rbacliveviewselect) + * 5.18.3.4 [RQ.SRS-006.RBAC.LiveView.Drop](#rqsrs-006rbacliveviewdrop) + * 5.18.3.5 [RQ.SRS-006.RBAC.LiveView.Refresh](#rqsrs-006rbacliveviewrefresh) + * 5.19 [Select](#select) + * 5.19.1 [RQ.SRS-006.RBAC.Select](#rqsrs-006rbacselect) + * 5.19.2 [RQ.SRS-006.RBAC.Select.Column](#rqsrs-006rbacselectcolumn) + * 5.19.3 [RQ.SRS-006.RBAC.Select.Cluster](#rqsrs-006rbacselectcluster) + * 5.19.4 [RQ.SRS-006.RBAC.Select.TableEngines](#rqsrs-006rbacselecttableengines) + * 5.20 [Insert](#insert) + * 5.20.1 [RQ.SRS-006.RBAC.Insert](#rqsrs-006rbacinsert) + * 5.20.2 [RQ.SRS-006.RBAC.Insert.Column](#rqsrs-006rbacinsertcolumn) + * 5.20.3 [RQ.SRS-006.RBAC.Insert.Cluster](#rqsrs-006rbacinsertcluster) + * 5.20.4 [RQ.SRS-006.RBAC.Insert.TableEngines](#rqsrs-006rbacinserttableengines) + * 5.21 [Alter](#alter) + * 5.21.1 [Alter Column](#alter-column) + * 5.21.1.1 [RQ.SRS-006.RBAC.Privileges.AlterColumn](#rqsrs-006rbacprivilegesaltercolumn) + * 5.21.1.2 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant](#rqsrs-006rbacprivilegesaltercolumngrant) + * 5.21.1.3 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke](#rqsrs-006rbacprivilegesaltercolumnrevoke) + * 5.21.1.4 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Column](#rqsrs-006rbacprivilegesaltercolumncolumn) + * 5.21.1.5 [RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster](#rqsrs-006rbacprivilegesaltercolumncluster) + * 5.21.1.6 [RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines](#rqsrs-006rbacprivilegesaltercolumntableengines) + * 5.21.2 [Alter Index](#alter-index) + * 5.21.2.1 [RQ.SRS-006.RBAC.Privileges.AlterIndex](#rqsrs-006rbacprivilegesalterindex) + * 5.21.2.2 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant](#rqsrs-006rbacprivilegesalterindexgrant) + * 5.21.2.3 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke](#rqsrs-006rbacprivilegesalterindexrevoke) + * 5.21.2.4 [RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster](#rqsrs-006rbacprivilegesalterindexcluster) + * 5.21.2.5 [RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines](#rqsrs-006rbacprivilegesalterindextableengines) + * 5.21.3 [Alter Constraint](#alter-constraint) + * 5.21.3.1 [RQ.SRS-006.RBAC.Privileges.AlterConstraint](#rqsrs-006rbacprivilegesalterconstraint) + * 5.21.3.2 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant](#rqsrs-006rbacprivilegesalterconstraintgrant) + * 5.21.3.3 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke](#rqsrs-006rbacprivilegesalterconstraintrevoke) + * 5.21.3.4 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster](#rqsrs-006rbacprivilegesalterconstraintcluster) + * 5.21.3.5 [RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines](#rqsrs-006rbacprivilegesalterconstrainttableengines) + * 5.21.4 [Alter TTL](#alter-ttl) + * 5.21.4.1 [RQ.SRS-006.RBAC.Privileges.AlterTTL](#rqsrs-006rbacprivilegesalterttl) + * 5.21.4.2 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant](#rqsrs-006rbacprivilegesalterttlgrant) + * 5.21.4.3 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke](#rqsrs-006rbacprivilegesalterttlrevoke) + * 5.21.4.4 [RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster](#rqsrs-006rbacprivilegesalterttlcluster) + * 5.21.4.5 [RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines](#rqsrs-006rbacprivilegesalterttltableengines) + * 5.21.5 [Alter Settings](#alter-settings) + * 5.21.5.1 [RQ.SRS-006.RBAC.Privileges.AlterSettings](#rqsrs-006rbacprivilegesaltersettings) + * 5.21.5.2 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant](#rqsrs-006rbacprivilegesaltersettingsgrant) + * 5.21.5.3 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke](#rqsrs-006rbacprivilegesaltersettingsrevoke) + * 5.21.5.4 [RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster](#rqsrs-006rbacprivilegesaltersettingscluster) + * 5.21.5.5 [RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines](#rqsrs-006rbacprivilegesaltersettingstableengines) + * 5.21.6 [Alter Update](#alter-update) + * 5.21.6.1 [RQ.SRS-006.RBAC.Privileges.AlterUpdate](#rqsrs-006rbacprivilegesalterupdate) + * 5.21.6.2 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant](#rqsrs-006rbacprivilegesalterupdategrant) + * 5.21.6.3 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke](#rqsrs-006rbacprivilegesalterupdaterevoke) + * 5.21.6.4 [RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines](#rqsrs-006rbacprivilegesalterupdatetableengines) + * 5.21.7 [Alter Delete](#alter-delete) + * 5.21.7.1 [RQ.SRS-006.RBAC.Privileges.AlterDelete](#rqsrs-006rbacprivilegesalterdelete) + * 5.21.7.2 [RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant](#rqsrs-006rbacprivilegesalterdeletegrant) + * 5.21.7.3 [RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke](#rqsrs-006rbacprivilegesalterdeleterevoke) + * 5.21.7.4 [RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines](#rqsrs-006rbacprivilegesalterdeletetableengines) + * 5.21.8 [Alter Freeze Partition](#alter-freeze-partition) + * 5.21.8.1 [RQ.SRS-006.RBAC.Privileges.AlterFreeze](#rqsrs-006rbacprivilegesalterfreeze) + * 5.21.8.2 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant](#rqsrs-006rbacprivilegesalterfreezegrant) + * 5.21.8.3 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke](#rqsrs-006rbacprivilegesalterfreezerevoke) + * 5.21.8.4 [RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines](#rqsrs-006rbacprivilegesalterfreezetableengines) + * 5.21.9 [Alter Fetch Partition](#alter-fetch-partition) + * 5.21.9.1 [RQ.SRS-006.RBAC.Privileges.AlterFetch](#rqsrs-006rbacprivilegesalterfetch) + * 5.21.9.2 [RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant](#rqsrs-006rbacprivilegesalterfetchgrant) + * 5.21.9.3 [RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke](#rqsrs-006rbacprivilegesalterfetchrevoke) + * 5.21.9.4 [RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines](#rqsrs-006rbacprivilegesalterfetchtableengines) + * 5.21.10 [Alter Move Partition](#alter-move-partition) + * 5.21.10.1 [RQ.SRS-006.RBAC.Privileges.AlterMove](#rqsrs-006rbacprivilegesaltermove) + * 5.21.10.2 [RQ.SRS-006.RBAC.Privileges.AlterMove.Grant](#rqsrs-006rbacprivilegesaltermovegrant) + * 5.21.10.3 [RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke](#rqsrs-006rbacprivilegesaltermoverevoke) + * 5.21.10.4 [RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines](#rqsrs-006rbacprivilegesaltermovetableengines) + * 5.22 [Create](#create) + * 5.22.1 [RQ.SRS-006.RBAC.Privileges.CreateTable](#rqsrs-006rbacprivilegescreatetable) + * 5.22.2 [RQ.SRS-006.RBAC.Privileges.CreateDatabase](#rqsrs-006rbacprivilegescreatedatabase) + * 5.22.3 [RQ.SRS-006.RBAC.Privileges.CreateDictionary](#rqsrs-006rbacprivilegescreatedictionary) + * 5.22.4 [RQ.SRS-006.RBAC.Privileges.CreateTemporaryTable](#rqsrs-006rbacprivilegescreatetemporarytable) + * 5.23 [Attach](#attach) + * 5.23.1 [RQ.SRS-006.RBAC.Privileges.AttachDatabase](#rqsrs-006rbacprivilegesattachdatabase) + * 5.23.2 [RQ.SRS-006.RBAC.Privileges.AttachDictionary](#rqsrs-006rbacprivilegesattachdictionary) + * 5.23.3 [RQ.SRS-006.RBAC.Privileges.AttachTemporaryTable](#rqsrs-006rbacprivilegesattachtemporarytable) + * 5.23.4 [RQ.SRS-006.RBAC.Privileges.AttachTable](#rqsrs-006rbacprivilegesattachtable) + * 5.24 [Drop](#drop) + * 5.24.1 [RQ.SRS-006.RBAC.Privileges.DropTable](#rqsrs-006rbacprivilegesdroptable) + * 5.24.2 [RQ.SRS-006.RBAC.Privileges.DropDatabase](#rqsrs-006rbacprivilegesdropdatabase) + * 5.24.3 [RQ.SRS-006.RBAC.Privileges.DropDictionary](#rqsrs-006rbacprivilegesdropdictionary) + * 5.25 [Detach](#detach) + * 5.25.1 [RQ.SRS-006.RBAC.Privileges.DetachTable](#rqsrs-006rbacprivilegesdetachtable) + * 5.25.2 [RQ.SRS-006.RBAC.Privileges.DetachView](#rqsrs-006rbacprivilegesdetachview) + * 5.25.3 [RQ.SRS-006.RBAC.Privileges.DetachDatabase](#rqsrs-006rbacprivilegesdetachdatabase) + * 5.25.4 [RQ.SRS-006.RBAC.Privileges.DetachDictionary](#rqsrs-006rbacprivilegesdetachdictionary) + * 5.26 [Truncate](#truncate) + * 5.26.1 [RQ.SRS-006.RBAC.Privileges.Truncate](#rqsrs-006rbacprivilegestruncate) + * 5.27 [Optimize](#optimize) + * 5.27.1 [RQ.SRS-006.RBAC.Privileges.Optimize](#rqsrs-006rbacprivilegesoptimize) + * 5.28 [Kill Query](#kill-query) + * 5.28.1 [RQ.SRS-006.RBAC.Privileges.KillQuery](#rqsrs-006rbacprivilegeskillquery) + * 5.29 [Kill Mutation](#kill-mutation) + * 5.29.1 [RQ.SRS-006.RBAC.Privileges.KillMutation](#rqsrs-006rbacprivilegeskillmutation) + * 5.29.2 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate](#rqsrs-006rbacprivilegeskillmutationalterupdate) + * 5.29.3 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete](#rqsrs-006rbacprivilegeskillmutationalterdelete) + * 5.29.4 [RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn](#rqsrs-006rbacprivilegeskillmutationalterdropcolumn) + * 5.30 [Show](#show) + * 5.30.1 [RQ.SRS-006.RBAC.ShowTables.Privilege](#rqsrs-006rbacshowtablesprivilege) + * 5.30.2 [RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege](#rqsrs-006rbacshowtablesrequiredprivilege) + * 5.30.3 [RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege](#rqsrs-006rbacexiststablerequiredprivilege) + * 5.30.4 [RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege](#rqsrs-006rbacchecktablerequiredprivilege) + * 5.30.5 [RQ.SRS-006.RBAC.ShowDatabases.Privilege](#rqsrs-006rbacshowdatabasesprivilege) + * 5.30.6 [RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege](#rqsrs-006rbacshowdatabasesrequiredprivilege) + * 5.30.7 [RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege](#rqsrs-006rbacshowcreatedatabaserequiredprivilege) + * 5.30.8 [RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege](#rqsrs-006rbacusedatabaserequiredprivilege) + * 5.30.9 [RQ.SRS-006.RBAC.ShowColumns.Privilege](#rqsrs-006rbacshowcolumnsprivilege) + * 5.30.10 [RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege](#rqsrs-006rbacshowcreatetablerequiredprivilege) + * 5.30.11 [RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege](#rqsrs-006rbacdescribetablerequiredprivilege) + * 5.30.12 [RQ.SRS-006.RBAC.ShowDictionaries.Privilege](#rqsrs-006rbacshowdictionariesprivilege) + * 5.30.13 [RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege](#rqsrs-006rbacshowdictionariesrequiredprivilege) + * 5.30.14 [RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege](#rqsrs-006rbacshowcreatedictionaryrequiredprivilege) + * 5.30.15 [RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege](#rqsrs-006rbacexistsdictionaryrequiredprivilege) + * 5.31 [Access Management](#access-management) + * 5.31.1 [RQ.SRS-006.RBAC.Privileges.CreateUser](#rqsrs-006rbacprivilegescreateuser) + * 5.31.2 [RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole](#rqsrs-006rbacprivilegescreateuserdefaultrole) + * 5.31.3 [RQ.SRS-006.RBAC.Privileges.AlterUser](#rqsrs-006rbacprivilegesalteruser) + * 5.31.4 [RQ.SRS-006.RBAC.Privileges.DropUser](#rqsrs-006rbacprivilegesdropuser) + * 5.31.5 [RQ.SRS-006.RBAC.Privileges.CreateRole](#rqsrs-006rbacprivilegescreaterole) + * 5.31.6 [RQ.SRS-006.RBAC.Privileges.AlterRole](#rqsrs-006rbacprivilegesalterrole) + * 5.31.7 [RQ.SRS-006.RBAC.Privileges.DropRole](#rqsrs-006rbacprivilegesdroprole) + * 5.31.8 [RQ.SRS-006.RBAC.Privileges.CreateRowPolicy](#rqsrs-006rbacprivilegescreaterowpolicy) + * 5.31.9 [RQ.SRS-006.RBAC.Privileges.AlterRowPolicy](#rqsrs-006rbacprivilegesalterrowpolicy) + * 5.31.10 [RQ.SRS-006.RBAC.Privileges.DropRowPolicy](#rqsrs-006rbacprivilegesdroprowpolicy) + * 5.31.11 [RQ.SRS-006.RBAC.Privileges.CreateQuota](#rqsrs-006rbacprivilegescreatequota) + * 5.31.12 [RQ.SRS-006.RBAC.Privileges.AlterQuota](#rqsrs-006rbacprivilegesalterquota) + * 5.31.13 [RQ.SRS-006.RBAC.Privileges.DropQuota](#rqsrs-006rbacprivilegesdropquota) + * 5.31.14 [RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile](#rqsrs-006rbacprivilegescreatesettingsprofile) + * 5.31.15 [RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile](#rqsrs-006rbacprivilegesaltersettingsprofile) + * 5.31.16 [RQ.SRS-006.RBAC.Privileges.DropSettingsProfile](#rqsrs-006rbacprivilegesdropsettingsprofile) + * 5.31.17 [RQ.SRS-006.RBAC.Privileges.RoleAdmin](#rqsrs-006rbacprivilegesroleadmin) + * 5.31.18 [Show Access](#show-access) + * 5.31.18.1 [RQ.SRS-006.RBAC.ShowUsers.Privilege](#rqsrs-006rbacshowusersprivilege) + * 5.31.18.2 [RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege](#rqsrs-006rbacshowusersrequiredprivilege) + * 5.31.18.3 [RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege](#rqsrs-006rbacshowcreateuserrequiredprivilege) + * 5.31.18.4 [RQ.SRS-006.RBAC.ShowRoles.Privilege](#rqsrs-006rbacshowrolesprivilege) + * 5.31.18.5 [RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege](#rqsrs-006rbacshowrolesrequiredprivilege) + * 5.31.18.6 [RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege](#rqsrs-006rbacshowcreaterolerequiredprivilege) + * 5.31.18.7 [RQ.SRS-006.RBAC.ShowRowPolicies.Privilege](#rqsrs-006rbacshowrowpoliciesprivilege) + * 5.31.18.8 [RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege](#rqsrs-006rbacshowrowpoliciesrequiredprivilege) + * 5.31.18.9 [RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege](#rqsrs-006rbacshowcreaterowpolicyrequiredprivilege) + * 5.31.18.10 [RQ.SRS-006.RBAC.ShowQuotas.Privilege](#rqsrs-006rbacshowquotasprivilege) + * 5.31.18.11 [RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege](#rqsrs-006rbacshowquotasrequiredprivilege) + * 5.31.18.12 [RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege](#rqsrs-006rbacshowcreatequotarequiredprivilege) + * 5.31.18.13 [RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege](#rqsrs-006rbacshowsettingsprofilesprivilege) + * 5.31.18.14 [RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege](#rqsrs-006rbacshowsettingsprofilesrequiredprivilege) + * 5.31.18.15 [RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege](#rqsrs-006rbacshowcreatesettingsprofilerequiredprivilege) + * 5.32 [dictGet](#dictget) + * 5.32.1 [RQ.SRS-006.RBAC.dictGet.Privilege](#rqsrs-006rbacdictgetprivilege) + * 5.32.2 [RQ.SRS-006.RBAC.dictGet.RequiredPrivilege](#rqsrs-006rbacdictgetrequiredprivilege) + * 5.32.3 [RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege](#rqsrs-006rbacdictgettyperequiredprivilege) + * 5.32.4 [RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege](#rqsrs-006rbacdictgetordefaultrequiredprivilege) + * 5.32.5 [RQ.SRS-006.RBAC.dictHas.RequiredPrivilege](#rqsrs-006rbacdicthasrequiredprivilege) + * 5.32.6 [RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege](#rqsrs-006rbacdictgethierarchyrequiredprivilege) + * 5.32.7 [RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege](#rqsrs-006rbacdictisinrequiredprivilege) + * 5.33 [Introspection](#introspection) + * 5.33.1 [RQ.SRS-006.RBAC.Privileges.Introspection](#rqsrs-006rbacprivilegesintrospection) + * 5.33.2 [RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine](#rqsrs-006rbacprivilegesintrospectionaddresstoline) + * 5.33.3 [RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol](#rqsrs-006rbacprivilegesintrospectionaddresstosymbol) + * 5.33.4 [RQ.SRS-006.RBAC.Privileges.Introspection.demangle](#rqsrs-006rbacprivilegesintrospectiondemangle) + * 5.34 [System](#system) + * 5.34.1 [RQ.SRS-006.RBAC.Privileges.System.Shutdown](#rqsrs-006rbacprivilegessystemshutdown) + * 5.34.2 [RQ.SRS-006.RBAC.Privileges.System.DropCache](#rqsrs-006rbacprivilegessystemdropcache) + * 5.34.3 [RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS](#rqsrs-006rbacprivilegessystemdropcachedns) + * 5.34.4 [RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark](#rqsrs-006rbacprivilegessystemdropcachemark) + * 5.34.5 [RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed](#rqsrs-006rbacprivilegessystemdropcacheuncompressed) + * 5.34.6 [RQ.SRS-006.RBAC.Privileges.System.Reload](#rqsrs-006rbacprivilegessystemreload) + * 5.34.7 [RQ.SRS-006.RBAC.Privileges.System.Reload.Config](#rqsrs-006rbacprivilegessystemreloadconfig) + * 5.34.8 [RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary](#rqsrs-006rbacprivilegessystemreloaddictionary) + * 5.34.9 [RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries](#rqsrs-006rbacprivilegessystemreloaddictionaries) + * 5.34.10 [RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries](#rqsrs-006rbacprivilegessystemreloadembeddeddictionaries) + * 5.34.11 [RQ.SRS-006.RBAC.Privileges.System.Merges](#rqsrs-006rbacprivilegessystemmerges) + * 5.34.12 [RQ.SRS-006.RBAC.Privileges.System.TTLMerges](#rqsrs-006rbacprivilegessystemttlmerges) + * 5.34.13 [RQ.SRS-006.RBAC.Privileges.System.Fetches](#rqsrs-006rbacprivilegessystemfetches) + * 5.34.14 [RQ.SRS-006.RBAC.Privileges.System.Moves](#rqsrs-006rbacprivilegessystemmoves) + * 5.34.15 [RQ.SRS-006.RBAC.Privileges.System.Sends](#rqsrs-006rbacprivilegessystemsends) + * 5.34.16 [RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed](#rqsrs-006rbacprivilegessystemsendsdistributed) + * 5.34.17 [RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated](#rqsrs-006rbacprivilegessystemsendsreplicated) + * 5.34.18 [RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues](#rqsrs-006rbacprivilegessystemreplicationqueues) + * 5.34.19 [RQ.SRS-006.RBAC.Privileges.System.SyncReplica](#rqsrs-006rbacprivilegessystemsyncreplica) + * 5.34.20 [RQ.SRS-006.RBAC.Privileges.System.RestartReplica](#rqsrs-006rbacprivilegessystemrestartreplica) + * 5.34.21 [RQ.SRS-006.RBAC.Privileges.System.Flush](#rqsrs-006rbacprivilegessystemflush) + * 5.34.22 [RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed](#rqsrs-006rbacprivilegessystemflushdistributed) + * 5.34.23 [RQ.SRS-006.RBAC.Privileges.System.Flush.Logs](#rqsrs-006rbacprivilegessystemflushlogs) + * 5.35 [Sources](#sources) + * 5.35.1 [RQ.SRS-006.RBAC.Privileges.Sources](#rqsrs-006rbacprivilegessources) + * 5.35.2 [RQ.SRS-006.RBAC.Privileges.Sources.File](#rqsrs-006rbacprivilegessourcesfile) + * 5.35.3 [RQ.SRS-006.RBAC.Privileges.Sources.URL](#rqsrs-006rbacprivilegessourcesurl) + * 5.35.4 [RQ.SRS-006.RBAC.Privileges.Sources.Remote](#rqsrs-006rbacprivilegessourcesremote) + * 5.35.5 [RQ.SRS-006.RBAC.Privileges.Sources.MySQL](#rqsrs-006rbacprivilegessourcesmysql) + * 5.35.6 [RQ.SRS-006.RBAC.Privileges.Sources.ODBC](#rqsrs-006rbacprivilegessourcesodbc) + * 5.35.7 [RQ.SRS-006.RBAC.Privileges.Sources.JDBC](#rqsrs-006rbacprivilegessourcesjdbc) + * 5.35.8 [RQ.SRS-006.RBAC.Privileges.Sources.HDFS](#rqsrs-006rbacprivilegessourceshdfs) + * 5.35.9 [RQ.SRS-006.RBAC.Privileges.Sources.S3](#rqsrs-006rbacprivilegessourcess3) + * 5.36 [RQ.SRS-006.RBAC.Privileges.GrantOption](#rqsrs-006rbacprivilegesgrantoption) + * 5.37 [RQ.SRS-006.RBAC.Privileges.All](#rqsrs-006rbacprivilegesall) + * 5.38 [RQ.SRS-006.RBAC.Privileges.RoleAll](#rqsrs-006rbacprivilegesroleall) + * 5.39 [RQ.SRS-006.RBAC.Privileges.None](#rqsrs-006rbacprivilegesnone) + * 5.40 [RQ.SRS-006.RBAC.Privileges.AdminOption](#rqsrs-006rbacprivilegesadminoption) * 6 [References](#references) ## Revision History @@ -656,256 +10643,103 @@ version: 1.0 [ClickHouse] SHALL support role based access control. -#### Login +### Login -##### RQ.SRS-006.RBAC.Login +#### RQ.SRS-006.RBAC.Login version: 1.0 [ClickHouse] SHALL only allow access to the server for a given user only when correct username and password are used during the connection to the server. -##### RQ.SRS-006.RBAC.Login.DefaultUser +#### RQ.SRS-006.RBAC.Login.DefaultUser version: 1.0 [ClickHouse] SHALL use the **default user** when no username and password are specified during the connection to the server. -#### User +### User -##### RQ.SRS-006.RBAC.User +#### RQ.SRS-006.RBAC.User version: 1.0 [ClickHouse] SHALL support creation and manipulation of one or more **user** accounts to which roles, privileges, settings profile, quotas and row policies can be assigned. -##### RQ.SRS-006.RBAC.User.Roles +#### RQ.SRS-006.RBAC.User.Roles version: 1.0 [ClickHouse] SHALL support assigning one or more **roles** to a **user**. -##### RQ.SRS-006.RBAC.User.Privileges +#### RQ.SRS-006.RBAC.User.Privileges version: 1.0 [ClickHouse] SHALL support assigning one or more privileges to a **user**. -##### RQ.SRS-006.RBAC.User.Variables +#### RQ.SRS-006.RBAC.User.Variables version: 1.0 [ClickHouse] SHALL support assigning one or more variables to a **user**. -##### RQ.SRS-006.RBAC.User.Variables.Constraints +#### RQ.SRS-006.RBAC.User.Variables.Constraints version: 1.0 [ClickHouse] SHALL support assigning min, max and read-only constraints for the variables that can be set and read by the **user**. -##### RQ.SRS-006.RBAC.User.SettingsProfile +#### RQ.SRS-006.RBAC.User.SettingsProfile version: 1.0 [ClickHouse] SHALL support assigning one or more **settings profiles** to a **user**. -##### RQ.SRS-006.RBAC.User.Quotas +#### RQ.SRS-006.RBAC.User.Quotas version: 1.0 [ClickHouse] SHALL support assigning one or more **quotas** to a **user**. -##### RQ.SRS-006.RBAC.User.RowPolicies +#### RQ.SRS-006.RBAC.User.RowPolicies version: 1.0 [ClickHouse] SHALL support assigning one or more **row policies** to a **user**. -##### RQ.SRS-006.RBAC.User.AccountLock -version: 1.0 - -[ClickHouse] SHALL support locking and unlocking of **user** accounts. - -##### RQ.SRS-006.RBAC.User.AccountLock.DenyAccess -version: 1.0 - -[ClickHouse] SHALL deny access to the user whose account is locked. - -##### RQ.SRS-006.RBAC.User.DefaultRole +#### RQ.SRS-006.RBAC.User.DefaultRole version: 1.0 [ClickHouse] SHALL support assigning a default role to a **user**. -##### RQ.SRS-006.RBAC.User.RoleSelection +#### RQ.SRS-006.RBAC.User.RoleSelection version: 1.0 [ClickHouse] SHALL support selection of one or more **roles** from the available roles -that are assigned to a **user**. +that are assigned to a **user** using `SET ROLE` statement. -##### RQ.SRS-006.RBAC.User.ShowCreate +#### RQ.SRS-006.RBAC.User.ShowCreate version: 1.0 [ClickHouse] SHALL support showing the command of how **user** account was created. -##### RQ.SRS-006.RBAC.User.ShowPrivileges +#### RQ.SRS-006.RBAC.User.ShowPrivileges version: 1.0 [ClickHouse] SHALL support listing the privileges of the **user**. -#### Role - -##### RQ.SRS-006.RBAC.Role -version: 1.0 - -[ClikHouse] SHALL support creation and manipulation of **roles** -to which privileges, settings profile, quotas and row policies can be -assigned. - -##### RQ.SRS-006.RBAC.Role.Privileges -version: 1.0 - -[ClickHouse] SHALL support assigning one or more privileges to a **role**. - -##### RQ.SRS-006.RBAC.Role.Variables -version: 1.0 - -[ClickHouse] SHALL support assigning one or more variables to a **role**. - -##### RQ.SRS-006.RBAC.Role.SettingsProfile -version: 1.0 - -[ClickHouse] SHALL support assigning one or more **settings profiles** -to a **role**. - -##### RQ.SRS-006.RBAC.Role.Quotas -version: 1.0 - -[ClickHouse] SHALL support assigning one or more **quotas** to a **role**. - -##### RQ.SRS-006.RBAC.Role.RowPolicies -version: 1.0 - -[ClickHouse] SHALL support assigning one or more **row policies** to a **role**. - -#### Partial Revokes - -##### RQ.SRS-006.RBAC.PartialRevokes -version: 1.0 - -[ClickHouse] SHALL support partial revoking of privileges granted -to a **user** or a **role**. - -#### Settings Profile - -##### RQ.SRS-006.RBAC.SettingsProfile -version: 1.0 - -[ClickHouse] SHALL support creation and manipulation of **settings profiles** -that can include value definition for one or more variables and can -can be assigned to one or more **users** or **roles**. - -##### RQ.SRS-006.RBAC.SettingsProfile.Constraints -version: 1.0 - -[ClickHouse] SHALL support assigning min, max and read-only constraints -for the variables specified in the **settings profile**. - -##### RQ.SRS-006.RBAC.SettingsProfile.ShowCreate -version: 1.0 - -[ClickHouse] SHALL support showing the command of how **setting profile** was created. - -#### Quotas - -##### RQ.SRS-006.RBAC.Quotas -version: 1.0 - -[ClickHouse] SHALL support creation and manipulation of **quotas** -that can be used to limit resource usage by a **user** or a **role** -over a period of time. - -##### RQ.SRS-006.RBAC.Quotas.Keyed -version: 1.0 - -[ClickHouse] SHALL support creating **quotas** that are keyed -so that a quota is tracked separately for each key value. - -##### RQ.SRS-006.RBAC.Quotas.Queries -version: 1.0 - -[ClickHouse] SHALL support setting **queries** quota to limit the total number of requests. - -##### RQ.SRS-006.RBAC.Quotas.Errors -version: 1.0 - -[ClickHouse] SHALL support setting **errors** quota to limit the number of queries that threw an exception. - -##### RQ.SRS-006.RBAC.Quotas.ResultRows -version: 1.0 - -[ClickHouse] SHALL support setting **result rows** quota to limit the -the total number of rows given as the result. - -##### RQ.SRS-006.RBAC.Quotas.ReadRows -version: 1.0 - -[ClickHouse] SHALL support setting **read rows** quota to limit the total -number of source rows read from tables for running the query on all remote servers. - -##### RQ.SRS-006.RBAC.Quotas.ResultBytes -version: 1.0 - -[ClickHouse] SHALL support setting **result bytes** quota to limit the total number -of bytes that can be returned as the result. - -##### RQ.SRS-006.RBAC.Quotas.ReadBytes -version: 1.0 - -[ClickHouse] SHALL support setting **read bytes** quota to limit the total number -of source bytes read from tables for running the query on all remote servers. - -##### RQ.SRS-006.RBAC.Quotas.ExecutionTime -version: 1.0 - -[ClickHouse] SHALL support setting **execution time** quota to limit the maximum -query execution time. - -##### RQ.SRS-006.RBAC.Quotas.ShowCreate -version: 1.0 - -[ClickHouse] SHALL support showing the command of how **quota** was created. - -#### Row Policy - -##### RQ.SRS-006.RBAC.RowPolicy -version: 1.0 - -[ClickHouse] SHALL support creation and manipulation of table **row policies** -that can be used to limit access to the table contents for a **user** or a **role** -using a specified **condition**. - -##### RQ.SRS-006.RBAC.RowPolicy.Condition -version: 1.0 - -[ClickHouse] SHALL support row policy **conditions** that can be any SQL -expression that returns a boolean. - -##### RQ.SRS-006.RBAC.RowPolicy.ShowCreate -version: 1.0 - -[ClickHouse] SHALL support showing the command of how **row policy** was created. - -### Specific - -##### RQ.SRS-006.RBAC.User.Use.DefaultRole +#### RQ.SRS-006.RBAC.User.Use.DefaultRole version: 1.0 [ClickHouse] SHALL by default use default role or roles assigned to the user if specified. -##### RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole +#### RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole version: 1.0 [ClickHouse] SHALL by default use all the roles assigned to the user if no default role or roles are specified for the user. +#### Create User + ##### RQ.SRS-006.RBAC.User.Create version: 1.0 @@ -1103,6 +10937,8 @@ CREATE USER [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name] [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] ``` +#### Alter User + ##### RQ.SRS-006.RBAC.User.Alter version: 1.0 @@ -1119,7 +10955,8 @@ the left. version: 1.0 [ClickHouse] SHALL support `IF EXISTS` clause in the `ALTER USER` statement -to skip raising an exception (producing a warning instead) if a user with the specified **name** does not exist. If the `IF EXISTS` clause is not specified then an exception SHALL be raised if a user with the **name** does not exist. +to skip raising an exception (producing a warning instead) if a user with the specified **name** does not exist. +If the `IF EXISTS` clause is not specified then an exception SHALL be raised if a user with the **name** does not exist. ##### RQ.SRS-006.RBAC.User.Alter.Cluster version: 1.0 @@ -1157,7 +10994,8 @@ to some password as identification when altering user account using ##### RQ.SRS-006.RBAC.User.Alter.Host.AddDrop version: 1.0 -[ClickHouse] SHALL support altering user by adding and dropping access to hosts with the `ADD HOST` or the `DROP HOST`in the `ALTER USER` statement. +[ClickHouse] SHALL support altering user by adding and dropping access to hosts +with the `ADD HOST` or the `DROP HOST` in the `ALTER USER` statement. ##### RQ.SRS-006.RBAC.User.Alter.Host.Local version: 1.0 @@ -1189,7 +11027,8 @@ which user can access the server using the `HOST IP` clause in the ##### RQ.SRS-006.RBAC.User.Alter.Host.Like version: 1.0 -[ClickHouse] SHALL support specifying sone or more similar hosts using `LIKE` command syntax using the `HOST LIKE` clause in the `ALTER USER` statement. +[ClickHouse] SHALL support specifying one or more similar hosts using `LIKE` command syntax +using the `HOST LIKE` clause in the `ALTER USER` statement. ##### RQ.SRS-006.RBAC.User.Alter.Host.Any version: 1.0 @@ -1232,7 +11071,6 @@ version: 1.0 [ClickHouse] SHALL support specifying a minimum value for the variable specifed using `SETTINGS` with `MIN` clause in the `ALTER USER` statement. - ##### RQ.SRS-006.RBAC.User.Alter.Settings.Max version: 1.0 @@ -1257,85 +11095,7 @@ ALTER USER [IF EXISTS] name [ON CLUSTER cluster_name] [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] ``` -##### RQ.SRS-006.RBAC.SetDefaultRole -version: 1.0 - -[ClickHouse] SHALL support setting or changing granted roles to default for one or more -users using `SET DEFAULT ROLE` statement which -SHALL permanently change the default roles for the user or users if successful. - -##### RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser -version: 1.0 - -[ClickHouse] SHALL support setting or changing granted roles to default for -the current user using `CURRENT_USER` clause in the `SET DEFAULT ROLE` statement. - -##### RQ.SRS-006.RBAC.SetDefaultRole.All -version: 1.0 - -[ClickHouse] SHALL support setting or changing all granted roles to default -for one or more users using `ALL` clause in the `SET DEFAULT ROLE` statement. - -##### RQ.SRS-006.RBAC.SetDefaultRole.AllExcept -version: 1.0 - -[ClickHouse] SHALL support setting or changing all granted roles except those specified -to default for one or more users using `ALL EXCEPT` clause in the `SET DEFAULT ROLE` statement. - -##### RQ.SRS-006.RBAC.SetDefaultRole.None -version: 1.0 - -[ClickHouse] SHALL support removing all granted roles from default -for one or more users using `NONE` clause in the `SET DEFAULT ROLE` statement. - -##### RQ.SRS-006.RBAC.SetDefaultRole.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for the `SET DEFAULT ROLE` statement. - -```sql -SET DEFAULT ROLE - {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} - TO {user|CURRENT_USER} [,...] - -``` - -##### RQ.SRS-006.RBAC.SetRole -version: 1.0 - -[ClickHouse] SHALL support activating role or roles for the current user -using `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.Default -version: 1.0 - -[ClickHouse] SHALL support activating default roles for the current user -using `DEFAULT` clause in the `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.None -version: 1.0 - -[ClickHouse] SHALL support activating no roles for the current user -using `NONE` clause in the `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.All -version: 1.0 - -[ClickHouse] SHALL support activating all roles for the current user -using `ALL` clause in the `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.AllExcept -version: 1.0 - -[ClickHouse] SHALL support activating all roles except those specified -for the current user using `ALL EXCEPT` clause in the `SET ROLE` statement. - -##### RQ.SRS-006.RBAC.SetRole.Syntax -version: 1.0 - -```sql -SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]} -``` +#### Show Create User ##### RQ.SRS-006.RBAC.User.ShowCreateUser version: 1.0 @@ -1358,6 +11118,8 @@ version: 1.0 SHOW CREATE USER [name | CURRENT_USER] ``` +#### Drop User + ##### RQ.SRS-006.RBAC.User.Drop version: 1.0 @@ -1386,6 +11148,43 @@ version: 1.0 DROP USER [IF EXISTS] name [,...] [ON CLUSTER cluster_name] ``` +### Role + +#### RQ.SRS-006.RBAC.Role +version: 1.0 + +[ClikHouse] SHALL support creation and manipulation of **roles** +to which privileges, settings profile, quotas and row policies can be +assigned. + +#### RQ.SRS-006.RBAC.Role.Privileges +version: 1.0 + +[ClickHouse] SHALL support assigning one or more privileges to a **role**. + +#### RQ.SRS-006.RBAC.Role.Variables +version: 1.0 + +[ClickHouse] SHALL support assigning one or more variables to a **role**. + +#### RQ.SRS-006.RBAC.Role.SettingsProfile +version: 1.0 + +[ClickHouse] SHALL support assigning one or more **settings profiles** +to a **role**. + +#### RQ.SRS-006.RBAC.Role.Quotas +version: 1.0 + +[ClickHouse] SHALL support assigning one or more **quotas** to a **role**. + +#### RQ.SRS-006.RBAC.Role.RowPolicies +version: 1.0 + +[ClickHouse] SHALL support assigning one or more **row policies** to a **role**. + +#### Create Role + ##### RQ.SRS-006.RBAC.Role.Create version: 1.0 @@ -1421,6 +11220,8 @@ CREATE ROLE [IF NOT EXISTS | OR REPLACE] name [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] ``` +#### Alter Role + ##### RQ.SRS-006.RBAC.Role.Alter version: 1.0 @@ -1467,6 +11268,8 @@ ALTER ROLE [IF EXISTS] name [ON CLUSTER cluster_name] [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] ``` +#### Drop Role + ##### RQ.SRS-006.RBAC.Role.Drop version: 1.0 @@ -1494,6 +11297,8 @@ version: 1.0 DROP ROLE [IF EXISTS] name [,...] [ON CLUSTER cluster_name] ``` +#### Show Create Role + ##### RQ.SRS-006.RBAC.Role.ShowCreate version: 1.0 @@ -1509,326 +11314,15 @@ version: 1.0 SHOW CREATE ROLE name ``` -##### RQ.SRS-006.RBAC.Grant.Privilege.To +### Partial Revokes + +#### RQ.SRS-006.RBAC.PartialRevokes version: 1.0 -[ClickHouse] SHALL support granting privileges to one or more users or roles using `TO` clause -in the `GRANT PRIVILEGE` statement. +[ClickHouse] SHALL support partial revoking of privileges granted +to a **user** or a **role**. -##### RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser -version: 1.0 - -[ClickHouse] SHALL support granting privileges to current user using `TO CURRENT_USER` clause -in the `GRANT PRIVILEGE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Select -version: 1.0 - -[ClickHouse] SHALL support granting the **select** privilege to one or more users or roles -for a database or a table using the `GRANT SELECT` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Insert -version: 1.0 - -[ClickHouse] SHALL support granting the **insert** privilege to one or more users or roles -for a database or a table using the `GRANT INSERT` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Alter -version: 1.0 - -[ClickHouse] SHALL support granting the **alter** privilege to one or more users or roles -for a database or a table using the `GRANT ALTER` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Create -version: 1.0 - -[ClickHouse] SHALL support granting the **create** privilege to one or more users or roles -using the `GRANT CREATE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Drop -version: 1.0 - -[ClickHouse] SHALL support granting the **drop** privilege to one or more users or roles -using the `GRANT DROP` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Truncate -version: 1.0 - -[ClickHouse] SHALL support granting the **truncate** privilege to one or more users or roles -for a database or a table using `GRANT TRUNCATE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Optimize -version: 1.0 - -[ClickHouse] SHALL support granting the **optimize** privilege to one or more users or roles -for a database or a table using `GRANT OPTIMIZE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Show -version: 1.0 - -[ClickHouse] SHALL support granting the **show** privilege to one or more users or roles -for a database or a table using `GRANT SHOW` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.KillQuery -version: 1.0 - -[ClickHouse] SHALL support granting the **kill query** privilege to one or more users or roles -for a database or a table using `GRANT KILL QUERY` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement -version: 1.0 - -[ClickHouse] SHALL support granting the **access management** privileges to one or more users or roles -for a database or a table using `GRANT ACCESS MANAGEMENT` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.System -version: 1.0 - -[ClickHouse] SHALL support granting the **system** privileges to one or more users or roles -for a database or a table using `GRANT SYSTEM` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Introspection -version: 1.0 - -[ClickHouse] SHALL support granting the **introspection** privileges to one or more users or roles -for a database or a table using `GRANT INTROSPECTION` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Sources -version: 1.0 - -[ClickHouse] SHALL support granting the **sources** privileges to one or more users or roles -for a database or a table using `GRANT SOURCES` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.DictGet -version: 1.0 - -[ClickHouse] SHALL support granting the **dictGet** privilege to one or more users or roles -for a database or a table using `GRANT dictGet` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.None -version: 1.0 - -[ClickHouse] SHALL support granting no privileges to one or more users or roles -for a database or a table using `GRANT NONE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.All -version: 1.0 - -[ClickHouse] SHALL support granting the **all** privileges to one or more users or roles -for a database or a table using the `GRANT ALL` or `GRANT ALL PRIVILEGES` statements. - -##### RQ.SRS-006.RBAC.Grant.Privilege.GrantOption -version: 1.0 - -[ClickHouse] SHALL support granting the **grant option** privilege to one or more users or roles -for a database or a table using the `WITH GRANT OPTION` clause in the `GRANT` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.On -version: 1.0 - -[ClickHouse] SHALL support the `ON` clause in the `GRANT` privilege statement -which SHALL allow to specify one or more tables to which the privilege SHALL -be granted using the following patterns - -* `*.*` any table in any database -* `database.*` any table in the specified database -* `database.table` specific table in the specified database -* `*` any table in the current database -* `table` specific table in the current database - -##### RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns -version: 1.0 - -[ClickHouse] SHALL support granting the privilege **some_privilege** to one or more users or roles -for a database or a table using the `GRANT some_privilege(column)` statement for one column. -Multiple columns will be supported with `GRANT some_privilege(column1, column2...)` statement. -The privileges will be granted for only the specified columns. - -##### RQ.SRS-006.RBAC.Grant.Privilege.OnCluster -version: 1.0 - -[ClickHouse] SHALL support specifying cluster on which to grant privileges using the `ON CLUSTER` -clause in the `GRANT PRIVILEGE` statement. - -##### RQ.SRS-006.RBAC.Grant.Privilege.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for the `GRANT` statement that -grants explicit privileges to a user or a role. - -```sql -GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] - ON {db.table|db.*|*.*|table|*} - TO {user | role | CURRENT_USER} [,...] - [WITH GRANT OPTION] -``` - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Cluster -version: 1.0 - -[ClickHouse] SHALL support revoking privileges to one or more users or roles -for a database or a table on some specific cluster using the `REVOKE ON CLUSTER cluster_name` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Any -version: 1.0 - -[ClickHouse] SHALL support revoking ANY privilege to one or more users or roles -for a database or a table using the `REVOKE some_privilege` statement. -**some_privilege** refers to any Clickhouse defined privilege, whose hierarchy includes -SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE, SHOW, KILL QUERY, ACCESS MANAGEMENT, -SYSTEM, INTROSPECTION, SOURCES, dictGet and all of their sub-privileges. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Select -version: 1.0 - -[ClickHouse] SHALL support revoking the **select** privilege to one or more users or roles -for a database or a table using the `REVOKE SELECT` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Insert -version: 1.0 - -[ClickHouse] SHALL support revoking the **insert** privilege to one or more users or roles -for a database or a table using the `REVOKE INSERT` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Alter -version: 1.0 - -[ClickHouse] SHALL support revoking the **alter** privilege to one or more users or roles -for a database or a table using the `REVOKE ALTER` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Create -version: 1.0 - -[ClickHouse] SHALL support revoking the **create** privilege to one or more users or roles -using the `REVOKE CREATE` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Drop -version: 1.0 - -[ClickHouse] SHALL support revoking the **drop** privilege to one or more users or roles -using the `REVOKE DROP` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Truncate -version: 1.0 - -[ClickHouse] SHALL support revoking the **truncate** privilege to one or more users or roles -for a database or a table using the `REVOKE TRUNCATE` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Optimize -version: 1.0 - -[ClickHouse] SHALL support revoking the **optimize** privilege to one or more users or roles -for a database or a table using the `REVOKE OPTIMIZE` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Show -version: 1.0 - -[ClickHouse] SHALL support revoking the **show** privilege to one or more users or roles -for a database or a table using the `REVOKE SHOW` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery -version: 1.0 - -[ClickHouse] SHALL support revoking the **kill query** privilege to one or more users or roles -for a database or a table using the `REVOKE KILL QUERY` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement -version: 1.0 - -[ClickHouse] SHALL support revoking the **access management** privilege to one or more users or roles -for a database or a table using the `REVOKE ACCESS MANAGEMENT` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.System -version: 1.0 - -[ClickHouse] SHALL support revoking the **system** privilege to one or more users or roles -for a database or a table using the `REVOKE SYSTEM` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Introspection -version: 1.0 - -[ClickHouse] SHALL support revoking the **introspection** privilege to one or more users or roles -for a database or a table using the `REVOKE INTROSPECTION` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Sources -version: 1.0 - -[ClickHouse] SHALL support revoking the **sources** privilege to one or more users or roles -for a database or a table using the `REVOKE SOURCES` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.DictGet -version: 1.0 - -[ClickHouse] SHALL support revoking the **dictGet** privilege to one or more users or roles -for a database or a table using the `REVOKE dictGet` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.PrivelegeColumns -version: 1.0 - -[ClickHouse] SHALL support revoking the privilege **some_privilege** to one or more users or roles -for a database or a table using the `REVOKE some_privilege(column)` statement for one column. -Multiple columns will be supported with `REVOKE some_privilege(column1, column2...)` statement. -The privileges will be revoked for only the specified columns. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Multiple -version: 1.0 - -[ClickHouse] SHALL support revoking MULTIPLE **privileges** to one or more users or roles -for a database or a table using the `REVOKE privilege1, privilege2...` statement. -**privileges** refers to any set of Clickhouse defined privilege, whose hierarchy includes -SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE, SHOW, KILL QUERY, ACCESS MANAGEMENT, -SYSTEM, INTROSPECTION, SOURCES, dictGet and all of their sub-privileges. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.All -version: 1.0 - -[ClickHouse] SHALL support revoking **all** privileges to one or more users or roles -for a database or a table using the `REVOKE ALL` or `REVOKE ALL PRIVILEGES` statements. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.None -version: 1.0 - -[ClickHouse] SHALL support revoking **no** privileges to one or more users or roles -for a database or a table using the `REVOKE NONE` statement. - -##### RQ.SRS-006.RBAC.Revoke.Privilege.On -version: 1.0 - -[ClickHouse] SHALL support the `ON` clause in the `REVOKE` privilege statement -which SHALL allow to specify one or more tables to which the privilege SHALL -be revoked using the following patterns - -* `db.table` specific table in the specified database -* `db.*` any table in the specified database -* `*.*` any table in any database -* `table` specific table in the current database -* `*` any table in the current database - -##### RQ.SRS-006.RBAC.Revoke.Privilege.From -version: 1.0 - -[ClickHouse] SHALL support the `FROM` clause in the `REVOKE` privilege statement -which SHALL allow to specify one or more users to which the privilege SHALL -be revoked using the following patterns - -* `{user | CURRENT_USER} [,...]` some combination of users by name, which may include the current user -* `ALL` all users -* `ALL EXCEPT {user | CURRENT_USER} [,...]` the logical reverse of the first pattern - -##### RQ.SRS-006.RBAC.Revoke.Privilege.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for the `REVOKE` statement that -revokes explicit privileges of a user or a role. - -```sql -REVOKE [ON CLUSTER cluster_name] privilege - [(column_name [,...])] [,...] - ON {db.table|db.*|*.*|table|*} - FROM {user | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user | CURRENT_USER} [,...] -``` - -##### RQ.SRS-006.RBAC.PartialRevoke.Syntax +#### RQ.SRS-006.RBAC.PartialRevoke.Syntax version: 1.0 [ClickHouse] SHALL support partial revokes by using `partial_revokes` variable @@ -1846,102 +11340,22 @@ To enable partial revokes the `partial revokes` variable SHALL be set to `1` SET partial_revokes = 1 ``` -##### RQ.SRS-006.RBAC.Grant.Role +### Settings Profile + +#### RQ.SRS-006.RBAC.SettingsProfile version: 1.0 -[ClickHouse] SHALL support granting one or more roles to -one or more users or roles using the `GRANT` role statement. +[ClickHouse] SHALL support creation and manipulation of **settings profiles** +that can include value definition for one or more variables and can +can be assigned to one or more **users** or **roles**. -##### RQ.SRS-006.RBAC.Grant.Role.CurrentUser +#### RQ.SRS-006.RBAC.SettingsProfile.Constraints version: 1.0 -[ClickHouse] SHALL support granting one or more roles to current user using -`TO CURRENT_USER` clause in the `GRANT` role statement. +[ClickHouse] SHALL support assigning min, max and read-only constraints +for the variables specified in the **settings profile**. -##### RQ.SRS-006.RBAC.Grant.Role.AdminOption -version: 1.0 - -[ClickHouse] SHALL support granting `admin option` privilege -to one or more users or roles using the `WITH ADMIN OPTION` clause -in the `GRANT` role statement. - -##### RQ.SRS-006.RBAC.Grant.Role.OnCluster -version: 1.0 - -[ClickHouse] SHALL support specifying cluster on which the user is to be granted one or more roles -using `ON CLUSTER` clause in the `GRANT` statement. - -##### RQ.SRS-006.RBAC.Grant.Role.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for `GRANT` role statement - -``` sql -GRANT - ON CLUSTER cluster_name - role [, role ...] - TO {user | role | CURRENT_USER} [,...] - [WITH ADMIN OPTION] -``` - -##### RQ.SRS-006.RBAC.Revoke.Role -version: 1.0 - -[ClickHouse] SHALL support revoking one or more roles from -one or more users or roles using the `REVOKE` role statement. - -##### RQ.SRS-006.RBAC.Revoke.Role.Keywords -version: 1.0 - -[ClickHouse] SHALL support revoking one or more roles from -special groupings of one or more users or roles with the `ALL`, `ALL EXCEPT`, -and `CURRENT_USER` keywords. - -##### RQ.SRS-006.RBAC.Revoke.Role.Cluster -version: 1.0 - -[ClickHouse] SHALL support revoking one or more roles from -one or more users or roles from one or more clusters -using the `REVOKE ON CLUSTER` role statement. - -##### RQ.SRS-006.RBAC.Revoke.AdminOption -version: 1.0 - -[ClickHouse] SHALL support revoking `admin option` privilege -in one or more users or roles using the `ADMIN OPTION FOR` clause -in the `REVOKE` role statement. - -##### RQ.SRS-006.RBAC.Revoke.Role.Syntax -version: 1.0 - -[ClickHouse] SHALL support the following syntax for the `REVOKE` role statement - -```sql -REVOKE [ON CLUSTER cluster_name] [ADMIN OPTION FOR] - role [,...] - FROM {user | role | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...] -``` - -##### RQ.SRS-006.RBAC.Show.Grants -version: 1.0 - -[ClickHouse] SHALL support listing all the privileges granted to current user and role -using the `SHOW GRANTS` statement. - -##### RQ.SRS-006.RBAC.Show.Grants.For -version: 1.0 - -[ClickHouse] SHALL support listing all the privileges granted to a user or a role -using the `FOR` clause in the `SHOW GRANTS` statement. - -##### RQ.SRS-006.RBAC.Show.Grants.Syntax -version: 1.0 - -[Clickhouse] SHALL use the following syntax for the `SHOW GRANTS` statement - -``` sql -SHOW GRANTS [FOR user_or_role] -``` +#### Create Settings Profile ##### RQ.SRS-006.RBAC.SettingsProfile.Create version: 1.0 @@ -2027,6 +11441,8 @@ CREATE SETTINGS PROFILE [IF NOT EXISTS | OR REPLACE] name [TO {user_or_role [,...] | NONE | ALL | ALL EXCEPT user_or_role [,...]}] ``` +#### Alter Settings Profile + ##### RQ.SRS-006.RBAC.SettingsProfile.Alter version: 1.0 @@ -2112,6 +11528,8 @@ ALTER SETTINGS PROFILE [IF EXISTS] name [TO {user_or_role [,...] | NONE | ALL | ALL EXCEPT user_or_role [,...]]} ``` +#### Drop Settings Profile + ##### RQ.SRS-006.RBAC.SettingsProfile.Drop version: 1.0 @@ -2140,6 +11558,8 @@ version: 1.0 DROP SETTINGS PROFILE [IF EXISTS] name [,name,...] ``` +#### Show Create Settings Profile + ##### RQ.SRS-006.RBAC.SettingsProfile.ShowCreateSettingsProfile version: 1.0 @@ -2150,6 +11570,63 @@ using the `SHOW CREATE SETTINGS PROFILE` statement with the following syntax SHOW CREATE SETTINGS PROFILE name ``` +### Quotas + +#### RQ.SRS-006.RBAC.Quotas +version: 1.0 + +[ClickHouse] SHALL support creation and manipulation of **quotas** +that can be used to limit resource usage by a **user** or a **role** +over a period of time. + +#### RQ.SRS-006.RBAC.Quotas.Keyed +version: 1.0 + +[ClickHouse] SHALL support creating **quotas** that are keyed +so that a quota is tracked separately for each key value. + +#### RQ.SRS-006.RBAC.Quotas.Queries +version: 1.0 + +[ClickHouse] SHALL support setting **queries** quota to limit the total number of requests. + +#### RQ.SRS-006.RBAC.Quotas.Errors +version: 1.0 + +[ClickHouse] SHALL support setting **errors** quota to limit the number of queries that threw an exception. + +#### RQ.SRS-006.RBAC.Quotas.ResultRows +version: 1.0 + +[ClickHouse] SHALL support setting **result rows** quota to limit the +the total number of rows given as the result. + +#### RQ.SRS-006.RBAC.Quotas.ReadRows +version: 1.0 + +[ClickHouse] SHALL support setting **read rows** quota to limit the total +number of source rows read from tables for running the query on all remote servers. + +#### RQ.SRS-006.RBAC.Quotas.ResultBytes +version: 1.0 + +[ClickHouse] SHALL support setting **result bytes** quota to limit the total number +of bytes that can be returned as the result. + +#### RQ.SRS-006.RBAC.Quotas.ReadBytes +version: 1.0 + +[ClickHouse] SHALL support setting **read bytes** quota to limit the total number +of source bytes read from tables for running the query on all remote servers. + +#### RQ.SRS-006.RBAC.Quotas.ExecutionTime +version: 1.0 + +[ClickHouse] SHALL support setting **execution time** quota to limit the maximum +query execution time. + +#### Create Quotas + ##### RQ.SRS-006.RBAC.Quota.Create version: 1.0 @@ -2188,7 +11665,6 @@ of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be: `FOR INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some real number to define the interval. - ##### RQ.SRS-006.RBAC.Quota.Create.Interval.Randomized version: 1.0 @@ -2311,6 +11787,8 @@ CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name] [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] ``` +#### Alter Quota + ##### RQ.SRS-006.RBAC.Quota.Alter version: 1.0 @@ -2469,6 +11947,8 @@ ALTER QUOTA [IF EXIST] name [TO {user_or_role [,...] | NONE | ALL} [EXCEPT user_or_role [,...]]] ``` +#### Drop Quota + ##### RQ.SRS-006.RBAC.Quota.Drop version: 1.0 @@ -2497,6 +11977,8 @@ version: 1.0 DROP QUOTA [IF EXISTS] name [,name...] ``` +#### Show Quotas + ##### RQ.SRS-006.RBAC.Quota.ShowQuotas version: 1.0 @@ -2521,7 +12003,6 @@ version: 1.0 [ClickHouse] SHALL support the `SETTINGS` clause in the `SHOW QUOTAS` statement to define settings in the showing of all quotas. - ##### RQ.SRS-006.RBAC.Quota.ShowQuotas.Syntax version: 1.0 @@ -2530,6 +12011,9 @@ with the following syntax ``` sql SHOW QUOTAS ``` + +#### Show Create Quota + ##### RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Name version: 1.0 @@ -2557,6 +12041,34 @@ using the `SHOW CREATE QUOTA` statement. SHOW CREATE QUOTA [name | CURRENT] ``` +### Row Policy + +#### RQ.SRS-006.RBAC.RowPolicy +version: 1.0 + +[ClickHouse] SHALL support creation and manipulation of table **row policies** +that can be used to limit access to the table contents for a **user** or a **role** +using a specified **condition**. + +#### RQ.SRS-006.RBAC.RowPolicy.Condition +version: 1.0 + +[ClickHouse] SHALL support row policy **conditions** that can be any SQL +expression that returns a boolean. + +#### RQ.SRS-006.RBAC.RowPolicy.Restriction +version: 1.0 + +[ClickHouse] SHALL restrict all access to a table when a row policy with a condition is created on that table. +All users require a permissive row policy in order to view the table. + +#### RQ.SRS-006.RBAC.RowPolicy.Nesting +version: 1.0 + +[ClickHouse] SHALL restrict rows of tables or views created on top of a table with row policies according to those policies. + +#### Create Row Policy + ##### RQ.SRS-006.RBAC.RowPolicy.Create version: 1.0 @@ -2611,14 +12123,14 @@ version: 1.0 [ClickHouse] SHALL support specifying which rows are affected using the `FOR SELECT` clause in the `CREATE ROW POLICY` statement. -REQUIRES CONFIRMATION +REQUIRES CONDITION. ##### RQ.SRS-006.RBAC.RowPolicy.Create.Condition version: 1.0 [ClickHouse] SHALL support specifying a condition that that can be any SQL expression which returns a boolean using the `USING` -clause in the `CREATE ROW POLOCY` statement. +clause in the `CREATE ROW POLICY` statement. ##### RQ.SRS-006.RBAC.RowPolicy.Create.Assignment version: 1.0 @@ -2657,6 +12169,8 @@ CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name [ON CLUSTER cluster [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] ``` +#### Alter Row Policy + ##### RQ.SRS-006.RBAC.RowPolicy.Alter version: 1.0 @@ -2763,6 +12277,8 @@ ALTER [ROW] POLICY [IF EXISTS] name [ON CLUSTER cluster_name] ON [database.]tabl [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] ``` +#### Drop Row Policy + ##### RQ.SRS-006.RBAC.RowPolicy.Drop version: 1.0 @@ -2797,6 +12313,8 @@ version: 1.0 DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...] [ON CLUSTER cluster_name] ``` +#### Show Create Row Policy + ##### RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy version: 1.0 @@ -2838,9 +12356,510 @@ version: 1.0 SHOW [ROW] POLICIES [ON [database.]table] ``` -#### Table Privileges +### Set Default Role -##### RQ.SRS-006.RBAC.Table.PublicTables +#### RQ.SRS-006.RBAC.SetDefaultRole +version: 1.0 + +[ClickHouse] SHALL support setting or changing granted roles to default for one or more +users using `SET DEFAULT ROLE` statement which +SHALL permanently change the default roles for the user or users if successful. + +#### RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser +version: 1.0 + +[ClickHouse] SHALL support setting or changing granted roles to default for +the current user using `CURRENT_USER` clause in the `SET DEFAULT ROLE` statement. + +#### RQ.SRS-006.RBAC.SetDefaultRole.All +version: 1.0 + +[ClickHouse] SHALL support setting or changing all granted roles to default +for one or more users using `ALL` clause in the `SET DEFAULT ROLE` statement. + +#### RQ.SRS-006.RBAC.SetDefaultRole.AllExcept +version: 1.0 + +[ClickHouse] SHALL support setting or changing all granted roles except those specified +to default for one or more users using `ALL EXCEPT` clause in the `SET DEFAULT ROLE` statement. + +#### RQ.SRS-006.RBAC.SetDefaultRole.None +version: 1.0 + +[ClickHouse] SHALL support removing all granted roles from default +for one or more users using `NONE` clause in the `SET DEFAULT ROLE` statement. + +#### RQ.SRS-006.RBAC.SetDefaultRole.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for the `SET DEFAULT ROLE` statement. + +```sql +SET DEFAULT ROLE + {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} + TO {user|CURRENT_USER} [,...] + +``` + +### Set Role + +#### RQ.SRS-006.RBAC.SetRole +version: 1.0 + +[ClickHouse] SHALL support activating role or roles for the current user +using `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.Default +version: 1.0 + +[ClickHouse] SHALL support activating default roles for the current user +using `DEFAULT` clause in the `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.None +version: 1.0 + +[ClickHouse] SHALL support activating no roles for the current user +using `NONE` clause in the `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.All +version: 1.0 + +[ClickHouse] SHALL support activating all roles for the current user +using `ALL` clause in the `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.AllExcept +version: 1.0 + +[ClickHouse] SHALL support activating all roles except those specified +for the current user using `ALL EXCEPT` clause in the `SET ROLE` statement. + +#### RQ.SRS-006.RBAC.SetRole.Syntax +version: 1.0 + +```sql +SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]} +``` + +### Grant + +#### RQ.SRS-006.RBAC.Grant.Privilege.To +version: 1.0 + +[ClickHouse] SHALL support granting privileges to one or more users or roles using `TO` clause +in the `GRANT PRIVILEGE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser +version: 1.0 + +[ClickHouse] SHALL support granting privileges to current user using `TO CURRENT_USER` clause +in the `GRANT PRIVILEGE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Select +version: 1.0 + +[ClickHouse] SHALL support granting the **select** privilege to one or more users or roles +for a database or a table using the `GRANT SELECT` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Insert +version: 1.0 + +[ClickHouse] SHALL support granting the **insert** privilege to one or more users or roles +for a database or a table using the `GRANT INSERT` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Alter +version: 1.0 + +[ClickHouse] SHALL support granting the **alter** privilege to one or more users or roles +for a database or a table using the `GRANT ALTER` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Create +version: 1.0 + +[ClickHouse] SHALL support granting the **create** privilege to one or more users or roles +using the `GRANT CREATE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Drop +version: 1.0 + +[ClickHouse] SHALL support granting the **drop** privilege to one or more users or roles +using the `GRANT DROP` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Truncate +version: 1.0 + +[ClickHouse] SHALL support granting the **truncate** privilege to one or more users or roles +for a database or a table using `GRANT TRUNCATE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Optimize +version: 1.0 + +[ClickHouse] SHALL support granting the **optimize** privilege to one or more users or roles +for a database or a table using `GRANT OPTIMIZE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Show +version: 1.0 + +[ClickHouse] SHALL support granting the **show** privilege to one or more users or roles +for a database or a table using `GRANT SHOW` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.KillQuery +version: 1.0 + +[ClickHouse] SHALL support granting the **kill query** privilege to one or more users or roles +for a database or a table using `GRANT KILL QUERY` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement +version: 1.0 + +[ClickHouse] SHALL support granting the **access management** privileges to one or more users or roles +for a database or a table using `GRANT ACCESS MANAGEMENT` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.System +version: 1.0 + +[ClickHouse] SHALL support granting the **system** privileges to one or more users or roles +for a database or a table using `GRANT SYSTEM` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Introspection +version: 1.0 + +[ClickHouse] SHALL support granting the **introspection** privileges to one or more users or roles +for a database or a table using `GRANT INTROSPECTION` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Sources +version: 1.0 + +[ClickHouse] SHALL support granting the **sources** privileges to one or more users or roles +for a database or a table using `GRANT SOURCES` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.DictGet +version: 1.0 + +[ClickHouse] SHALL support granting the **dictGet** privilege to one or more users or roles +for a database or a table using `GRANT dictGet` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.None +version: 1.0 + +[ClickHouse] SHALL support granting no privileges to one or more users or roles +for a database or a table using `GRANT NONE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.All +version: 1.0 + +[ClickHouse] SHALL support granting the **all** privileges to one or more users or roles +using the `GRANT ALL` or `GRANT ALL PRIVILEGES` statements. + +#### RQ.SRS-006.RBAC.Grant.Privilege.GrantOption +version: 1.0 + +[ClickHouse] SHALL support granting the **grant option** privilege to one or more users or roles +for a database or a table using the `WITH GRANT OPTION` clause in the `GRANT` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.On +version: 1.0 + +[ClickHouse] SHALL support the `ON` clause in the `GRANT` privilege statement +which SHALL allow to specify one or more tables to which the privilege SHALL +be granted using the following patterns + +* `*.*` any table in any database +* `database.*` any table in the specified database +* `database.table` specific table in the specified database +* `*` any table in the current database +* `table` specific table in the current database + +#### RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns +version: 1.0 + +[ClickHouse] SHALL support granting the privilege **some_privilege** to one or more users or roles +for a database or a table using the `GRANT some_privilege(column)` statement for one column. +Multiple columns will be supported with `GRANT some_privilege(column1, column2...)` statement. +The privileges will be granted for only the specified columns. + +#### RQ.SRS-006.RBAC.Grant.Privilege.OnCluster +version: 1.0 + +[ClickHouse] SHALL support specifying cluster on which to grant privileges using the `ON CLUSTER` +clause in the `GRANT PRIVILEGE` statement. + +#### RQ.SRS-006.RBAC.Grant.Privilege.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for the `GRANT` statement that +grants explicit privileges to a user or a role. + +```sql +GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...] + ON {db.table|db.*|*.*|table|*} + TO {user | role | CURRENT_USER} [,...] + [WITH GRANT OPTION] +``` + +### Revoke + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Cluster +version: 1.0 + +[ClickHouse] SHALL support revoking privileges to one or more users or roles +for a database or a table on some specific cluster using the `REVOKE ON CLUSTER cluster_name` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Select +version: 1.0 + +[ClickHouse] SHALL support revoking the **select** privilege to one or more users or roles +for a database or a table using the `REVOKE SELECT` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Insert +version: 1.0 + +[ClickHouse] SHALL support revoking the **insert** privilege to one or more users or roles +for a database or a table using the `REVOKE INSERT` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Alter +version: 1.0 + +[ClickHouse] SHALL support revoking the **alter** privilege to one or more users or roles +for a database or a table using the `REVOKE ALTER` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Create +version: 1.0 + +[ClickHouse] SHALL support revoking the **create** privilege to one or more users or roles +using the `REVOKE CREATE` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Drop +version: 1.0 + +[ClickHouse] SHALL support revoking the **drop** privilege to one or more users or roles +using the `REVOKE DROP` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Truncate +version: 1.0 + +[ClickHouse] SHALL support revoking the **truncate** privilege to one or more users or roles +for a database or a table using the `REVOKE TRUNCATE` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Optimize +version: 1.0 + +[ClickHouse] SHALL support revoking the **optimize** privilege to one or more users or roles +for a database or a table using the `REVOKE OPTIMIZE` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Show +version: 1.0 + +[ClickHouse] SHALL support revoking the **show** privilege to one or more users or roles +for a database or a table using the `REVOKE SHOW` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery +version: 1.0 + +[ClickHouse] SHALL support revoking the **kill query** privilege to one or more users or roles +for a database or a table using the `REVOKE KILL QUERY` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement +version: 1.0 + +[ClickHouse] SHALL support revoking the **access management** privilege to one or more users or roles +for a database or a table using the `REVOKE ACCESS MANAGEMENT` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.System +version: 1.0 + +[ClickHouse] SHALL support revoking the **system** privilege to one or more users or roles +for a database or a table using the `REVOKE SYSTEM` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Introspection +version: 1.0 + +[ClickHouse] SHALL support revoking the **introspection** privilege to one or more users or roles +for a database or a table using the `REVOKE INTROSPECTION` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Sources +version: 1.0 + +[ClickHouse] SHALL support revoking the **sources** privilege to one or more users or roles +for a database or a table using the `REVOKE SOURCES` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.DictGet +version: 1.0 + +[ClickHouse] SHALL support revoking the **dictGet** privilege to one or more users or roles +for a database or a table using the `REVOKE dictGet` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.PrivilegeColumns +version: 1.0 + +[ClickHouse] SHALL support revoking the privilege **some_privilege** to one or more users or roles +for a database or a table using the `REVOKE some_privilege(column)` statement for one column. +Multiple columns will be supported with `REVOKE some_privilege(column1, column2...)` statement. +The privileges will be revoked for only the specified columns. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Multiple +version: 1.0 + +[ClickHouse] SHALL support revoking MULTIPLE **privileges** to one or more users or roles +for a database or a table using the `REVOKE privilege1, privilege2...` statement. +**privileges** refers to any set of Clickhouse defined privilege, whose hierarchy includes +SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE, SHOW, KILL QUERY, ACCESS MANAGEMENT, +SYSTEM, INTROSPECTION, SOURCES, dictGet and all of their sub-privileges. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.All +version: 1.0 + +[ClickHouse] SHALL support revoking **all** privileges to one or more users or roles +for a database or a table using the `REVOKE ALL` or `REVOKE ALL PRIVILEGES` statements. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.None +version: 1.0 + +[ClickHouse] SHALL support revoking **no** privileges to one or more users or roles +for a database or a table using the `REVOKE NONE` statement. + +#### RQ.SRS-006.RBAC.Revoke.Privilege.On +version: 1.0 + +[ClickHouse] SHALL support the `ON` clause in the `REVOKE` privilege statement +which SHALL allow to specify one or more tables to which the privilege SHALL +be revoked using the following patterns + +* `db.table` specific table in the specified database +* `db.*` any table in the specified database +* `*.*` any table in any database +* `table` specific table in the current database +* `*` any table in the current database + +#### RQ.SRS-006.RBAC.Revoke.Privilege.From +version: 1.0 + +[ClickHouse] SHALL support the `FROM` clause in the `REVOKE` privilege statement +which SHALL allow to specify one or more users to which the privilege SHALL +be revoked using the following patterns + +* `{user | CURRENT_USER} [,...]` some combination of users by name, which may include the current user +* `ALL` all users +* `ALL EXCEPT {user | CURRENT_USER} [,...]` the logical reverse of the first pattern + +#### RQ.SRS-006.RBAC.Revoke.Privilege.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for the `REVOKE` statement that +revokes explicit privileges of a user or a role. + +```sql +REVOKE [ON CLUSTER cluster_name] privilege + [(column_name [,...])] [,...] + ON {db.table|db.*|*.*|table|*} + FROM {user | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user | CURRENT_USER} [,...] +``` + +### Grant Role + +#### RQ.SRS-006.RBAC.Grant.Role +version: 1.0 + +[ClickHouse] SHALL support granting one or more roles to +one or more users or roles using the `GRANT` role statement. + +#### RQ.SRS-006.RBAC.Grant.Role.CurrentUser +version: 1.0 + +[ClickHouse] SHALL support granting one or more roles to current user using +`TO CURRENT_USER` clause in the `GRANT` role statement. + +#### RQ.SRS-006.RBAC.Grant.Role.AdminOption +version: 1.0 + +[ClickHouse] SHALL support granting `admin option` privilege +to one or more users or roles using the `WITH ADMIN OPTION` clause +in the `GRANT` role statement. + +#### RQ.SRS-006.RBAC.Grant.Role.OnCluster +version: 1.0 + +[ClickHouse] SHALL support specifying cluster on which the user is to be granted one or more roles +using `ON CLUSTER` clause in the `GRANT` statement. + +#### RQ.SRS-006.RBAC.Grant.Role.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for `GRANT` role statement + +``` sql +GRANT + ON CLUSTER cluster_name + role [, role ...] + TO {user | role | CURRENT_USER} [,...] + [WITH ADMIN OPTION] +``` + +### Revoke Role + +#### RQ.SRS-006.RBAC.Revoke.Role +version: 1.0 + +[ClickHouse] SHALL support revoking one or more roles from +one or more users or roles using the `REVOKE` role statement. + +#### RQ.SRS-006.RBAC.Revoke.Role.Keywords +version: 1.0 + +[ClickHouse] SHALL support revoking one or more roles from +special groupings of one or more users or roles with the `ALL`, `ALL EXCEPT`, +and `CURRENT_USER` keywords. + +#### RQ.SRS-006.RBAC.Revoke.Role.Cluster +version: 1.0 + +[ClickHouse] SHALL support revoking one or more roles from +one or more users or roles from one or more clusters +using the `REVOKE ON CLUSTER` role statement. + +#### RQ.SRS-006.RBAC.Revoke.AdminOption +version: 1.0 + +[ClickHouse] SHALL support revoking `admin option` privilege +in one or more users or roles using the `ADMIN OPTION FOR` clause +in the `REVOKE` role statement. + +#### RQ.SRS-006.RBAC.Revoke.Role.Syntax +version: 1.0 + +[ClickHouse] SHALL support the following syntax for the `REVOKE` role statement + +```sql +REVOKE [ON CLUSTER cluster_name] [ADMIN OPTION FOR] + role [,...] + FROM {user | role | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...] +``` + +### Show Grants + +#### RQ.SRS-006.RBAC.Show.Grants +version: 1.0 + +[ClickHouse] SHALL support listing all the privileges granted to current user and role +using the `SHOW GRANTS` statement. + +#### RQ.SRS-006.RBAC.Show.Grants.For +version: 1.0 + +[ClickHouse] SHALL support listing all the privileges granted to a user or a role +using the `FOR` clause in the `SHOW GRANTS` statement. + +#### RQ.SRS-006.RBAC.Show.Grants.Syntax +version: 1.0 + +[Clickhouse] SHALL use the following syntax for the `SHOW GRANTS` statement + +``` sql +SHOW GRANTS [FOR user_or_role] +``` + +### Table Privileges + +#### RQ.SRS-006.RBAC.Table.PublicTables version: 1.0 [ClickHouse] SHALL support that a user without any privileges will be able to access the following tables @@ -2850,7 +12869,7 @@ version: 1.0 * system.contributors * system.functions -##### RQ.SRS-006.RBAC.Table.SensitiveTables +#### RQ.SRS-006.RBAC.Table.SensitiveTables version: 1.0 [ClickHouse] SHALL not support a user with no privileges accessing the following `system` tables: @@ -2867,15 +12886,15 @@ version: 1.0 * zookeeper * macros -#### Distributed Tables +### Distributed Tables -##### RQ.SRS-006.RBAC.DistributedTable.Create +#### RQ.SRS-006.RBAC.DistributedTable.Create version: 1.0 [ClickHouse] SHALL successfully `CREATE` a distributed table if and only if the user has **create table** privilege on the table and **remote** privilege on *.* -##### RQ.SRS-006.RBAC.DistributedTable.Select +#### RQ.SRS-006.RBAC.DistributedTable.Select version: 1.0 [ClickHouse] SHALL successfully `SELECT` from a distributed table if and only if @@ -2883,7 +12902,7 @@ the user has **select** privilege on the table and on the remote table specified Does not require **select** privilege for the remote table if the remote table does not exist on the same server as the user. -##### RQ.SRS-006.RBAC.DistributedTable.Insert +#### RQ.SRS-006.RBAC.DistributedTable.Insert version: 1.0 [ClickHouse] SHALL successfully `INSERT` into a distributed table if and only if @@ -2892,7 +12911,7 @@ the user has **insert** privilege on the table and on the remote table specified Does not require **insert** privilege for the remote table if the remote table does not exist on the same server as the user, insert executes into the remote table on a different server. -##### RQ.SRS-006.RBAC.DistributedTable.SpecialTables +#### RQ.SRS-006.RBAC.DistributedTable.SpecialTables version: 1.0 [ClickHouse] SHALL successfully execute a query using a distributed table that uses one of the special tables if and only if @@ -2902,29 +12921,29 @@ Special tables include: * distributed table * source table of a materialized view -##### RQ.SRS-006.RBAC.DistributedTable.LocalUser +#### RQ.SRS-006.RBAC.DistributedTable.LocalUser version: 1.0 [ClickHouse] SHALL successfully execute a query using a distributed table from a user present locally, but not remotely. -##### RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges +#### RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges version: 1.0 [ClickHouse] SHALL successfully execute a query using a distributed table by a user that exists on multiple nodes if and only if the user has the required privileges on the node the query is being executed from. -#### Views +### Views -##### View +#### View -###### RQ.SRS-006.RBAC.View +##### RQ.SRS-006.RBAC.View version: 1.0 [ClickHouse] SHALL support controlling access to **create**, **select** and **drop** privileges for a view for users or roles. -###### RQ.SRS-006.RBAC.View.Create +##### RQ.SRS-006.RBAC.View.Create version: 1.0 [ClickHouse] SHALL only successfully execute a `CREATE VIEW` command if and only if @@ -2942,7 +12961,7 @@ CREATE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL CREATE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2 ``` -###### RQ.SRS-006.RBAC.View.Select +##### RQ.SRS-006.RBAC.View.Select version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from a view if and only if @@ -2962,21 +12981,21 @@ CREATE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2 SELECT * FROM view ``` -###### RQ.SRS-006.RBAC.View.Drop +##### RQ.SRS-006.RBAC.View.Drop version: 1.0 [ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if the user has **drop view** privilege on that view either explicitly or through a role. -##### Materialized View +#### Materialized View -###### RQ.SRS-006.RBAC.MaterializedView +##### RQ.SRS-006.RBAC.MaterializedView version: 1.0 [ClickHouse] SHALL support controlling access to **create**, **select**, **alter** and **drop** privileges for a materialized view for users or roles. -###### RQ.SRS-006.RBAC.MaterializedView.Create +##### RQ.SRS-006.RBAC.MaterializedView.Create version: 1.0 [ClickHouse] SHALL only successfully execute a `CREATE MATERIALIZED VIEW` command if and only if @@ -3008,7 +13027,7 @@ For example, CREATE MATERIALIZED VIEW view TO target_table AS SELECT * FROM source_table ``` -###### RQ.SRS-006.RBAC.MaterializedView.Select +##### RQ.SRS-006.RBAC.MaterializedView.Select version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from a materialized view if and only if @@ -3028,25 +13047,25 @@ CREATE MATERIALIZED VIEW view0 ENGINE = Memory AS SELECT column FROM view1 UNION SELECT * FROM view ``` -###### RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable +##### RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from the target table, implicit or explicit, of a materialized view if and only if the user has `SELECT` privilege for the table, either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable +##### RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from the source table of a materialized view if and only if the user has `SELECT` privilege for the table, either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.Drop +##### RQ.SRS-006.RBAC.MaterializedView.Drop version: 1.0 [ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if the user has **drop view** privilege on that view either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.ModifyQuery +##### RQ.SRS-006.RBAC.MaterializedView.ModifyQuery version: 1.0 [ClickHouse] SHALL only successfully execute a `MODIFY QUERY` command if and only if @@ -3059,33 +13078,33 @@ For example, ALTER TABLE view MODIFY QUERY SELECT * FROM source_table ``` -###### RQ.SRS-006.RBAC.MaterializedView.Insert +##### RQ.SRS-006.RBAC.MaterializedView.Insert version: 1.0 [ClickHouse] SHALL only succesfully `INSERT` into a materialized view if and only if the user has `INSERT` privilege on the view, either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable +##### RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable version: 1.0 [ClickHouse] SHALL only succesfully `INSERT` into a source table of a materialized view if and only if the user has `INSERT` privilege on the source table, either explicitly or through a role. -###### RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable +##### RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable version: 1.0 [ClickHouse] SHALL only succesfully `INSERT` into a target table of a materialized view if and only if the user has `INSERT` privelege on the target table, either explicitly or through a role. -##### Live View +#### Live View -###### RQ.SRS-006.RBAC.LiveView +##### RQ.SRS-006.RBAC.LiveView version: 1.0 [ClickHouse] SHALL support controlling access to **create**, **select**, **alter** and **drop** privileges for a live view for users or roles. -###### RQ.SRS-006.RBAC.LiveView.Create +##### RQ.SRS-006.RBAC.LiveView.Create version: 1.0 [ClickHouse] SHALL only successfully execute a `CREATE LIVE VIEW` command if and only if @@ -3103,7 +13122,7 @@ CREATE LIVE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNIO CREATE LIVE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2 ``` -###### RQ.SRS-006.RBAC.LiveView.Select +##### RQ.SRS-006.RBAC.LiveView.Select version: 1.0 [ClickHouse] SHALL only successfully `SELECT` from a live view if and only if @@ -3123,28 +13142,28 @@ CREATE LIVE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM SELECT * FROM view ``` -###### RQ.SRS-006.RBAC.LiveView.Drop +##### RQ.SRS-006.RBAC.LiveView.Drop version: 1.0 [ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if the user has **drop view** privilege on that view either explicitly or through a role. -###### RQ.SRS-006.RBAC.LiveView.Refresh +##### RQ.SRS-006.RBAC.LiveView.Refresh version: 1.0 [ClickHouse] SHALL only successfully execute an `ALTER LIVE VIEW REFRESH` command if and only if the user has **refresh** privilege on that view either explicitly or through a role. -#### Select +### Select -##### RQ.SRS-006.RBAC.Select +#### RQ.SRS-006.RBAC.Select version: 1.0 [ClickHouse] SHALL execute `SELECT` if and only if the user has the **select** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -##### RQ.SRS-006.RBAC.Select.Column +#### RQ.SRS-006.RBAC.Select.Column version: 1.0 [ClickHouse] SHALL support granting or revoking **select** privilege @@ -3153,7 +13172,7 @@ Any `SELECT` statements SHALL not to be executed, unless the user has the **select** privilege for the destination column either because of the explicit grant or through one of the roles assigned to the user. -##### RQ.SRS-006.RBAC.Select.Cluster +#### RQ.SRS-006.RBAC.Select.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **select** privilege @@ -3161,7 +13180,7 @@ on a specified cluster to one or more **users** or **roles**. Any `SELECT` statements SHALL succeed only on nodes where the table exists and privilege was granted. -##### RQ.SRS-006.RBAC.Select.TableEngines +#### RQ.SRS-006.RBAC.Select.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **select** privilege @@ -3182,16 +13201,16 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -#### Insert +### Insert -##### RQ.SRS-006.RBAC.Insert +#### RQ.SRS-006.RBAC.Insert version: 1.0 [ClickHouse] SHALL execute `INSERT INTO` if and only if the user has the **insert** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -##### RQ.SRS-006.RBAC.Insert.Column +#### RQ.SRS-006.RBAC.Insert.Column version: 1.0 [ClickHouse] SHALL support granting or revoking **insert** privilege @@ -3200,7 +13219,7 @@ Any `INSERT INTO` statements SHALL not to be executed, unless the user has the **insert** privilege for the destination column either because of the explicit grant or through one of the roles assigned to the user. -##### RQ.SRS-006.RBAC.Insert.Cluster +#### RQ.SRS-006.RBAC.Insert.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **insert** privilege @@ -3208,7 +13227,7 @@ on a specified cluster to one or more **users** or **roles**. Any `INSERT INTO` statements SHALL succeed only on nodes where the table exists and privilege was granted. -##### RQ.SRS-006.RBAC.Insert.TableEngines +#### RQ.SRS-006.RBAC.Insert.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **insert** privilege @@ -3229,11 +13248,11 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -#### Alter +### Alter -##### Alter Column +#### Alter Column -###### RQ.SRS-006.RBAC.Privileges.AlterColumn +##### RQ.SRS-006.RBAC.Privileges.AlterColumn version: 1.0 [ClickHouse] SHALL support controlling access to the **alter column** privilege @@ -3243,19 +13262,19 @@ return an error, unless the user has the **alter column** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant version: 1.0 [ClickHouse] SHALL support granting **alter column** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter column** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.Column +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.Column version: 1.0 [ClickHouse] SHALL support granting or revoking **alter column** privilege @@ -3264,7 +13283,7 @@ Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN` statements SHALL retu unless the user has the **alter column** privilege for the destination column either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter column** privilege @@ -3272,7 +13291,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter column** privilege @@ -3293,9 +13312,9 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Index +#### Alter Index -###### RQ.SRS-006.RBAC.Privileges.AlterIndex +##### RQ.SRS-006.RBAC.Privileges.AlterIndex version: 1.0 [ClickHouse] SHALL support controlling access to the **alter index** privilege @@ -3305,19 +13324,19 @@ return an error, unless the user has the **alter index** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant version: 1.0 [ClickHouse] SHALL support granting **alter index** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter index** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter index** privilege @@ -3325,7 +13344,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... ORDER BY | ADD|DROP|MATERIALIZE|CLEAR INDEX` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter index** privilege @@ -3346,9 +13365,9 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Constraint +#### Alter Constraint -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint version: 1.0 [ClickHouse] SHALL support controlling access to the **alter constraint** privilege @@ -3358,19 +13377,19 @@ return an error, unless the user has the **alter constraint** privilege for the destination table either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant version: 1.0 [ClickHouse] SHALL support granting **alter constraint** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter constraint** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter constraint** privilege @@ -3378,7 +13397,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... ADD|DROP CONSTRAINT` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter constraint** privilege @@ -3399,9 +13418,9 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter TTL +#### Alter TTL -###### RQ.SRS-006.RBAC.Privileges.AlterTTL +##### RQ.SRS-006.RBAC.Privileges.AlterTTL version: 1.0 [ClickHouse] SHALL support controlling access to the **alter ttl** or **alter materialize ttl** privilege @@ -3411,19 +13430,19 @@ return an error, unless the user has the **alter ttl** or **alter materialize tt the destination table either because of the explicit grant or through one of the roles assigned to the user. -###### RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant version: 1.0 [ClickHouse] SHALL support granting **alter ttl** or **alter materialize ttl** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter ttl** or **alter materialize ttl** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter ttl** or **alter materialize ttl** privilege @@ -3431,7 +13450,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... ALTER TTL | ALTER MATERIALIZE TTL` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter ttl** or **alter materialize ttl** privilege @@ -3439,9 +13458,9 @@ on tables created using the following engines * MergeTree -##### Alter Settings +#### Alter Settings -###### RQ.SRS-006.RBAC.Privileges.AlterSettings +##### RQ.SRS-006.RBAC.Privileges.AlterSettings version: 1.0 [ClickHouse] SHALL support controlling access to the **alter settings** privilege @@ -3452,19 +13471,19 @@ the destination table either because of the explicit grant or through one of the roles assigned to the user. The **alter settings** privilege allows modifying table engine settings. It doesn’t affect settings or server configuration parameters. -###### RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant version: 1.0 [ClickHouse] SHALL support granting **alter settings** privilege for a database or a specific table to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter settings** privilege for a database or a specific table to one or more **users** or **roles** -###### RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster +##### RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster version: 1.0 [ClickHouse] SHALL support granting or revoking **alter settings** privilege @@ -3472,7 +13491,7 @@ on a specified cluster to one or more **users** or **roles**. Any `ALTER TABLE ... MODIFY SETTING setting` statements SHALL succeed only on nodes where the table exists and privilege was granted. -###### RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter settings** privilege @@ -3493,27 +13512,27 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Update +#### Alter Update -###### RQ.SRS-006.RBAC.Privileges.AlterUpdate +##### RQ.SRS-006.RBAC.Privileges.AlterUpdate version: 1.0 [ClickHouse] SHALL successfully execute `ALTER UPDATE` statement if and only if the user has **alter update** privilege for that column, either directly or through a role. -###### RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant version: 1.0 [ClickHouse] SHALL support granting **alter update** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter update** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter update** privilege @@ -3534,27 +13553,27 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Delete +#### Alter Delete -###### RQ.SRS-006.RBAC.Privileges.AlterDelete +##### RQ.SRS-006.RBAC.Privileges.AlterDelete version: 1.0 [ClickHouse] SHALL successfully execute `ALTER DELETE` statement if and only if the user has **alter delete** privilege for that table, either directly or through a role. -###### RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant version: 1.0 [ClickHouse] SHALL support granting **alter delete** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter delete** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter delete** privilege @@ -3575,27 +13594,27 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Freeze Partition +#### Alter Freeze Partition -###### RQ.SRS-006.RBAC.Privileges.AlterFreeze +##### RQ.SRS-006.RBAC.Privileges.AlterFreeze version: 1.0 [ClickHouse] SHALL successfully execute `ALTER FREEZE` statement if and only if the user has **alter freeze** privilege for that table, either directly or through a role. -###### RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant version: 1.0 [ClickHouse] SHALL support granting **alter freeze** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter freeze** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter freeze** privilege @@ -3616,27 +13635,27 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Fetch Partition +#### Alter Fetch Partition -###### RQ.SRS-006.RBAC.Privileges.AlterFetch +##### RQ.SRS-006.RBAC.Privileges.AlterFetch version: 1.0 [ClickHouse] SHALL successfully execute `ALTER FETCH` statement if and only if the user has **alter fetch** privilege for that table, either directly or through a role. -###### RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant version: 1.0 [ClickHouse] SHALL support granting **alter fetch** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter fetch** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter fetch** privilege @@ -3650,9 +13669,9 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree -##### Alter Move Partition +#### Alter Move Partition -###### RQ.SRS-006.RBAC.Privileges.AlterMove +##### RQ.SRS-006.RBAC.Privileges.AlterMove version: 1.0 [ClickHouse] SHALL successfully execute `ALTER MOVE` statement if and only if the user has **alter move**, **select**, and **alter delete** privilege on the source table @@ -3662,19 +13681,19 @@ For example, ALTER TABLE source_table MOVE PARTITION 1 TO target_table ``` -###### RQ.SRS-006.RBAC.Privileges.AlterMove.Grant +##### RQ.SRS-006.RBAC.Privileges.AlterMove.Grant version: 1.0 [ClickHouse] SHALL support granting **alter move** privilege on a column level to one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke +##### RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke version: 1.0 [ClickHouse] SHALL support revoking **alter move** privilege on a column level from one or more **users** or **roles**. -###### RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines +##### RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines version: 1.0 [ClickHouse] SHALL support controlling access to the **alter move** privilege @@ -3695,6 +13714,8 @@ on tables created using the following engines * ReplicatedVersionedCollapsingMergeTree * ReplicatedGraphiteMergeTree +### Create + #### RQ.SRS-006.RBAC.Privileges.CreateTable version: 1.0 @@ -3731,6 +13752,8 @@ version: 1.0 [ClickHouse] SHALL successfully execute `CREATE TEMPORARY TABLE` statement if and only if the user has **create temporary table** privilege on the table, either directly or through a role. +### Attach + #### RQ.SRS-006.RBAC.Privileges.AttachDatabase version: 1.0 @@ -3755,6 +13778,8 @@ version: 1.0 [ClickHouse] SHALL successfully execute `ATTACH TABLE` statement if and only if the user has **create table** privilege on the table, either directly or through a role. +### Drop + #### RQ.SRS-006.RBAC.Privileges.DropTable version: 1.0 @@ -3773,6 +13798,8 @@ version: 1.0 [ClickHouse] SHALL successfully execute `DROP DICTIONARY` statement if and only if the user has **drop dictionary** privilege on the dictionary, either directly or through a role. +### Detach + #### RQ.SRS-006.RBAC.Privileges.DetachTable version: 1.0 @@ -3797,354 +13824,360 @@ version: 1.0 [ClickHouse] SHALL successfully execute `DETACH DICTIONARY` statement if and only if the user has **drop dictionary** privilege on the dictionary, either directly or through a role. +### Truncate + #### RQ.SRS-006.RBAC.Privileges.Truncate version: 1.0 [ClickHouse] SHALL successfully execute `TRUNCATE TABLE` statement if and only if the user has **truncate table** privilege on the table, either directly or through a role. +### Optimize + #### RQ.SRS-006.RBAC.Privileges.Optimize version: 1.0 [ClickHouse] SHALL successfully execute `OPTIMIZE TABLE` statement if and only if the user has **optimize table** privilege on the table, either directly or through a role. +### Kill Query + #### RQ.SRS-006.RBAC.Privileges.KillQuery version: 1.0 [ClickHouse] SHALL successfully execute `KILL QUERY` statement if and only if the user has **kill query** privilege, either directly or through a role. -#### Kill Mutation +### Kill Mutation -##### RQ.SRS-006.RBAC.Privileges.KillMutation +#### RQ.SRS-006.RBAC.Privileges.KillMutation version: 1.0 [ClickHouse] SHALL successfully execute `KILL MUTATION` statement if and only if the user has the privilege that created the mutation, either directly or through a role. For example, to `KILL MUTATION` after `ALTER UPDATE` query, the user needs `ALTER UPDATE` privilege. -##### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate +#### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate version: 1.0 [ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER UPDATE` mutation if and only if the user has `ALTER UPDATE` privilege on the table where the mutation was created, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete +#### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete version: 1.0 [ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER DELETE` mutation if and only if the user has `ALTER DELETE` privilege on the table where the mutation was created, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn +#### RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn version: 1.0 [ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER DROP COLUMN` mutation if and only if the user has `ALTER DROP COLUMN` privilege on the table where the mutation was created, either directly or through a role. -#### Show +### Show -##### RQ.SRS-006.RBAC.ShowTables.Privilege +#### RQ.SRS-006.RBAC.ShowTables.Privilege version: 1.0 [ClickHouse] SHALL grant **show tables** privilege on a table to a user if that user has recieved any grant, including `SHOW TABLES`, on that table, either directly or through a role. -##### RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW TABLES` statement if and only if the user has **show tables** privilege, or any privilege on the table either directly or through a role. -##### RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege +#### RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `EXISTS table` statement if and only if the user has **show tables** privilege, or any privilege on the table either directly or through a role. -##### RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege +#### RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `CHECK table` statement if and only if the user has **show tables** privilege, or any privilege on the table either directly or through a role. -##### RQ.SRS-006.RBAC.ShowDatabases.Privilege +#### RQ.SRS-006.RBAC.ShowDatabases.Privilege version: 1.0 [ClickHouse] SHALL grant **show databases** privilege on a database to a user if that user has recieved any grant, including `SHOW DATABASES`, on that table, either directly or through a role. -##### RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW DATABASES` statement if and only if the user has **show databases** privilege, or any privilege on the database either directly or through a role. -##### RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE DATABASE` statement if and only if the user has **show databases** privilege, or any privilege on the database either directly or through a role. -##### RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege +#### RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `USE database` statement if and only if the user has **show databases** privilege, or any privilege on the database either directly or through a role. -##### RQ.SRS-006.RBAC.ShowColumns.Privilege +#### RQ.SRS-006.RBAC.ShowColumns.Privilege version: 1.0 [ClickHouse] SHALL support granting or revoking the `SHOW COLUMNS` privilege. -##### RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE TABLE` statement if and only if the user has **show columns** privilege on that table, either directly or through a role. -##### RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege +#### RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `DESCRIBE table` statement if and only if the user has **show columns** privilege on that table, either directly or through a role. -##### RQ.SRS-006.RBAC.ShowDictionaries.Privilege +#### RQ.SRS-006.RBAC.ShowDictionaries.Privilege version: 1.0 [ClickHouse] SHALL grant **show dictionaries** privilege on a dictionary to a user if that user has recieved any grant, including `SHOW DICTIONARIES`, on that dictionary, either directly or through a role. -##### RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW DICTIONARIES` statement if and only if the user has **show dictionaries** privilege, or any privilege on the dictionary either directly or through a role. -##### RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege +#### RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE DICTIONARY` statement if and only if the user has **show dictionaries** privilege, or any privilege on the dictionary either directly or through a role. -##### RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege +#### RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `EXISTS dictionary` statement if and only if the user has **show dictionaries** privilege, or any privilege on the dictionary either directly or through a role. -#### Access Management +### Access Management -##### RQ.SRS-006.RBAC.Privileges.CreateUser +#### RQ.SRS-006.RBAC.Privileges.CreateUser version: 1.0 [ClickHouse] SHALL successfully execute `CREATE USER` statement if and only if the user has **create user** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole +#### RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole version: 1.0 [ClickHouse] SHALL successfully execute `CREATE USER` statement with `DEFAULT ROLE ` clause if and only if the user has **create user** privilege and the role with **admin option**, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterUser +#### RQ.SRS-006.RBAC.Privileges.AlterUser version: 1.0 [ClickHouse] SHALL successfully execute `ALTER USER` statement if and only if the user has **alter user** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropUser +#### RQ.SRS-006.RBAC.Privileges.DropUser version: 1.0 [ClickHouse] SHALL successfully execute `DROP USER` statement if and only if the user has **drop user** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateRole +#### RQ.SRS-006.RBAC.Privileges.CreateRole version: 1.0 [ClickHouse] SHALL successfully execute `CREATE ROLE` statement if and only if the user has **create role** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterRole +#### RQ.SRS-006.RBAC.Privileges.AlterRole version: 1.0 [ClickHouse] SHALL successfully execute `ALTER ROLE` statement if and only if the user has **alter role** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropRole +#### RQ.SRS-006.RBAC.Privileges.DropRole version: 1.0 [ClickHouse] SHALL successfully execute `DROP ROLE` statement if and only if the user has **drop role** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateRowPolicy +#### RQ.SRS-006.RBAC.Privileges.CreateRowPolicy version: 1.0 [ClickHouse] SHALL successfully execute `CREATE ROW POLICY` statement if and only if the user has **create row policy** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterRowPolicy +#### RQ.SRS-006.RBAC.Privileges.AlterRowPolicy version: 1.0 [ClickHouse] SHALL successfully execute `ALTER ROW POLICY` statement if and only if the user has **alter row policy** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropRowPolicy +#### RQ.SRS-006.RBAC.Privileges.DropRowPolicy version: 1.0 [ClickHouse] SHALL successfully execute `DROP ROW POLICY` statement if and only if the user has **drop row policy** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateQuota +#### RQ.SRS-006.RBAC.Privileges.CreateQuota version: 1.0 [ClickHouse] SHALL successfully execute `CREATE QUOTA` statement if and only if the user has **create quota** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterQuota +#### RQ.SRS-006.RBAC.Privileges.AlterQuota version: 1.0 [ClickHouse] SHALL successfully execute `ALTER QUOTA` statement if and only if the user has **alter quota** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropQuota +#### RQ.SRS-006.RBAC.Privileges.DropQuota version: 1.0 [ClickHouse] SHALL successfully execute `DROP QUOTA` statement if and only if the user has **drop quota** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile +#### RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile version: 1.0 [ClickHouse] SHALL successfully execute `CREATE SETTINGS PROFILE` statement if and only if the user has **create settings profile** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile +#### RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile version: 1.0 [ClickHouse] SHALL successfully execute `ALTER SETTINGS PROFILE` statement if and only if the user has **alter settings profile** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.DropSettingsProfile +#### RQ.SRS-006.RBAC.Privileges.DropSettingsProfile version: 1.0 [ClickHouse] SHALL successfully execute `DROP SETTINGS PROFILE` statement if and only if the user has **drop settings profile** privilege, or either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.RoleAdmin +#### RQ.SRS-006.RBAC.Privileges.RoleAdmin version: 1.0 [ClickHouse] SHALL successfully execute any role grant or revoke by a user with `ROLE ADMIN` privilege. -##### Show Access +#### Show Access -###### RQ.SRS-006.RBAC.ShowUsers.Privilege +##### RQ.SRS-006.RBAC.ShowUsers.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW USERS` privilege when the user is granted `SHOW USERS`, `SHOW CREATE USER`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW USERS` statement if and only if the user has **show users** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE USER` statement if and only if the user has **show users** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowRoles.Privilege +##### RQ.SRS-006.RBAC.ShowRoles.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW ROLES` privilege when the user is granted `SHOW ROLES`, `SHOW CREATE ROLE`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW ROLES` statement if and only if the user has **show roles** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE ROLE` statement if and only if the user has **show roles** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowRowPolicies.Privilege +##### RQ.SRS-006.RBAC.ShowRowPolicies.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW ROW POLICIES` privilege when the user is granted `SHOW ROW POLICIES`, `SHOW POLICIES`, `SHOW CREATE ROW POLICY`, `SHOW CREATE POLICY`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW ROW POLICIES` or `SHOW POLICIES` statement if and only if the user has **show row policies** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE ROW POLICY` or `SHOW CREATE POLICY` statement if and only if the user has **show row policies** privilege,either directly or through a role. -###### RQ.SRS-006.RBAC.ShowQuotas.Privilege +##### RQ.SRS-006.RBAC.ShowQuotas.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW QUOTAS` privilege when the user is granted `SHOW QUOTAS`, `SHOW CREATE QUOTA`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW QUOTAS` statement if and only if the user has **show quotas** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE QUOTA` statement if and only if the user has **show quotas** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege +##### RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `SHOW SETTINGS PROFILES` privilege when the user is granted `SHOW SETTINGS PROFILES`, `SHOW PROFILES`, `SHOW CREATE SETTINGS PROFILE`, `SHOW SETTINGS PROFILE`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`. -###### RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW SETTINGS PROFILES` or `SHOW PROFILES` statement if and only if the user has **show settings profiles** privilege, either directly or through a role. -###### RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege +##### RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `SHOW CREATE SETTINGS PROFILE` or `SHOW CREATE PROFILE` statement if and only if the user has **show settings profiles** privilege, either directly or through a role. -#### dictGet +### dictGet -##### RQ.SRS-006.RBAC.dictGet.Privilege +#### RQ.SRS-006.RBAC.dictGet.Privilege version: 1.0 [ClickHouse] SHALL successfully grant `dictGet` privilege when the user is granted `dictGet`, `dictHas`, `dictGetHierarchy`, or `dictIsIn`. -##### RQ.SRS-006.RBAC.dictGet.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictGet.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictGet` statement if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role. -##### RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictGet[TYPE]` statement @@ -4166,270 +14199,283 @@ Available types: * UUID * String -##### RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictGetOrDefault` statement if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role. -##### RQ.SRS-006.RBAC.dictHas.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictHas.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictHas` statement if and only if the user has **dictGet** privilege, either directly or through a role. -##### RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictGetHierarchy` statement if and only if the user has **dictGet** privilege, either directly or through a role. -##### RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege +#### RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege version: 1.0 [ClickHouse] SHALL successfully execute `dictIsIn` statement if and only if the user has **dictGet** privilege, either directly or through a role. -#### Introspection +### Introspection -##### RQ.SRS-006.RBAC.Privileges.Introspection +#### RQ.SRS-006.RBAC.Privileges.Introspection version: 1.0 [ClickHouse] SHALL successfully grant `INTROSPECTION` privilege when the user is granted `INTROSPECTION` or `INTROSPECTION FUNCTIONS`. -##### RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine +#### RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine version: 1.0 [ClickHouse] SHALL successfully execute `addressToLine` statement if and only if the user has **introspection** privilege, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol +#### RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol version: 1.0 [ClickHouse] SHALL successfully execute `addressToSymbol` statement if and only if the user has **introspection** privilege, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Introspection.demangle +#### RQ.SRS-006.RBAC.Privileges.Introspection.demangle version: 1.0 [ClickHouse] SHALL successfully execute `demangle` statement if and only if the user has **introspection** privilege, either directly or through a role. -#### System +### System -##### RQ.SRS-006.RBAC.Privileges.System.Shutdown +#### RQ.SRS-006.RBAC.Privileges.System.Shutdown version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM SHUTDOWN` privilege when the user is granted `SYSTEM`, `SYSTEM SHUTDOWN`, `SHUTDOWN`,or `SYSTEM KILL`. -##### RQ.SRS-006.RBAC.Privileges.System.DropCache +#### RQ.SRS-006.RBAC.Privileges.System.DropCache version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DROP CACHE` privilege when the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, or `DROP CACHE`. -##### RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS +#### RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DROP DNS CACHE` privilege when the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP DNS CACHE`, `SYSTEM DROP DNS`, `DROP DNS CACHE`, or `DROP DNS`. -##### RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark +#### RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DROP MARK CACHE` privilege when the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP MARK CACHE`, `SYSTEM DROP MARK`, `DROP MARK CACHE`, or `DROP MARKS`. -##### RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed +#### RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DROP UNCOMPRESSED CACHE` privilege when the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP UNCOMPRESSED CACHE`, `SYSTEM DROP UNCOMPRESSED`, `DROP UNCOMPRESSED CACHE`, or `DROP UNCOMPRESSED`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload +#### RQ.SRS-006.RBAC.Privileges.System.Reload version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD` privilege when the user is granted `SYSTEM` or `SYSTEM RELOAD`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload.Config +#### RQ.SRS-006.RBAC.Privileges.System.Reload.Config version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD CONFIG` privilege when the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD CONFIG`, or `RELOAD CONFIG`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary +#### RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD DICTIONARY` privilege when the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARIES`, `RELOAD DICTIONARIES`, or `RELOAD DICTIONARY`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries +#### RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD DICTIONARIES` privilege when the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARIES`, `RELOAD DICTIONARIES`, or `RELOAD DICTIONARY`. -##### RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries +#### RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RELOAD EMBEDDED DICTIONARIES` privilege when the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARY ON *.*`, or `SYSTEM RELOAD EMBEDDED DICTIONARIES`. -##### RQ.SRS-006.RBAC.Privileges.System.Merges +#### RQ.SRS-006.RBAC.Privileges.System.Merges version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM MERGES` privilege when the user is granted `SYSTEM`, `SYSTEM MERGES`, `SYSTEM STOP MERGES`, `SYSTEM START MERGES`, `STOP MERGES`, or `START MERGES`. -##### RQ.SRS-006.RBAC.Privileges.System.TTLMerges +#### RQ.SRS-006.RBAC.Privileges.System.TTLMerges version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM TTL MERGES` privilege when the user is granted `SYSTEM`, `SYSTEM TTL MERGES`, `SYSTEM STOP TTL MERGES`, `SYSTEM START TTL MERGES`, `STOP TTL MERGES`, or `START TTL MERGES`. -##### RQ.SRS-006.RBAC.Privileges.System.Fetches +#### RQ.SRS-006.RBAC.Privileges.System.Fetches version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM FETCHES` privilege when the user is granted `SYSTEM`, `SYSTEM FETCHES`, `SYSTEM STOP FETCHES`, `SYSTEM START FETCHES`, `STOP FETCHES`, or `START FETCHES`. -##### RQ.SRS-006.RBAC.Privileges.System.Moves +#### RQ.SRS-006.RBAC.Privileges.System.Moves version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM MOVES` privilege when the user is granted `SYSTEM`, `SYSTEM MOVES`, `SYSTEM STOP MOVES`, `SYSTEM START MOVES`, `STOP MOVES`, or `START MOVES`. -##### RQ.SRS-006.RBAC.Privileges.System.Sends +#### RQ.SRS-006.RBAC.Privileges.System.Sends version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM SENDS` privilege when the user is granted `SYSTEM`, `SYSTEM SENDS`, `SYSTEM STOP SENDS`, `SYSTEM START SENDS`, `STOP SENDS`, or `START SENDS`. -##### RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed +#### RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM DISTRIBUTED SENDS` privilege when the user is granted `SYSTEM`, `SYSTEM DISTRIBUTED SENDS`, `SYSTEM STOP DISTRIBUTED SENDS`, `SYSTEM START DISTRIBUTED SENDS`, `STOP DISTRIBUTED SENDS`, or `START DISTRIBUTED SENDS`. -##### RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated +#### RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM REPLICATED SENDS` privilege when the user is granted `SYSTEM`, `SYSTEM REPLICATED SENDS`, `SYSTEM STOP REPLICATED SENDS`, `SYSTEM START REPLICATED SENDS`, `STOP REPLICATED SENDS`, or `START REPLICATED SENDS`. -##### RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues +#### RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM REPLICATION QUEUES` privilege when the user is granted `SYSTEM`, `SYSTEM REPLICATION QUEUES`, `SYSTEM STOP REPLICATION QUEUES`, `SYSTEM START REPLICATION QUEUES`, `STOP REPLICATION QUEUES`, or `START REPLICATION QUEUES`. -##### RQ.SRS-006.RBAC.Privileges.System.SyncReplica +#### RQ.SRS-006.RBAC.Privileges.System.SyncReplica version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM SYNC REPLICA` privilege when the user is granted `SYSTEM`, `SYSTEM SYNC REPLICA`, or `SYNC REPLICA`. -##### RQ.SRS-006.RBAC.Privileges.System.RestartReplica +#### RQ.SRS-006.RBAC.Privileges.System.RestartReplica version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM RESTART REPLICA` privilege when the user is granted `SYSTEM`, `SYSTEM RESTART REPLICA`, or `RESTART REPLICA`. -##### RQ.SRS-006.RBAC.Privileges.System.Flush +#### RQ.SRS-006.RBAC.Privileges.System.Flush version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM FLUSH` privilege when the user is granted `SYSTEM` or `SYSTEM FLUSH`. -##### RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed +#### RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM FLUSH DISTRIBUTED` privilege when the user is granted `SYSTEM`, `SYSTEM FLUSH DISTRIBUTED`, or `FLUSH DISTRIBUTED`. -##### RQ.SRS-006.RBAC.Privileges.System.Flush.Logs +#### RQ.SRS-006.RBAC.Privileges.System.Flush.Logs version: 1.0 [ClickHouse] SHALL successfully grant `SYSTEM FLUSH LOGS` privilege when the user is granted `SYSTEM`, `SYSTEM FLUSH LOGS`, or `FLUSH LOGS`. -#### Sources +### Sources -##### RQ.SRS-006.RBAC.Privileges.Sources +#### RQ.SRS-006.RBAC.Privileges.Sources version: 1.0 [ClickHouse] SHALL support granting or revoking `SOURCES` privilege from the user, either directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.File +#### RQ.SRS-006.RBAC.Privileges.Sources.File version: 1.0 [ClickHouse] SHALL support the use of `FILE` source by a user if and only if the user has `FILE` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.URL +#### RQ.SRS-006.RBAC.Privileges.Sources.URL version: 1.0 [ClickHouse] SHALL support the use of `URL` source by a user if and only if the user has `URL` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.Remote +#### RQ.SRS-006.RBAC.Privileges.Sources.Remote version: 1.0 [ClickHouse] SHALL support the use of `REMOTE` source by a user if and only if the user has `REMOTE` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.MySQL +#### RQ.SRS-006.RBAC.Privileges.Sources.MySQL version: 1.0 [ClickHouse] SHALL support the use of `MySQL` source by a user if and only if the user has `MySQL` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.ODBC +#### RQ.SRS-006.RBAC.Privileges.Sources.ODBC version: 1.0 [ClickHouse] SHALL support the use of `ODBC` source by a user if and only if the user has `ODBC` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.JDBC +#### RQ.SRS-006.RBAC.Privileges.Sources.JDBC version: 1.0 [ClickHouse] SHALL support the use of `JDBC` source by a user if and only if the user has `JDBC` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.HDFS +#### RQ.SRS-006.RBAC.Privileges.Sources.HDFS version: 1.0 [ClickHouse] SHALL support the use of `HDFS` source by a user if and only if the user has `HDFS` or `SOURCES` privileges granted to them directly or through a role. -##### RQ.SRS-006.RBAC.Privileges.Sources.S3 +#### RQ.SRS-006.RBAC.Privileges.Sources.S3 version: 1.0 [ClickHouse] SHALL support the use of `S3` source by a user if and only if the user has `S3` or `SOURCES` privileges granted to them directly or through a role. -#### RQ.SRS-006.RBAC.Privileges.GrantOption +### RQ.SRS-006.RBAC.Privileges.GrantOption version: 1.0 [ClickHouse] SHALL successfully execute `GRANT` or `REVOKE` privilege statements by a user if and only if the user has that privilege with `GRANT OPTION`, either directly or through a role. -#### RQ.SRS-006.RBAC.Privileges.All +### RQ.SRS-006.RBAC.Privileges.All version: 1.0 -[ClickHouse] SHALL support granting or revoking `ALL` privilege. +[ClickHouse] SHALL support granting or revoking `ALL` privilege +using `GRANT ALL ON *.* TO user`. -#### RQ.SRS-006.RBAC.Privileges.AdminOption +### RQ.SRS-006.RBAC.Privileges.RoleAll +version: 1.0 + +[ClickHouse] SHALL support granting a role named `ALL` using `GRANT ALL TO user`. +This shall only grant the user the privileges that have been granted to the role. + +### RQ.SRS-006.RBAC.Privileges.None +version: 1.0 + +[ClickHouse] SHALL support granting or revoking `NONE` privilege +using `GRANT NONE TO user` or `GRANT USAGE ON *.* TO user`. + +### RQ.SRS-006.RBAC.Privileges.AdminOption version: 1.0 [ClickHouse] SHALL support a user granting or revoking a role if and only if @@ -4451,7845 +14497,3 @@ the user has that role with `ADMIN OPTION` privilege. [MySQL]: https://dev.mysql.com/doc/refman/8.0/en/account-management-statements.html [PostgreSQL]: https://www.postgresql.org/docs/12/user-manag.html ''') - -RQ_SRS_006_RBAC = Requirement( - name='RQ.SRS-006.RBAC', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support role based access control.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Login = Requirement( - name='RQ.SRS-006.RBAC.Login', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only allow access to the server for a given\n' - 'user only when correct username and password are used during\n' - 'the connection to the server.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Login_DefaultUser = Requirement( - name='RQ.SRS-006.RBAC.Login.DefaultUser', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL use the **default user** when no username and password\n' - 'are specified during the connection to the server.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User = Requirement( - name='RQ.SRS-006.RBAC.User', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creation and manipulation of\n' - 'one or more **user** accounts to which roles, privileges,\n' - 'settings profile, quotas and row policies can be assigned.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Roles = Requirement( - name='RQ.SRS-006.RBAC.User.Roles', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more **roles**\n' - 'to a **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Privileges = Requirement( - name='RQ.SRS-006.RBAC.User.Privileges', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more privileges to a **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Variables = Requirement( - name='RQ.SRS-006.RBAC.User.Variables', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more variables to a **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Variables_Constraints = Requirement( - name='RQ.SRS-006.RBAC.User.Variables.Constraints', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning min, max and read-only constraints\n' - 'for the variables that can be set and read by the **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_SettingsProfile = Requirement( - name='RQ.SRS-006.RBAC.User.SettingsProfile', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more **settings profiles**\n' - 'to a **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Quotas = Requirement( - name='RQ.SRS-006.RBAC.User.Quotas', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more **quotas** to a **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_RowPolicies = Requirement( - name='RQ.SRS-006.RBAC.User.RowPolicies', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more **row policies** to a **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_AccountLock = Requirement( - name='RQ.SRS-006.RBAC.User.AccountLock', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support locking and unlocking of **user** accounts.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_AccountLock_DenyAccess = Requirement( - name='RQ.SRS-006.RBAC.User.AccountLock.DenyAccess', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL deny access to the user whose account is locked.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_DefaultRole = Requirement( - name='RQ.SRS-006.RBAC.User.DefaultRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning a default role to a **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_RoleSelection = Requirement( - name='RQ.SRS-006.RBAC.User.RoleSelection', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support selection of one or more **roles** from the available roles\n' - 'that are assigned to a **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_ShowCreate = Requirement( - name='RQ.SRS-006.RBAC.User.ShowCreate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the command of how **user** account was created.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_ShowPrivileges = Requirement( - name='RQ.SRS-006.RBAC.User.ShowPrivileges', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support listing the privileges of the **user**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role = Requirement( - name='RQ.SRS-006.RBAC.Role', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClikHouse] SHALL support creation and manipulation of **roles**\n' - 'to which privileges, settings profile, quotas and row policies can be\n' - 'assigned.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Privileges = Requirement( - name='RQ.SRS-006.RBAC.Role.Privileges', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more privileges to a **role**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Variables = Requirement( - name='RQ.SRS-006.RBAC.Role.Variables', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more variables to a **role**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_SettingsProfile = Requirement( - name='RQ.SRS-006.RBAC.Role.SettingsProfile', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more **settings profiles**\n' - 'to a **role**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Quotas = Requirement( - name='RQ.SRS-006.RBAC.Role.Quotas', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more **quotas** to a **role**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_RowPolicies = Requirement( - name='RQ.SRS-006.RBAC.Role.RowPolicies', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning one or more **row policies** to a **role**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_PartialRevokes = Requirement( - name='RQ.SRS-006.RBAC.PartialRevokes', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support partial revoking of privileges granted\n' - 'to a **user** or a **role**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creation and manipulation of **settings profiles**\n' - 'that can include value definition for one or more variables and can\n' - 'can be assigned to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Constraints = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Constraints', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning min, max and read-only constraints\n' - 'for the variables specified in the **settings profile**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_ShowCreate = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.ShowCreate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the command of how **setting profile** was created.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas = Requirement( - name='RQ.SRS-006.RBAC.Quotas', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creation and manipulation of **quotas**\n' - 'that can be used to limit resource usage by a **user** or a **role**\n' - 'over a period of time.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas_Keyed = Requirement( - name='RQ.SRS-006.RBAC.Quotas.Keyed', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creating **quotas** that are keyed\n' - 'so that a quota is tracked separately for each key value.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas_Queries = Requirement( - name='RQ.SRS-006.RBAC.Quotas.Queries', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting **queries** quota to limit the total number of requests.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas_Errors = Requirement( - name='RQ.SRS-006.RBAC.Quotas.Errors', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting **errors** quota to limit the number of queries that threw an exception.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas_ResultRows = Requirement( - name='RQ.SRS-006.RBAC.Quotas.ResultRows', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting **result rows** quota to limit the\n' - 'the total number of rows given as the result.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas_ReadRows = Requirement( - name='RQ.SRS-006.RBAC.Quotas.ReadRows', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting **read rows** quota to limit the total\n' - 'number of source rows read from tables for running the query on all remote servers.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas_ResultBytes = Requirement( - name='RQ.SRS-006.RBAC.Quotas.ResultBytes', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting **result bytes** quota to limit the total number\n' - 'of bytes that can be returned as the result.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas_ReadBytes = Requirement( - name='RQ.SRS-006.RBAC.Quotas.ReadBytes', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting **read bytes** quota to limit the total number\n' - 'of source bytes read from tables for running the query on all remote servers.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas_ExecutionTime = Requirement( - name='RQ.SRS-006.RBAC.Quotas.ExecutionTime', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting **execution time** quota to limit the maximum\n' - 'query execution time.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quotas_ShowCreate = Requirement( - name='RQ.SRS-006.RBAC.Quotas.ShowCreate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the command of how **quota** was created.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creation and manipulation of table **row policies**\n' - 'that can be used to limit access to the table contents for a **user** or a **role**\n' - 'using a specified **condition**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Condition = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Condition', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support row policy **conditions** that can be any SQL\n' - 'expression that returns a boolean.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_ShowCreate = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.ShowCreate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the command of how **row policy** was created.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Use_DefaultRole = Requirement( - name='RQ.SRS-006.RBAC.User.Use.DefaultRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL by default use default role or roles assigned\n' - 'to the user if specified.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Use_AllRolesWhenNoDefaultRole = Requirement( - name='RQ.SRS-006.RBAC.User.Use.AllRolesWhenNoDefaultRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL by default use all the roles assigned to the user\n' - 'if no default role or roles are specified for the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create = Requirement( - name='RQ.SRS-006.RBAC.User.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creating **user** accounts using `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_IfNotExists = Requirement( - name='RQ.SRS-006.RBAC.User.Create.IfNotExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE USER` statement\n' - 'to skip raising an exception if a user with the same **name** already exists.\n' - 'If the `IF NOT EXISTS` clause is not specified then an exception SHALL be\n' - 'raised if a user with the same **name** already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Replace = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Replace', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE USER` statement\n' - 'to replace existing user account if already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_NoPassword = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.NoPassword', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying no password when creating\n' - 'user account using `IDENTIFIED WITH NO_PASSWORD` clause .\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_NoPassword_Login = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.NoPassword.Login', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL use no password for the user when connecting to the server\n' - 'when an account was created with `IDENTIFIED WITH NO_PASSWORD` clause.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_PlainText = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.PlainText', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying plaintext password when creating\n' - 'user account using `IDENTIFIED WITH PLAINTEXT_PASSWORD BY` clause.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_PlainText_Login = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.PlainText.Login', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL use the plaintext password passed by the user when connecting to the server\n' - 'when an account was created with `IDENTIFIED WITH PLAINTEXT_PASSWORD` clause\n' - 'and compare the password with the one used in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_Sha256Password = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Password', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying the result of applying SHA256\n' - 'to some password when creating user account using `IDENTIFIED WITH SHA256_PASSWORD BY` or `IDENTIFIED BY`\n' - 'clause.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_Sha256Password_Login = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Password.Login', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL calculate `SHA256` of the password passed by the user when connecting to the server\n' - "when an account was created with `IDENTIFIED WITH SHA256_PASSWORD` or with 'IDENTIFIED BY' clause\n" - 'and compare the calculated hash to the one used in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_Sha256Hash = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying the result of applying SHA256\n' - 'to some already calculated hash when creating user account using `IDENTIFIED WITH SHA256_HASH`\n' - 'clause.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_Sha256Hash_Login = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.Sha256Hash.Login', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL calculate `SHA256` of the already calculated hash passed by\n' - 'the user when connecting to the server\n' - 'when an account was created with `IDENTIFIED WITH SHA256_HASH` clause\n' - 'and compare the calculated hash to the one used in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Password = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying the result of applying SHA1 two times\n' - 'to a password when creating user account using `IDENTIFIED WITH DOUBLE_SHA1_PASSWORD`\n' - 'clause.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Password_Login = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Password.Login', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL calculate `SHA1` two times over the password passed by\n' - 'the user when connecting to the server\n' - 'when an account was created with `IDENTIFIED WITH DOUBLE_SHA1_PASSWORD` clause\n' - 'and compare the calculated value to the one used in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Hash = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying the result of applying SHA1 two times\n' - 'to a hash when creating user account using `IDENTIFIED WITH DOUBLE_SHA1_HASH`\n' - 'clause.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Hash_Login = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Password.DoubleSha1Hash.Login', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL calculate `SHA1` two times over the hash passed by\n' - 'the user when connecting to the server\n' - 'when an account was created with `IDENTIFIED WITH DOUBLE_SHA1_HASH` clause\n' - 'and compare the calculated value to the one used in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Host_Name = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Host.Name', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more hostnames from\n' - 'which user can access the server using the `HOST NAME` clause\n' - 'in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Host_Regexp = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Host.Regexp', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more regular expressions\n' - 'to match hostnames from which user can access the server\n' - 'using the `HOST REGEXP` clause in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Host_IP = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Host.IP', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more IP address or subnet from\n' - 'which user can access the server using the `HOST IP` clause in the\n' - '`CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Host_Any = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Host.Any', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying `HOST ANY` clause in the `CREATE USER` statement\n' - 'to indicate that user can access the server from any host.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Host_None = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Host.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support fobidding access from any host using `HOST NONE` clause in the\n' - '`CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Host_Local = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Host.Local', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting user access to local only using `HOST LOCAL` clause in the\n' - '`CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Host_Like = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Host.Like', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying host using `LIKE` command syntax using the\n' - '`HOST LIKE` clause in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Host_Default = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Host.Default', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support user access to server from any host\n' - 'if no `HOST` clause is specified in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_DefaultRole = Requirement( - name='RQ.SRS-006.RBAC.User.Create.DefaultRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more default roles\n' - 'using `DEFAULT ROLE` clause in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_DefaultRole_None = Requirement( - name='RQ.SRS-006.RBAC.User.Create.DefaultRole.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying no default roles\n' - 'using `DEFAULT ROLE NONE` clause in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_DefaultRole_All = Requirement( - name='RQ.SRS-006.RBAC.User.Create.DefaultRole.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying all roles to be used as default\n' - 'using `DEFAULT ROLE ALL` clause in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Settings = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Settings', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying settings and profile\n' - 'using `SETTINGS` clause in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.User.Create.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying cluster on which the user\n' - 'will be created using `ON CLUSTER` clause in the `CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Create_Syntax = Requirement( - name='RQ.SRS-006.RBAC.User.Create.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for `CREATE USER` statement.\n' - '\n' - '```sql\n' - 'CREATE USER [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name]\n' - " [IDENTIFIED [WITH {NO_PASSWORD|PLAINTEXT_PASSWORD|SHA256_PASSWORD|SHA256_HASH|DOUBLE_SHA1_PASSWORD|DOUBLE_SHA1_HASH}] BY {'password'|'hash'}]\n" - " [HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]\n" - ' [DEFAULT ROLE role [,...]]\n' - " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter = Requirement( - name='RQ.SRS-006.RBAC.User.Alter', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering **user** accounts using `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_OrderOfEvaluation = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.OrderOfEvaluation', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support evaluating `ALTER USER` statement from left to right\n' - 'where things defined on the right override anything that was previously defined on\n' - 'the left.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_IfExists = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `IF EXISTS` clause in the `ALTER USER` statement\n' - 'to skip raising an exception (producing a warning instead) if a user with the specified **name** does not exist. If the `IF EXISTS` clause is not specified then an exception SHALL be raised if a user with the **name** does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Cluster = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying the cluster the user is on\n' - 'when altering user account using `ON CLUSTER` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Rename = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Rename', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying a new name for the user when\n' - 'altering user account using `RENAME` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Password_PlainText = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Password.PlainText', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying plaintext password when altering\n' - 'user account using `IDENTIFIED WITH PLAINTEXT_PASSWORD BY` or\n' - 'using shorthand `IDENTIFIED BY` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Password_Sha256Password = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Password.Sha256Password', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying the result of applying SHA256\n' - 'to some password as identification when altering user account using\n' - '`IDENTIFIED WITH SHA256_PASSWORD` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Password_DoubleSha1Password = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Password.DoubleSha1Password', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying the result of applying Double SHA1\n' - 'to some password as identification when altering user account using\n' - '`IDENTIFIED WITH DOUBLE_SHA1_PASSWORD` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Host_AddDrop = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Host.AddDrop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering user by adding and dropping access to hosts with the `ADD HOST` or the `DROP HOST`in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Host_Local = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Host.Local', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting user access to local only using `HOST LOCAL` clause in the\n' - '`ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Host_Name = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Host.Name', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more hostnames from\n' - 'which user can access the server using the `HOST NAME` clause\n' - 'in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Host_Regexp = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Host.Regexp', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more regular expressions\n' - 'to match hostnames from which user can access the server\n' - 'using the `HOST REGEXP` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Host_IP = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Host.IP', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more IP address or subnet from\n' - 'which user can access the server using the `HOST IP` clause in the\n' - '`ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Host_Like = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Host.Like', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying sone or more similar hosts using `LIKE` command syntax using the `HOST LIKE` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Host_Any = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Host.Any', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying `HOST ANY` clause in the `ALTER USER` statement\n' - 'to indicate that user can access the server from any host.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Host_None = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Host.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support fobidding access from any host using `HOST NONE` clause in the\n' - '`ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_DefaultRole = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.DefaultRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more default roles\n' - 'using `DEFAULT ROLE` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_DefaultRole_All = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.DefaultRole.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying all roles to be used as default\n' - 'using `DEFAULT ROLE ALL` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_DefaultRole_AllExcept = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.DefaultRole.AllExcept', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more roles which will not be used as default\n' - 'using `DEFAULT ROLE ALL EXCEPT` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Settings = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Settings', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying one or more variables\n' - 'using `SETTINGS` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Settings_Min = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Settings.Min', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying a minimum value for the variable specifed using `SETTINGS` with `MIN` clause in the `ALTER USER` statement.\n' - '\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Settings_Max = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Settings.Max', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying a maximum value for the variable specifed using `SETTINGS` with `MAX` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Settings_Profile = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Settings.Profile', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying the name of a profile for the variable specifed using `SETTINGS` with `PROFILE` clause in the `ALTER USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Alter_Syntax = Requirement( - name='RQ.SRS-006.RBAC.User.Alter.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `ALTER USER` statement.\n' - '\n' - '```sql\n' - 'ALTER USER [IF EXISTS] name [ON CLUSTER cluster_name]\n' - ' [RENAME TO new_name]\n' - " [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}]\n" - " [[ADD|DROP] HOST {LOCAL | NAME 'name' | REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]\n" - ' [DEFAULT ROLE role [,...] | ALL | ALL EXCEPT role [,...] ]\n' - " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetDefaultRole = Requirement( - name='RQ.SRS-006.RBAC.SetDefaultRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting or changing granted roles to default for one or more\n' - 'users using `SET DEFAULT ROLE` statement which\n' - 'SHALL permanently change the default roles for the user or users if successful.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetDefaultRole_CurrentUser = Requirement( - name='RQ.SRS-006.RBAC.SetDefaultRole.CurrentUser', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting or changing granted roles to default for\n' - 'the current user using `CURRENT_USER` clause in the `SET DEFAULT ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetDefaultRole_All = Requirement( - name='RQ.SRS-006.RBAC.SetDefaultRole.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting or changing all granted roles to default\n' - 'for one or more users using `ALL` clause in the `SET DEFAULT ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetDefaultRole_AllExcept = Requirement( - name='RQ.SRS-006.RBAC.SetDefaultRole.AllExcept', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting or changing all granted roles except those specified\n' - 'to default for one or more users using `ALL EXCEPT` clause in the `SET DEFAULT ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetDefaultRole_None = Requirement( - name='RQ.SRS-006.RBAC.SetDefaultRole.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support removing all granted roles from default\n' - 'for one or more users using `NONE` clause in the `SET DEFAULT ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetDefaultRole_Syntax = Requirement( - name='RQ.SRS-006.RBAC.SetDefaultRole.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `SET DEFAULT ROLE` statement.\n' - '\n' - '```sql\n' - 'SET DEFAULT ROLE\n' - ' {NONE | role [,...] | ALL | ALL EXCEPT role [,...]}\n' - ' TO {user|CURRENT_USER} [,...]\n' - '\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetRole = Requirement( - name='RQ.SRS-006.RBAC.SetRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support activating role or roles for the current user\n' - 'using `SET ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetRole_Default = Requirement( - name='RQ.SRS-006.RBAC.SetRole.Default', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support activating default roles for the current user\n' - 'using `DEFAULT` clause in the `SET ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetRole_None = Requirement( - name='RQ.SRS-006.RBAC.SetRole.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support activating no roles for the current user\n' - 'using `NONE` clause in the `SET ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetRole_All = Requirement( - name='RQ.SRS-006.RBAC.SetRole.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support activating all roles for the current user\n' - 'using `ALL` clause in the `SET ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetRole_AllExcept = Requirement( - name='RQ.SRS-006.RBAC.SetRole.AllExcept', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support activating all roles except those specified\n' - 'for the current user using `ALL EXCEPT` clause in the `SET ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SetRole_Syntax = Requirement( - name='RQ.SRS-006.RBAC.SetRole.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '```sql\n' - 'SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]}\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_ShowCreateUser = Requirement( - name='RQ.SRS-006.RBAC.User.ShowCreateUser', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the `CREATE USER` statement used to create the current user object\n' - 'using the `SHOW CREATE USER` statement with `CURRENT_USER` or no argument.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_ShowCreateUser_For = Requirement( - name='RQ.SRS-006.RBAC.User.ShowCreateUser.For', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the `CREATE USER` statement used to create the specified user object\n' - 'using the `FOR` clause in the `SHOW CREATE USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_ShowCreateUser_Syntax = Requirement( - name='RQ.SRS-006.RBAC.User.ShowCreateUser.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the following syntax for `SHOW CREATE USER` statement.\n' - '\n' - '```sql\n' - 'SHOW CREATE USER [name | CURRENT_USER]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Drop = Requirement( - name='RQ.SRS-006.RBAC.User.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support removing a user account using `DROP USER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Drop_IfExists = Requirement( - name='RQ.SRS-006.RBAC.User.Drop.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support using `IF EXISTS` clause in the `DROP USER` statement\n' - 'to skip raising an exception if the user account does not exist.\n' - 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' - 'raised if a user does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Drop_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.User.Drop.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support using `ON CLUSTER` clause in the `DROP USER` statement\n' - 'to specify the name of the cluster the user should be dropped from.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_User_Drop_Syntax = Requirement( - name='RQ.SRS-006.RBAC.User.Drop.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for `DROP USER` statement\n' - '\n' - '```sql\n' - 'DROP USER [IF EXISTS] name [,...] [ON CLUSTER cluster_name]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Create = Requirement( - name='RQ.SRS-006.RBAC.Role.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creating a **role** using `CREATE ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Create_IfNotExists = Requirement( - name='RQ.SRS-006.RBAC.Role.Create.IfNotExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE ROLE` statement\n' - 'to raising an exception if a role with the same **name** already exists.\n' - 'If the `IF NOT EXISTS` clause is not specified then an exception SHALL be\n' - 'raised if a role with the same **name** already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Create_Replace = Requirement( - name='RQ.SRS-006.RBAC.Role.Create.Replace', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE ROLE` statement\n' - 'to replace existing role if it already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Create_Settings = Requirement( - name='RQ.SRS-006.RBAC.Role.Create.Settings', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying settings and profile using `SETTINGS`\n' - 'clause in the `CREATE ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Create_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Role.Create.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `CREATE ROLE` statement\n' - '\n' - '``` sql\n' - 'CREATE ROLE [IF NOT EXISTS | OR REPLACE] name\n' - " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Alter = Requirement( - name='RQ.SRS-006.RBAC.Role.Alter', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering one **role** using `ALTER ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Alter_IfExists = Requirement( - name='RQ.SRS-006.RBAC.Role.Alter.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering one **role** using `ALTER ROLE IF EXISTS` statement, where no exception\n' - 'will be thrown if the role does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Alter_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Role.Alter.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering one **role** using `ALTER ROLE role ON CLUSTER` statement to specify the\n' - 'cluster location of the specified role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Alter_Rename = Requirement( - name='RQ.SRS-006.RBAC.Role.Alter.Rename', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering one **role** using `ALTER ROLE role RENAME TO` statement which renames the\n' - 'role to a specified new name. If the new name already exists, that an exception SHALL be raised unless the\n' - '`IF EXISTS` clause is specified, by which no exception will be raised and nothing will change.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Alter_Settings = Requirement( - name='RQ.SRS-006.RBAC.Role.Alter.Settings', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the settings of one **role** using `ALTER ROLE role SETTINGS ...` statement.\n' - 'Altering variable values, creating max and min values, specifying readonly or writable, and specifying the\n' - 'profiles for which this alter change shall be applied to, are all supported, using the following syntax.\n' - '\n' - '```sql\n' - "[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" - '```\n' - '\n' - 'One or more variables and profiles may be specified as shown above.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Alter_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Role.Alter.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '```sql\n' - 'ALTER ROLE [IF EXISTS] name [ON CLUSTER cluster_name]\n' - ' [RENAME TO new_name]\n' - " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]\n" - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Drop = Requirement( - name='RQ.SRS-006.RBAC.Role.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support removing one or more roles using `DROP ROLE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Drop_IfExists = Requirement( - name='RQ.SRS-006.RBAC.Role.Drop.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support using `IF EXISTS` clause in the `DROP ROLE` statement\n' - 'to skip raising an exception if the role does not exist.\n' - 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' - 'raised if a role does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Drop_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Role.Drop.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support using `ON CLUSTER` clause in the `DROP ROLE` statement to specify the cluster from which to drop the specified role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_Drop_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Role.Drop.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `DROP ROLE` statement\n' - '\n' - '``` sql\n' - 'DROP ROLE [IF EXISTS] name [,...] [ON CLUSTER cluster_name]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_ShowCreate = Requirement( - name='RQ.SRS-006.RBAC.Role.ShowCreate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support viewing the settings for a role upon creation with the `SHOW CREATE ROLE`\n' - 'statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Role_ShowCreate_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Role.ShowCreate.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `SHOW CREATE ROLE` command.\n' - '\n' - '```sql\n' - 'SHOW CREATE ROLE name\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_To = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.To', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting privileges to one or more users or roles using `TO` clause\n' - 'in the `GRANT PRIVILEGE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_ToCurrentUser = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.ToCurrentUser', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting privileges to current user using `TO CURRENT_USER` clause\n' - 'in the `GRANT PRIVILEGE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Select = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Select', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **select** privilege to one or more users or roles\n' - 'for a database or a table using the `GRANT SELECT` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Insert = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Insert', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **insert** privilege to one or more users or roles\n' - 'for a database or a table using the `GRANT INSERT` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Alter = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Alter', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **alter** privilege to one or more users or roles\n' - 'for a database or a table using the `GRANT ALTER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Create = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **create** privilege to one or more users or roles\n' - 'using the `GRANT CREATE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Drop = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **drop** privilege to one or more users or roles\n' - 'using the `GRANT DROP` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Truncate = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Truncate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **truncate** privilege to one or more users or roles\n' - 'for a database or a table using `GRANT TRUNCATE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Optimize = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Optimize', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **optimize** privilege to one or more users or roles\n' - 'for a database or a table using `GRANT OPTIMIZE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Show = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Show', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **show** privilege to one or more users or roles\n' - 'for a database or a table using `GRANT SHOW` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_KillQuery = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.KillQuery', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **kill query** privilege to one or more users or roles\n' - 'for a database or a table using `GRANT KILL QUERY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_AccessManagement = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.AccessManagement', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **access management** privileges to one or more users or roles\n' - 'for a database or a table using `GRANT ACCESS MANAGEMENT` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_System = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.System', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **system** privileges to one or more users or roles\n' - 'for a database or a table using `GRANT SYSTEM` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Introspection = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Introspection', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **introspection** privileges to one or more users or roles\n' - 'for a database or a table using `GRANT INTROSPECTION` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Sources = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Sources', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **sources** privileges to one or more users or roles\n' - 'for a database or a table using `GRANT SOURCES` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_DictGet = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.DictGet', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **dictGet** privilege to one or more users or roles\n' - 'for a database or a table using `GRANT dictGet` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_None = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting no privileges to one or more users or roles\n' - 'for a database or a table using `GRANT NONE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_All = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **all** privileges to one or more users or roles\n' - 'for a database or a table using the `GRANT ALL` or `GRANT ALL PRIVILEGES` statements.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_GrantOption = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.GrantOption', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the **grant option** privilege to one or more users or roles\n' - 'for a database or a table using the `WITH GRANT OPTION` clause in the `GRANT` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_On = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.On', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the `ON` clause in the `GRANT` privilege statement\n' - 'which SHALL allow to specify one or more tables to which the privilege SHALL\n' - 'be granted using the following patterns\n' - '\n' - '* `*.*` any table in any database\n' - '* `database.*` any table in the specified database\n' - '* `database.table` specific table in the specified database\n' - '* `*` any table in the current database\n' - '* `table` specific table in the current database\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_PrivilegeColumns = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.PrivilegeColumns', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting the privilege **some_privilege** to one or more users or roles\n' - 'for a database or a table using the `GRANT some_privilege(column)` statement for one column.\n' - 'Multiple columns will be supported with `GRANT some_privilege(column1, column2...)` statement.\n' - 'The privileges will be granted for only the specified columns.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying cluster on which to grant privileges using the `ON CLUSTER`\n' - 'clause in the `GRANT PRIVILEGE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Privilege_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Grant.Privilege.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `GRANT` statement that\n' - 'grants explicit privileges to a user or a role.\n' - '\n' - '```sql\n' - 'GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...]\n' - ' ON {db.table|db.*|*.*|table|*}\n' - ' TO {user | role | CURRENT_USER} [,...]\n' - ' [WITH GRANT OPTION]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking privileges to one or more users or roles\n' - 'for a database or a table on some specific cluster using the `REVOKE ON CLUSTER cluster_name` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Any = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Any', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking ANY privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE some_privilege` statement.\n' - '**some_privilege** refers to any Clickhouse defined privilege, whose hierarchy includes\n' - 'SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE, SHOW, KILL QUERY, ACCESS MANAGEMENT,\n' - 'SYSTEM, INTROSPECTION, SOURCES, dictGet and all of their sub-privileges.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Select = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Select', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **select** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE SELECT` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Insert = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Insert', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **insert** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE INSERT` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Alter = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Alter', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **alter** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE ALTER` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Create = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **create** privilege to one or more users or roles\n' - 'using the `REVOKE CREATE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Drop = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **drop** privilege to one or more users or roles\n' - 'using the `REVOKE DROP` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Truncate = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Truncate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **truncate** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE TRUNCATE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Optimize = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Optimize', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **optimize** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE OPTIMIZE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Show = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Show', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **show** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE SHOW` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_KillQuery = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.KillQuery', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **kill query** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE KILL QUERY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_AccessManagement = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.AccessManagement', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **access management** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE ACCESS MANAGEMENT` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_System = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.System', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **system** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE SYSTEM` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Introspection = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Introspection', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **introspection** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE INTROSPECTION` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Sources = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Sources', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **sources** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE SOURCES` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_DictGet = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.DictGet', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the **dictGet** privilege to one or more users or roles\n' - 'for a database or a table using the `REVOKE dictGet` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_PrivelegeColumns = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.PrivelegeColumns', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking the privilege **some_privilege** to one or more users or roles\n' - 'for a database or a table using the `REVOKE some_privilege(column)` statement for one column.\n' - 'Multiple columns will be supported with `REVOKE some_privilege(column1, column2...)` statement.\n' - 'The privileges will be revoked for only the specified columns.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Multiple = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Multiple', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking MULTIPLE **privileges** to one or more users or roles\n' - 'for a database or a table using the `REVOKE privilege1, privilege2...` statement.\n' - '**privileges** refers to any set of Clickhouse defined privilege, whose hierarchy includes\n' - 'SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE, SHOW, KILL QUERY, ACCESS MANAGEMENT,\n' - 'SYSTEM, INTROSPECTION, SOURCES, dictGet and all of their sub-privileges.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_All = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **all** privileges to one or more users or roles\n' - 'for a database or a table using the `REVOKE ALL` or `REVOKE ALL PRIVILEGES` statements.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_None = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **no** privileges to one or more users or roles\n' - 'for a database or a table using the `REVOKE NONE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_On = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.On', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the `ON` clause in the `REVOKE` privilege statement\n' - 'which SHALL allow to specify one or more tables to which the privilege SHALL\n' - 'be revoked using the following patterns\n' - '\n' - '* `db.table` specific table in the specified database\n' - '* `db.*` any table in the specified database\n' - '* `*.*` any table in any database\n' - '* `table` specific table in the current database\n' - '* `*` any table in the current database\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_From = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.From', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the `FROM` clause in the `REVOKE` privilege statement\n' - 'which SHALL allow to specify one or more users to which the privilege SHALL\n' - 'be revoked using the following patterns\n' - '\n' - '* `{user | CURRENT_USER} [,...]` some combination of users by name, which may include the current user\n' - '* `ALL` all users\n' - '* `ALL EXCEPT {user | CURRENT_USER} [,...]` the logical reverse of the first pattern\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Privilege_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Privilege.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `REVOKE` statement that\n' - 'revokes explicit privileges of a user or a role.\n' - '\n' - '```sql\n' - 'REVOKE [ON CLUSTER cluster_name] privilege\n' - ' [(column_name [,...])] [,...]\n' - ' ON {db.table|db.*|*.*|table|*}\n' - ' FROM {user | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user | CURRENT_USER} [,...]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_PartialRevoke_Syntax = Requirement( - name='RQ.SRS-006.RBAC.PartialRevoke.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support partial revokes by using `partial_revokes` variable\n' - 'that can be set or unset using the following syntax.\n' - '\n' - 'To disable partial revokes the `partial_revokes` variable SHALL be set to `0`\n' - '\n' - '```sql\n' - 'SET partial_revokes = 0\n' - '```\n' - '\n' - 'To enable partial revokes the `partial revokes` variable SHALL be set to `1`\n' - '\n' - '```sql\n' - 'SET partial_revokes = 1\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Role = Requirement( - name='RQ.SRS-006.RBAC.Grant.Role', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting one or more roles to\n' - 'one or more users or roles using the `GRANT` role statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Role_CurrentUser = Requirement( - name='RQ.SRS-006.RBAC.Grant.Role.CurrentUser', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting one or more roles to current user using\n' - '`TO CURRENT_USER` clause in the `GRANT` role statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Role_AdminOption = Requirement( - name='RQ.SRS-006.RBAC.Grant.Role.AdminOption', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting `admin option` privilege\n' - 'to one or more users or roles using the `WITH ADMIN OPTION` clause\n' - 'in the `GRANT` role statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Role_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.Grant.Role.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying cluster on which the user is to be granted one or more roles\n' - 'using `ON CLUSTER` clause in the `GRANT` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Grant_Role_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Grant.Role.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for `GRANT` role statement\n' - '\n' - '``` sql\n' - 'GRANT\n' - ' ON CLUSTER cluster_name\n' - ' role [, role ...]\n' - ' TO {user | role | CURRENT_USER} [,...]\n' - ' [WITH ADMIN OPTION]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Role = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Role', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking one or more roles from\n' - 'one or more users or roles using the `REVOKE` role statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Role_Keywords = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Role.Keywords', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking one or more roles from\n' - 'special groupings of one or more users or roles with the `ALL`, `ALL EXCEPT`,\n' - 'and `CURRENT_USER` keywords.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Role_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Role.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking one or more roles from\n' - 'one or more users or roles from one or more clusters\n' - 'using the `REVOKE ON CLUSTER` role statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_AdminOption = Requirement( - name='RQ.SRS-006.RBAC.Revoke.AdminOption', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking `admin option` privilege\n' - 'in one or more users or roles using the `ADMIN OPTION FOR` clause\n' - 'in the `REVOKE` role statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Revoke_Role_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Revoke.Role.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `REVOKE` role statement\n' - '\n' - '```sql\n' - 'REVOKE [ON CLUSTER cluster_name] [ADMIN OPTION FOR]\n' - ' role [,...]\n' - ' FROM {user | role | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Show_Grants = Requirement( - name='RQ.SRS-006.RBAC.Show.Grants', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support listing all the privileges granted to current user and role\n' - 'using the `SHOW GRANTS` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Show_Grants_For = Requirement( - name='RQ.SRS-006.RBAC.Show.Grants.For', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support listing all the privileges granted to a user or a role\n' - 'using the `FOR` clause in the `SHOW GRANTS` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Show_Grants_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Show.Grants.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[Clickhouse] SHALL use the following syntax for the `SHOW GRANTS` statement\n' - '\n' - '``` sql\n' - 'SHOW GRANTS [FOR user_or_role]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creating settings profile using the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_IfNotExists = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.IfNotExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE SETTINGS PROFILE` statement\n' - 'to skip raising an exception if a settings profile with the same **name** already exists.\n' - 'If `IF NOT EXISTS` clause is not specified then an exception SHALL be raised if\n' - 'a settings profile with the same **name** already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Replace = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Replace', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE SETTINGS PROFILE` statement\n' - 'to replace existing settings profile if it already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Variables = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Variables', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning values and constraints to one or more\n' - 'variables in the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Value = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Value', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning variable value in the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Variables.Constraints', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support setting `MIN`, `MAX`, `READONLY`, and `WRITABLE`\n' - 'constraints for the variables in the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning settings profile to one or more users\n' - 'or roles in the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_None = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning settings profile to no users or roles using\n' - '`TO NONE` clause in the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_All = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning settings profile to all current users and roles\n' - 'using `TO ALL` clause in the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_AllExcept = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Assignment.AllExcept', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support excluding assignment to one or more users or roles using\n' - 'the `ALL EXCEPT` clause in the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Inherit = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Inherit', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support inheriting profile settings from indicated profile using\n' - 'the `INHERIT` clause in the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying what cluster to create settings profile on\n' - 'using `ON CLUSTER` clause in the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Create_Syntax = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Create.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `CREATE SETTINGS PROFILE` statement.\n' - '\n' - '``` sql\n' - 'CREATE SETTINGS PROFILE [IF NOT EXISTS | OR REPLACE] name\n' - ' [ON CLUSTER cluster_name]\n' - " [SET varname [= value] [MIN min] [MAX max] [READONLY|WRITABLE] | [INHERIT 'profile_name'] [,...]]\n" - ' [TO {user_or_role [,...] | NONE | ALL | ALL EXCEPT user_or_role [,...]}]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering settings profile using the `ALTER STETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_IfExists = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `IF EXISTS` clause in the `ALTER SETTINGS PROFILE` statement\n' - 'to not raise exception if a settings profile does not exist.\n' - 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' - 'raised if a settings profile does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Rename = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Rename', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support renaming settings profile using the `RANAME TO` clause\n' - 'in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering values and constraints of one or more\n' - 'variables in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Value', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering value of the variable in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Variables.Constraints', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering `MIN`, `MAX`, `READONLY`, and `WRITABLE`\n' - 'constraints for the variables in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support reassigning settings profile to one or more users\n' - 'or roles using the `TO` clause in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_None = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support reassigning settings profile to no users or roles using the\n' - '`TO NONE` clause in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_All = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support reassigning settings profile to all current users and roles\n' - 'using the `TO ALL` clause in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_AllExcept = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.AllExcept', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support excluding assignment to one or more users or roles using\n' - 'the `TO ALL EXCEPT` clause in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_Inherit = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.Inherit', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the settings profile by inheriting settings from\n' - 'specified profile using `INHERIT` clause in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Assignment.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the settings profile on a specified cluster using\n' - '`ON CLUSTER` clause in the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Alter_Syntax = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Alter.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `ALTER SETTINGS PROFILE` statement.\n' - '\n' - '``` sql\n' - 'ALTER SETTINGS PROFILE [IF EXISTS] name\n' - ' [ON CLUSTER cluster_name]\n' - ' [RENAME TO new_name]\n' - " [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | INHERIT 'profile_name'] [,...]\n" - ' [TO {user_or_role [,...] | NONE | ALL | ALL EXCEPT user_or_role [,...]]}\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Drop = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support removing one or more settings profiles using the `DROP SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Drop_IfExists = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Drop.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support using `IF EXISTS` clause in the `DROP SETTINGS PROFILE` statement\n' - 'to skip raising an exception if the settings profile does not exist.\n' - 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' - 'raised if a settings profile does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Drop_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Drop.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support dropping one or more settings profiles on specified cluster using\n' - '`ON CLUSTER` clause in the `DROP SETTINGS PROFILE` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_Drop_Syntax = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.Drop.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `DROP SETTINGS PROFILE` statement\n' - '\n' - '``` sql\n' - 'DROP SETTINGS PROFILE [IF EXISTS] name [,name,...]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_SettingsProfile_ShowCreateSettingsProfile = Requirement( - name='RQ.SRS-006.RBAC.SettingsProfile.ShowCreateSettingsProfile', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the `CREATE SETTINGS PROFILE` statement used to create the settings profile\n' - 'using the `SHOW CREATE SETTINGS PROFILE` statement with the following syntax\n' - '\n' - '``` sql\n' - 'SHOW CREATE SETTINGS PROFILE name\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creating quotas using the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_IfNotExists = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.IfNotExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE QUOTA` statement\n' - 'to skip raising an exception if a quota with the same **name** already exists.\n' - 'If `IF NOT EXISTS` clause is not specified then an exception SHALL be raised if\n' - 'a quota with the same **name** already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Replace = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Replace', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE QUOTA` statement\n' - 'to replace existing quota if it already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creating quotas on a specific cluster with the\n' - '`ON CLUSTER` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Interval = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Interval', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support defining the quota interval that specifies\n' - 'a period of time over for which the quota SHALL apply using the\n' - '`FOR INTERVAL` clause in the `CREATE QUOTA` statement.\n' - '\n' - 'This statement SHALL also support a number and a time period which will be one\n' - 'of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be:\n' - '\n' - '`FOR INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some real number\n' - 'to define the interval.\n' - '\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Interval_Randomized = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Interval.Randomized', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support defining the quota randomized interval that specifies\n' - 'a period of time over for which the quota SHALL apply using the\n' - '`FOR RANDOMIZED INTERVAL` clause in the `CREATE QUOTA` statement.\n' - '\n' - 'This statement SHALL also support a number and a time period which will be one\n' - 'of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be:\n' - '\n' - '`FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some\n' - 'real number to define the interval.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Queries = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Queries', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting number of requests over a period of time\n' - 'using the `QUERIES` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Errors = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Errors', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting number of queries that threw an exception\n' - 'using the `ERRORS` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_ResultRows = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.ResultRows', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting the total number of rows given as the result\n' - 'using the `RESULT ROWS` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_ReadRows = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.ReadRows', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting the total number of source rows read from tables\n' - 'for running the query on all remote servers\n' - 'using the `READ ROWS` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_ResultBytes = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.ResultBytes', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting the total number of bytes that can be returned as the result\n' - 'using the `RESULT BYTES` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_ReadBytes = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.ReadBytes', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting the total number of source bytes read from tables\n' - 'for running the query on all remote servers\n' - 'using the `READ BYTES` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_ExecutionTime = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.ExecutionTime', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting the maximum query execution time\n' - 'using the `EXECUTION TIME` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_NoLimits = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.NoLimits', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting the maximum query execution time\n' - 'using the `NO LIMITS` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_TrackingOnly = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.TrackingOnly', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting the maximum query execution time\n' - 'using the `TRACKING ONLY` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_KeyedBy = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.KeyedBy', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support to track quota for some key\n' - 'following the `KEYED BY` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_KeyedByOptions = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.KeyedByOptions', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support to track quota separately for some parameter\n' - "using the `KEYED BY 'parameter'` clause in the `CREATE QUOTA` statement.\n" - '\n' - "'parameter' can be one of:\n" - "`{'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}`\n" - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Assignment = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Assignment', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning quota to one or more users\n' - 'or roles using the `TO` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Assignment_None = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Assignment.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning quota to no users or roles using\n' - '`TO NONE` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Assignment_All = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Assignment.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning quota to all current users and roles\n' - 'using `TO ALL` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Assignment_Except = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Assignment.Except', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support excluding assignment of quota to one or more users or roles using\n' - 'the `EXCEPT` clause in the `CREATE QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Create_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Quota.Create.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `CREATE QUOTA` statement\n' - '\n' - '```sql\n' - 'CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name]\n' - " [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]\n" - ' [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}\n' - ' {MAX { {QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number } [,...] |\n' - ' NO LIMITS | TRACKING ONLY} [,...]]\n' - ' [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering quotas using the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_IfExists = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `IF EXISTS` clause in the `ALTER QUOTA` statement\n' - 'to skip raising an exception if a quota does not exist.\n' - 'If the `IF EXISTS` clause is not specified then an exception SHALL be raised if\n' - 'a quota does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Rename = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Rename', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `RENAME TO` clause in the `ALTER QUOTA` statement\n' - 'to rename the quota to the specified name.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering quotas on a specific cluster with the\n' - '`ON CLUSTER` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Interval = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Interval', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support redefining the quota interval that specifies\n' - 'a period of time over for which the quota SHALL apply using the\n' - '`FOR INTERVAL` clause in the `ALTER QUOTA` statement.\n' - '\n' - 'This statement SHALL also support a number and a time period which will be one\n' - 'of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be:\n' - '\n' - '`FOR INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some real number\n' - 'to define the interval.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Interval_Randomized = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Interval.Randomized', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support redefining the quota randomized interval that specifies\n' - 'a period of time over for which the quota SHALL apply using the\n' - '`FOR RANDOMIZED INTERVAL` clause in the `ALTER QUOTA` statement.\n' - '\n' - 'This statement SHALL also support a number and a time period which will be one\n' - 'of `{SECOND | MINUTE | HOUR | DAY | MONTH}`. Thus, the complete syntax SHALL be:\n' - '\n' - '`FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}` where number is some\n' - 'real number to define the interval.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Queries = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Queries', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the limit of number of requests over a period of time\n' - 'using the `QUERIES` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Errors = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Errors', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the limit of number of queries that threw an exception\n' - 'using the `ERRORS` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_ResultRows = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.ResultRows', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the limit of the total number of rows given as the result\n' - 'using the `RESULT ROWS` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_ReadRows = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.ReadRows', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the limit of the total number of source rows read from tables\n' - 'for running the query on all remote servers\n' - 'using the `READ ROWS` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_ALter_ResultBytes = Requirement( - name='RQ.SRS-006.RBAC.Quota.ALter.ResultBytes', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the limit of the total number of bytes that can be returned as the result\n' - 'using the `RESULT BYTES` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_ReadBytes = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.ReadBytes', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the limit of the total number of source bytes read from tables\n' - 'for running the query on all remote servers\n' - 'using the `READ BYTES` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_ExecutionTime = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.ExecutionTime', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering the limit of the maximum query execution time\n' - 'using the `EXECUTION TIME` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_NoLimits = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.NoLimits', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting the maximum query execution time\n' - 'using the `NO LIMITS` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_TrackingOnly = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.TrackingOnly', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support limiting the maximum query execution time\n' - 'using the `TRACKING ONLY` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_KeyedBy = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.KeyedBy', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering quota to track quota separately for some key\n' - 'following the `KEYED BY` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_KeyedByOptions = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.KeyedByOptions', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering quota to track quota separately for some parameter\n' - "using the `KEYED BY 'parameter'` clause in the `ALTER QUOTA` statement.\n" - '\n' - "'parameter' can be one of:\n" - "`{'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}`\n" - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Assignment = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Assignment', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support reassigning quota to one or more users\n' - 'or roles using the `TO` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Assignment_None = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Assignment.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support reassigning quota to no users or roles using\n' - '`TO NONE` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Assignment_All = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Assignment.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support reassigning quota to all current users and roles\n' - 'using `TO ALL` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Assignment_Except = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Assignment.Except', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support excluding assignment of quota to one or more users or roles using\n' - 'the `EXCEPT` clause in the `ALTER QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Alter_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Quota.Alter.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `ALTER QUOTA` statement\n' - '\n' - '``` sql\n' - 'ALTER QUOTA [IF EXIST] name\n' - ' {{{QUERIES | ERRORS | RESULT ROWS | READ ROWS | RESULT BYTES | READ BYTES | EXECUTION TIME} number} [, ...] FOR INTERVAL number time_unit} [, ...]\n' - ' [KEYED BY USERNAME | KEYED BY IP | NOT KEYED] [ALLOW CUSTOM KEY | DISALLOW CUSTOM KEY]\n' - ' [TO {user_or_role [,...] | NONE | ALL} [EXCEPT user_or_role [,...]]]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Drop = Requirement( - name='RQ.SRS-006.RBAC.Quota.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support removing one or more quotas using the `DROP QUOTA` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Drop_IfExists = Requirement( - name='RQ.SRS-006.RBAC.Quota.Drop.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support using `IF EXISTS` clause in the `DROP QUOTA` statement\n' - 'to skip raising an exception when the quota does not exist.\n' - 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' - 'raised if the quota does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Drop_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Quota.Drop.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support using `ON CLUSTER` clause in the `DROP QUOTA` statement\n' - 'to indicate the cluster the quota to be dropped is located on.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_Drop_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Quota.Drop.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `DROP QUOTA` statement\n' - '\n' - '``` sql\n' - 'DROP QUOTA [IF EXISTS] name [,name...]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_ShowQuotas = Requirement( - name='RQ.SRS-006.RBAC.Quota.ShowQuotas', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing all of the current quotas\n' - 'using the `SHOW QUOTAS` statement with the following syntax\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_ShowQuotas_IntoOutfile = Requirement( - name='RQ.SRS-006.RBAC.Quota.ShowQuotas.IntoOutfile', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the `INTO OUTFILE` clause in the `SHOW QUOTAS` statement to define an outfile by some given string literal.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_ShowQuotas_Format = Requirement( - name='RQ.SRS-006.RBAC.Quota.ShowQuotas.Format', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the `FORMAT` clause in the `SHOW QUOTAS` statement to define a format for the output quota list.\n' - '\n' - 'The types of valid formats are many, listed in output column:\n' - 'https://clickhouse.tech/docs/en/interfaces/formats/\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_ShowQuotas_Settings = Requirement( - name='RQ.SRS-006.RBAC.Quota.ShowQuotas.Settings', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the `SETTINGS` clause in the `SHOW QUOTAS` statement to define settings in the showing of all quotas.\n' - '\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_ShowQuotas_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Quota.ShowQuotas.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support using the `SHOW QUOTAS` statement\n' - 'with the following syntax\n' - '``` sql\n' - 'SHOW QUOTAS\n' - '```\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Name = Requirement( - name='RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Name', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the `CREATE QUOTA` statement used to create the quota with some given name\n' - 'using the `SHOW CREATE QUOTA` statement with the following syntax\n' - '\n' - '``` sql\n' - 'SHOW CREATE QUOTA name\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Current = Requirement( - name='RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Current', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the `CREATE QUOTA` statement used to create the CURRENT quota\n' - 'using the `SHOW CREATE QUOTA CURRENT` statement or the shorthand form\n' - '`SHOW CREATE QUOTA`\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Syntax = Requirement( - name='RQ.SRS-006.RBAC.Quota.ShowCreateQuota.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax when\n' - 'using the `SHOW CREATE QUOTA` statement.\n' - '\n' - '```sql\n' - 'SHOW CREATE QUOTA [name | CURRENT]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support creating row policy using the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_IfNotExists = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.IfNotExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `IF NOT EXISTS` clause in the `CREATE ROW POLICY` statement\n' - 'to skip raising an exception if a row policy with the same **name** already exists.\n' - 'If the `IF NOT EXISTS` clause is not specified then an exception SHALL be raised if\n' - 'a row policy with the same **name** already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Replace = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Replace', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support `OR REPLACE` clause in the `CREATE ROW POLICY` statement\n' - 'to replace existing row policy if it already exists.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying cluster on which to create the role policy\n' - 'using the `ON CLUSTER` clause in the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_On = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.On', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying table on which to create the role policy\n' - 'using the `ON` clause in the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Access = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Access', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support allowing or restricting access to rows using the\n' - '`AS` clause in the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Access_Permissive = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Access.Permissive', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support allowing access to rows using the\n' - '`AS PERMISSIVE` clause in the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Access_Restrictive = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Access.Restrictive', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support restricting access to rows using the\n' - '`AS RESTRICTIVE` clause in the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_ForSelect = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.ForSelect', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying which rows are affected\n' - 'using the `FOR SELECT` clause in the `CREATE ROW POLICY` statement.\n' - 'REQUIRES CONFIRMATION\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Condition = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Condition', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying a condition that\n' - 'that can be any SQL expression which returns a boolean using the `USING`\n' - 'clause in the `CREATE ROW POLOCY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Assignment = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning row policy to one or more users\n' - 'or roles using the `TO` clause in the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_None = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning row policy to no users or roles using\n' - 'the `TO NONE` clause in the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_All = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support assigning row policy to all current users and roles\n' - 'using `TO ALL` clause in the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_AllExcept = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Assignment.AllExcept', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support excluding assignment of row policy to one or more users or roles using\n' - 'the `ALL EXCEPT` clause in the `CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Create_Syntax = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Create.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `CRETE ROW POLICY` statement\n' - '\n' - '``` sql\n' - 'CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name [ON CLUSTER cluster_name] ON [db.]table\n' - ' [AS {PERMISSIVE | RESTRICTIVE}]\n' - ' [FOR SELECT]\n' - ' [USING condition]\n' - ' [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering row policy using the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_IfExists = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the `IF EXISTS` clause in the `ALTER ROW POLICY` statement\n' - 'to skip raising an exception if a row policy does not exist.\n' - 'If the `IF EXISTS` clause is not specified then an exception SHALL be raised if\n' - 'a row policy does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_ForSelect = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.ForSelect', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support modifying rows on which to apply the row policy\n' - 'using the `FOR SELECT` clause in the `ALTER ROW POLICY` statement.\n' - 'REQUIRES FUNCTION CONFIRMATION.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying cluster on which to alter the row policy\n' - 'using the `ON CLUSTER` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_On = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.On', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support specifying table on which to alter the row policy\n' - 'using the `ON` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Rename = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Rename', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support renaming the row policy using the `RENAME` clause\n' - 'in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Access = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Access', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support altering access to rows using the\n' - '`AS` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Permissive = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Permissive', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support permitting access to rows using the\n' - '`AS PERMISSIVE` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Restrictive = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Access.Restrictive', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support restricting access to rows using the\n' - '`AS RESTRICTIVE` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Condition = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Condition', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support re-specifying the row policy condition\n' - 'using the `USING` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Condition_None = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Condition.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support removing the row policy condition\n' - 'using the `USING NONE` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support reassigning row policy to one or more users\n' - 'or roles using the `TO` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_None = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.None', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support reassigning row policy to no users or roles using\n' - 'the `TO NONE` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_All = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support reassigning row policy to all current users and roles\n' - 'using the `TO ALL` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_AllExcept = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Assignment.AllExcept', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support excluding assignment of row policy to one or more users or roles using\n' - 'the `ALL EXCEPT` clause in the `ALTER ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Alter_Syntax = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Alter.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `ALTER ROW POLICY` statement\n' - '\n' - '``` sql\n' - 'ALTER [ROW] POLICY [IF EXISTS] name [ON CLUSTER cluster_name] ON [database.]table\n' - ' [RENAME TO new_name]\n' - ' [AS {PERMISSIVE | RESTRICTIVE}]\n' - ' [FOR SELECT]\n' - ' [USING {condition | NONE}][,...]\n' - ' [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Drop = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support removing one or more row policies using the `DROP ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Drop_IfExists = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Drop.IfExists', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support using the `IF EXISTS` clause in the `DROP ROW POLICY` statement\n' - 'to skip raising an exception when the row policy does not exist.\n' - 'If the `IF EXISTS` clause is not specified then an exception SHALL be\n' - 'raised if the row policy does not exist.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Drop_On = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Drop.On', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support removing row policy from one or more specified tables\n' - 'using the `ON` clause in the `DROP ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Drop.OnCluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support removing row policy from specified cluster\n' - 'using the `ON CLUSTER` clause in the `DROP ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_Drop_Syntax = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.Drop.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for the `DROP ROW POLICY` statement.\n' - '\n' - '``` sql\n' - 'DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...] [ON CLUSTER cluster_name]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing the `CREATE ROW POLICY` statement used to create the row policy\n' - 'using the `SHOW CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_On = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.On', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing statement used to create row policy on specific table\n' - 'using the `ON` in the `SHOW CREATE ROW POLICY` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_Syntax = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.ShowCreateRowPolicy.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for `SHOW CREATE ROW POLICY`.\n' - '\n' - '``` sql\n' - 'SHOW CREATE [ROW] POLICY name ON [database.]table\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing row policies using the `SHOW ROW POLICIES` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_On = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.On', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support showing row policies on a specific table\n' - 'using the `ON` clause in the `SHOW ROW POLICIES` statement.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_Syntax = Requirement( - name='RQ.SRS-006.RBAC.RowPolicy.ShowRowPolicies.Syntax', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the following syntax for `SHOW ROW POLICIES`.\n' - '\n' - '```sql\n' - 'SHOW [ROW] POLICIES [ON [database.]table]\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Table_PublicTables = Requirement( - name='RQ.SRS-006.RBAC.Table.PublicTables', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support that a user without any privileges will be able to access the following tables\n' - '\n' - '* system.one\n' - '* system.numbers\n' - '* system.contributors\n' - '* system.functions\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Table_SensitiveTables = Requirement( - name='RQ.SRS-006.RBAC.Table.SensitiveTables', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL not support a user with no privileges accessing the following `system` tables:\n' - '\n' - '* processes\n' - '* query_log\n' - '* query_thread_log\n' - '* clusters\n' - '* events\n' - '* graphite_retentions\n' - '* stack_trace\n' - '* trace_log\n' - '* user_directories\n' - '* zookeeper\n' - '* macros\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_DistributedTable_Create = Requirement( - name='RQ.SRS-006.RBAC.DistributedTable.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully `CREATE` a distributed table if and only if\n' - 'the user has **create table** privilege on the table and **remote** privilege on *.*\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_DistributedTable_Select = Requirement( - name='RQ.SRS-006.RBAC.DistributedTable.Select', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully `SELECT` from a distributed table if and only if\n' - 'the user has **select** privilege on the table and on the remote table specified in the `CREATE` query of the distributed table.\n' - '\n' - 'Does not require **select** privilege for the remote table if the remote table does not exist on the same server as the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_DistributedTable_Insert = Requirement( - name='RQ.SRS-006.RBAC.DistributedTable.Insert', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully `INSERT` into a distributed table if and only if\n' - 'the user has **insert** privilege on the table and on the remote table specified in the `CREATE` query of the distributed table.\n' - '\n' - 'Does not require **insert** privilege for the remote table if the remote table does not exist on the same server as the user,\n' - 'insert executes into the remote table on a different server.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_DistributedTable_SpecialTables = Requirement( - name='RQ.SRS-006.RBAC.DistributedTable.SpecialTables', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute a query using a distributed table that uses one of the special tables if and only if\n' - 'the user has the necessary privileges to interact with that special table, either granted directly or through a role.\n' - 'Special tables include:\n' - '* materialized view\n' - '* distributed table\n' - '* source table of a materialized view\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_DistributedTable_LocalUser = Requirement( - name='RQ.SRS-006.RBAC.DistributedTable.LocalUser', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute a query using a distributed table from\n' - 'a user present locally, but not remotely.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_DistributedTable_SameUserDifferentNodesDifferentPrivileges = Requirement( - name='RQ.SRS-006.RBAC.DistributedTable.SameUserDifferentNodesDifferentPrivileges', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute a query using a distributed table by a user that exists on multiple nodes\n' - 'if and only if the user has the required privileges on the node the query is being executed from.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_View = Requirement( - name='RQ.SRS-006.RBAC.View', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to **create**, **select** and **drop**\n' - 'privileges for a view for users or roles.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_View_Create = Requirement( - name='RQ.SRS-006.RBAC.View.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully execute a `CREATE VIEW` command if and only if\n' - 'the user has **create view** privilege either explicitly or through roles.\n' - '\n' - 'If the stored query includes one or more source tables, the user must have **select** privilege\n' - 'on all the source tables either explicitly or through a role.\n' - 'For example,\n' - '```sql\n' - 'CREATE VIEW view AS SELECT * FROM source_table\n' - 'CREATE VIEW view AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' - 'CREATE VIEW view AS SELECT * FROM table0 JOIN table1 USING column\n' - 'CREATE VIEW view AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' - 'CREATE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' - 'CREATE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_View_Select = Requirement( - name='RQ.SRS-006.RBAC.View.Select', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully `SELECT` from a view if and only if\n' - 'the user has **select** privilege for that view either explicitly or through a role.\n' - '\n' - 'If the stored query includes one or more source tables, the user must have **select** privilege\n' - 'on all the source tables either explicitly or through a role.\n' - 'For example,\n' - '```sql\n' - 'CREATE VIEW view AS SELECT * FROM source_table\n' - 'CREATE VIEW view AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' - 'CREATE VIEW view AS SELECT * FROM table0 JOIN table1 USING column\n' - 'CREATE VIEW view AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' - 'CREATE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' - 'CREATE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' - '\n' - 'SELECT * FROM view\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_View_Drop = Requirement( - name='RQ.SRS-006.RBAC.View.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if\n' - 'the user has **drop view** privilege on that view either explicitly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to **create**, **select**, **alter** and **drop**\n' - 'privileges for a materialized view for users or roles.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView_Create = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully execute a `CREATE MATERIALIZED VIEW` command if and only if\n' - 'the user has **create view** privilege either explicitly or through roles.\n' - '\n' - 'If `POPULATE` is specified, the user must have `INSERT` privilege on the view,\n' - 'either explicitly or through roles.\n' - 'For example,\n' - '```sql\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory POPULATE AS SELECT * FROM source_table\n' - '```\n' - '\n' - 'If the stored query includes one or more source tables, the user must have **select** privilege\n' - 'on all the source tables either explicitly or through a role.\n' - 'For example,\n' - '```sql\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM source_table\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 JOIN table1 USING column\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' - 'CREATE MATERIALIZED VIEW view0 ENGINE = Memory AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' - '```\n' - '\n' - 'If the materialized view has a target table explicitly declared in the `TO` clause, the user must have\n' - '**insert** and **select** privilege on the target table.\n' - 'For example,\n' - '```sql\n' - 'CREATE MATERIALIZED VIEW view TO target_table AS SELECT * FROM source_table\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView_Select = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView.Select', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully `SELECT` from a materialized view if and only if\n' - 'the user has **select** privilege for that view either explicitly or through a role.\n' - '\n' - 'If the stored query includes one or more source tables, the user must have **select** privilege\n' - 'on all the source tables either explicitly or through a role.\n' - 'For example,\n' - '```sql\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM source_table\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 JOIN table1 USING column\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' - 'CREATE MATERIALIZED VIEW view ENGINE = Memory AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' - 'CREATE MATERIALIZED VIEW view0 ENGINE = Memory AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' - '\n' - 'SELECT * FROM view\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView_Select_TargetTable = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView.Select.TargetTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully `SELECT` from the target table, implicit or explicit, of a materialized view if and only if\n' - 'the user has `SELECT` privilege for the table, either explicitly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView_Select_SourceTable = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView.Select.SourceTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully `SELECT` from the source table of a materialized view if and only if\n' - 'the user has `SELECT` privilege for the table, either explicitly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView_Drop = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if\n' - 'the user has **drop view** privilege on that view either explicitly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView_ModifyQuery = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView.ModifyQuery', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully execute a `MODIFY QUERY` command if and only if\n' - 'the user has **modify query** privilege on that view either explicitly or through a role.\n' - '\n' - 'If the new query includes one or more source tables, the user must have **select** privilege\n' - 'on all the source tables either explicitly or through a role.\n' - 'For example,\n' - '```sql\n' - 'ALTER TABLE view MODIFY QUERY SELECT * FROM source_table\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView_Insert = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView.Insert', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only succesfully `INSERT` into a materialized view if and only if\n' - 'the user has `INSERT` privilege on the view, either explicitly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView_Insert_SourceTable = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView.Insert.SourceTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only succesfully `INSERT` into a source table of a materialized view if and only if\n' - 'the user has `INSERT` privilege on the source table, either explicitly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_MaterializedView_Insert_TargetTable = Requirement( - name='RQ.SRS-006.RBAC.MaterializedView.Insert.TargetTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only succesfully `INSERT` into a target table of a materialized view if and only if\n' - 'the user has `INSERT` privelege on the target table, either explicitly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_LiveView = Requirement( - name='RQ.SRS-006.RBAC.LiveView', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to **create**, **select**, **alter** and **drop**\n' - 'privileges for a live view for users or roles.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_LiveView_Create = Requirement( - name='RQ.SRS-006.RBAC.LiveView.Create', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully execute a `CREATE LIVE VIEW` command if and only if\n' - 'the user has **create view** privilege either explicitly or through roles.\n' - '\n' - 'If the stored query includes one or more source tables, the user must have **select** privilege\n' - 'on all the source tables either explicitly or through a role.\n' - 'For example,\n' - '```sql\n' - 'CREATE LIVE VIEW view AS SELECT * FROM source_table\n' - 'CREATE LIVE VIEW view AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' - 'CREATE LIVE VIEW view AS SELECT * FROM table0 JOIN table1 USING column\n' - 'CREATE LIVE VIEW view AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' - 'CREATE LIVE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' - 'CREATE LIVE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_LiveView_Select = Requirement( - name='RQ.SRS-006.RBAC.LiveView.Select', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully `SELECT` from a live view if and only if\n' - 'the user has **select** privilege for that view either explicitly or through a role.\n' - '\n' - 'If the stored query includes one or more source tables, the user must have **select** privilege\n' - 'on all the source tables either explicitly or through a role.\n' - 'For example,\n' - '```sql\n' - 'CREATE LIVE VIEW view AS SELECT * FROM source_table\n' - 'CREATE LIVE VIEW view AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' - 'CREATE LIVE VIEW view AS SELECT * FROM table0 JOIN table1 USING column\n' - 'CREATE LIVE VIEW view AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' - 'CREATE LIVE VIEW view AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' - 'CREATE LIVE VIEW view0 AS SELECT column FROM view1 UNION ALL SELECT column FROM view2\n' - '\n' - 'SELECT * FROM view\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_LiveView_Drop = Requirement( - name='RQ.SRS-006.RBAC.LiveView.Drop', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully execute a `DROP VIEW` command if and only if\n' - 'the user has **drop view** privilege on that view either explicitly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_LiveView_Refresh = Requirement( - name='RQ.SRS-006.RBAC.LiveView.Refresh', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully execute an `ALTER LIVE VIEW REFRESH` command if and only if\n' - 'the user has **refresh** privilege on that view either explicitly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Select = Requirement( - name='RQ.SRS-006.RBAC.Select', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL execute `SELECT` if and only if the user\n' - 'has the **select** privilege for the destination table\n' - 'either because of the explicit grant or through one of the roles assigned to the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Select_Column = Requirement( - name='RQ.SRS-006.RBAC.Select.Column', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **select** privilege\n' - 'for one or more specified columns in a table to one or more **users** or **roles**.\n' - 'Any `SELECT` statements SHALL not to be executed, unless the user\n' - 'has the **select** privilege for the destination column\n' - 'either because of the explicit grant or through one of the roles assigned to the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Select_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Select.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **select** privilege\n' - 'on a specified cluster to one or more **users** or **roles**.\n' - 'Any `SELECT` statements SHALL succeed only on nodes where\n' - 'the table exists and privilege was granted.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Select_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Select.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **select** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Insert = Requirement( - name='RQ.SRS-006.RBAC.Insert', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL execute `INSERT INTO` if and only if the user\n' - 'has the **insert** privilege for the destination table\n' - 'either because of the explicit grant or through one of the roles assigned to the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Insert_Column = Requirement( - name='RQ.SRS-006.RBAC.Insert.Column', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **insert** privilege\n' - 'for one or more specified columns in a table to one or more **users** or **roles**.\n' - 'Any `INSERT INTO` statements SHALL not to be executed, unless the user\n' - 'has the **insert** privilege for the destination column\n' - 'either because of the explicit grant or through one of the roles assigned to the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Insert_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Insert.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **insert** privilege\n' - 'on a specified cluster to one or more **users** or **roles**.\n' - 'Any `INSERT INTO` statements SHALL succeed only on nodes where\n' - 'the table exists and privilege was granted.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Insert_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Insert.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **insert** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterColumn = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterColumn', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter column** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN` statements SHALL\n' - 'return an error, unless the user has the **alter column** privilege for\n' - 'the destination table either because of the explicit grant or through one of\n' - 'the roles assigned to the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterColumn_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter column** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterColumn_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter column** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterColumn_Column = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Column', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **alter column** privilege\n' - 'for one or more specified columns in a table to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN` statements SHALL return an error,\n' - 'unless the user has the **alter column** privilege for the destination column\n' - 'either because of the explicit grant or through one of the roles assigned to the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterColumn_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterColumn.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **alter column** privilege\n' - 'on a specified cluster to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN`\n' - 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterColumn_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterColumn.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter column** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterIndex = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterIndex', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter index** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... ORDER BY | ADD|DROP|MATERIALIZE|CLEAR INDEX` statements SHALL\n' - 'return an error, unless the user has the **alter index** privilege for\n' - 'the destination table either because of the explicit grant or through one of\n' - 'the roles assigned to the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterIndex_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterIndex.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter index** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterIndex_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterIndex.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter index** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterIndex_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterIndex.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **alter index** privilege\n' - 'on a specified cluster to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... ORDER BY | ADD|DROP|MATERIALIZE|CLEAR INDEX`\n' - 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterIndex_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterIndex.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter index** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterConstraint = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterConstraint', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter constraint** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... ADD|CREATE CONSTRAINT` statements SHALL\n' - 'return an error, unless the user has the **alter constraint** privilege for\n' - 'the destination table either because of the explicit grant or through one of\n' - 'the roles assigned to the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterConstraint_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter constraint** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterConstraint_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter constraint** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterConstraint_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **alter constraint** privilege\n' - 'on a specified cluster to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... ADD|DROP CONSTRAINT`\n' - 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterConstraint_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterConstraint.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter constraint** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterTTL = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterTTL', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter ttl** or **alter materialize ttl** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... ALTER TTL | ALTER MATERIALIZE TTL` statements SHALL\n' - 'return an error, unless the user has the **alter ttl** or **alter materialize ttl** privilege for\n' - 'the destination table either because of the explicit grant or through one of\n' - 'the roles assigned to the user.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterTTL_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterTTL.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter ttl** or **alter materialize ttl** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterTTL_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterTTL.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter ttl** or **alter materialize ttl** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterTTL_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterTTL.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **alter ttl** or **alter materialize ttl** privilege\n' - 'on a specified cluster to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... ALTER TTL | ALTER MATERIALIZE TTL`\n' - 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterTTL_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterTTL.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter ttl** or **alter materialize ttl** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterSettings = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterSettings', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter settings** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... MODIFY SETTING setting` statements SHALL\n' - 'return an error, unless the user has the **alter settings** privilege for\n' - 'the destination table either because of the explicit grant or through one of\n' - 'the roles assigned to the user. The **alter settings** privilege allows\n' - 'modifying table engine settings. It doesn’t affect settings or server configuration parameters.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterSettings_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterSettings.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter settings** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterSettings_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterSettings.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter settings** privilege\n' - 'for a database or a specific table to one or more **users** or **roles**\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterSettings_Cluster = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterSettings.Cluster', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking **alter settings** privilege\n' - 'on a specified cluster to one or more **users** or **roles**.\n' - 'Any `ALTER TABLE ... MODIFY SETTING setting`\n' - 'statements SHALL succeed only on nodes where the table exists and privilege was granted.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterSettings_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterSettings.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter settings** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterUpdate = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterUpdate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER UPDATE` statement if and only if the user has **alter update** privilege for that column,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterUpdate_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterUpdate.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter update** privilege on a column level\n' - 'to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterUpdate_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterUpdate.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter update** privilege on a column level\n' - 'from one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterUpdate_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterUpdate.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter update** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterDelete = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterDelete', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER DELETE` statement if and only if the user has **alter delete** privilege for that table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterDelete_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterDelete.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter delete** privilege on a column level\n' - 'to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterDelete_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterDelete.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter delete** privilege on a column level\n' - 'from one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterDelete_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterDelete.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter delete** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterFreeze = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterFreeze', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER FREEZE` statement if and only if the user has **alter freeze** privilege for that table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterFreeze_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterFreeze.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter freeze** privilege on a column level\n' - 'to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterFreeze_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterFreeze.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter freeze** privilege on a column level\n' - 'from one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterFreeze_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterFreeze.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter freeze** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterFetch = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterFetch', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER FETCH` statement if and only if the user has **alter fetch** privilege for that table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterFetch_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterFetch.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter fetch** privilege on a column level\n' - 'to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterFetch_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterFetch.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter fetch** privilege on a column level\n' - 'from one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterFetch_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterFetch.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter fetch** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterMove = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterMove', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER MOVE` statement if and only if the user has **alter move**, **select**, and **alter delete** privilege on the source table\n' - 'and **insert** privilege on the target table, either directly or through a role.\n' - 'For example,\n' - '```sql\n' - 'ALTER TABLE source_table MOVE PARTITION 1 TO target_table\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterMove_Grant = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterMove.Grant', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting **alter move** privilege on a column level\n' - 'to one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterMove_Revoke = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterMove.Revoke', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support revoking **alter move** privilege on a column level\n' - 'from one or more **users** or **roles**.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterMove_TableEngines = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterMove.TableEngines', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support controlling access to the **alter move** privilege\n' - 'on tables created using the following engines\n' - '\n' - '* MergeTree\n' - '* ReplacingMergeTree\n' - '* SummingMergeTree\n' - '* AggregatingMergeTree\n' - '* CollapsingMergeTree\n' - '* VersionedCollapsingMergeTree\n' - '* GraphiteMergeTree\n' - '* ReplicatedMergeTree\n' - '* ReplicatedSummingMergeTree\n' - '* ReplicatedReplacingMergeTree\n' - '* ReplicatedAggregatingMergeTree\n' - '* ReplicatedCollapsingMergeTree\n' - '* ReplicatedVersionedCollapsingMergeTree\n' - '* ReplicatedGraphiteMergeTree\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateTable = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL only successfully execute a `CREATE TABLE` command if and only if\n' - 'the user has **create table** privilege either explicitly or through roles.\n' - '\n' - 'If the stored query includes one or more source tables, the user must have **select** privilege\n' - "on all the source tables and **insert** for the table they're trying to create either explicitly or through a role.\n" - 'For example,\n' - '```sql\n' - 'CREATE TABLE table AS SELECT * FROM source_table\n' - 'CREATE TABLE table AS SELECT * FROM table0 WHERE column IN (SELECT column FROM table1 WHERE column IN (SELECT column FROM table2 WHERE expression))\n' - 'CREATE TABLE table AS SELECT * FROM table0 JOIN table1 USING column\n' - 'CREATE TABLE table AS SELECT * FROM table0 UNION ALL SELECT * FROM table1 UNION ALL SELECT * FROM table2\n' - 'CREATE TABLE table AS SELECT column FROM table0 JOIN table1 USING column UNION ALL SELECT column FROM table2 WHERE column IN (SELECT column FROM table3 WHERE column IN (SELECT column FROM table4 WHERE expression))\n' - 'CREATE TABLE table0 AS SELECT column FROM table1 UNION ALL SELECT column FROM table2\n' - '```\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateDatabase = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateDatabase', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CREATE DATABASE` statement if and only if the user has **create database** privilege on the database,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateDictionary = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateDictionary', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CREATE DICTIONARY` statement if and only if the user has **create dictionary** privilege on the dictionary,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateTemporaryTable = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateTemporaryTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CREATE TEMPORARY TABLE` statement if and only if the user has **create temporary table** privilege on the table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AttachDatabase = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AttachDatabase', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ATTACH DATABASE` statement if and only if the user has **create database** privilege on the database,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AttachDictionary = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AttachDictionary', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ATTACH DICTIONARY` statement if and only if the user has **create dictionary** privilege on the dictionary,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AttachTemporaryTable = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AttachTemporaryTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ATTACH TEMPORARY TABLE` statement if and only if the user has **create temporary table** privilege on the table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AttachTable = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AttachTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ATTACH TABLE` statement if and only if the user has **create table** privilege on the table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DropTable = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DropTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DROP TABLE` statement if and only if the user has **drop table** privilege on the table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DropDatabase = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DropDatabase', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DROP DATABASE` statement if and only if the user has **drop database** privilege on the database,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DropDictionary = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DropDictionary', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DROP DICTIONARY` statement if and only if the user has **drop dictionary** privilege on the dictionary,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DetachTable = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DetachTable', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DETACH TABLE` statement if and only if the user has **drop table** privilege on the table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DetachView = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DetachView', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DETACH VIEW` statement if and only if the user has **drop view** privilege on the view,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DetachDatabase = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DetachDatabase', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DETACH DATABASE` statement if and only if the user has **drop database** privilege on the database,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DetachDictionary = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DetachDictionary', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DETACH DICTIONARY` statement if and only if the user has **drop dictionary** privilege on the dictionary,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Truncate = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Truncate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `TRUNCATE TABLE` statement if and only if the user has **truncate table** privilege on the table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Optimize = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Optimize', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `OPTIMIZE TABLE` statement if and only if the user has **optimize table** privilege on the table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_KillQuery = Requirement( - name='RQ.SRS-006.RBAC.Privileges.KillQuery', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `KILL QUERY` statement if and only if the user has **kill query** privilege,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_KillMutation = Requirement( - name='RQ.SRS-006.RBAC.Privileges.KillMutation', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `KILL MUTATION` statement if and only if\n' - 'the user has the privilege that created the mutation, either directly or through a role.\n' - 'For example, to `KILL MUTATION` after `ALTER UPDATE` query, the user needs `ALTER UPDATE` privilege.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_KillMutation_AlterUpdate = Requirement( - name='RQ.SRS-006.RBAC.Privileges.KillMutation.AlterUpdate', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER UPDATE` mutation if and only if\n' - 'the user has `ALTER UPDATE` privilege on the table where the mutation was created, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_KillMutation_AlterDelete = Requirement( - name='RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDelete', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER DELETE` mutation if and only if\n' - 'the user has `ALTER DELETE` privilege on the table where the mutation was created, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_KillMutation_AlterDropColumn = Requirement( - name='RQ.SRS-006.RBAC.Privileges.KillMutation.AlterDropColumn', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `KILL MUTATION` query on an `ALTER DROP COLUMN` mutation if and only if\n' - 'the user has `ALTER DROP COLUMN` privilege on the table where the mutation was created, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowTables_Privilege = Requirement( - name='RQ.SRS-006.RBAC.ShowTables.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL grant **show tables** privilege on a table to a user if that user has recieved any grant,\n' - 'including `SHOW TABLES`, on that table, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowTables_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowTables.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW TABLES` statement if and only if the user has **show tables** privilege,\n' - 'or any privilege on the table either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ExistsTable_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ExistsTable.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `EXISTS table` statement if and only if the user has **show tables** privilege,\n' - 'or any privilege on the table either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_CheckTable_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.CheckTable.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CHECK table` statement if and only if the user has **show tables** privilege,\n' - 'or any privilege on the table either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowDatabases_Privilege = Requirement( - name='RQ.SRS-006.RBAC.ShowDatabases.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL grant **show databases** privilege on a database to a user if that user has recieved any grant,\n' - 'including `SHOW DATABASES`, on that table, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowDatabases_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowDatabases.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW DATABASES` statement if and only if the user has **show databases** privilege,\n' - 'or any privilege on the database either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowCreateDatabase_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowCreateDatabase.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW CREATE DATABASE` statement if and only if the user has **show databases** privilege,\n' - 'or any privilege on the database either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_UseDatabase_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.UseDatabase.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `USE database` statement if and only if the user has **show databases** privilege,\n' - 'or any privilege on the database either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowColumns_Privilege = Requirement( - name='RQ.SRS-006.RBAC.ShowColumns.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking the `SHOW COLUMNS` privilege.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowCreateTable_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowCreateTable.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW CREATE TABLE` statement if and only if the user has **show columns** privilege on that table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_DescribeTable_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.DescribeTable.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DESCRIBE table` statement if and only if the user has **show columns** privilege on that table,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowDictionaries_Privilege = Requirement( - name='RQ.SRS-006.RBAC.ShowDictionaries.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL grant **show dictionaries** privilege on a dictionary to a user if that user has recieved any grant,\n' - 'including `SHOW DICTIONARIES`, on that dictionary, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowDictionaries_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowDictionaries.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW DICTIONARIES` statement if and only if the user has **show dictionaries** privilege,\n' - 'or any privilege on the dictionary either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowCreateDictionary_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowCreateDictionary.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW CREATE DICTIONARY` statement if and only if the user has **show dictionaries** privilege,\n' - 'or any privilege on the dictionary either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ExistsDictionary_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ExistsDictionary.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `EXISTS dictionary` statement if and only if the user has **show dictionaries** privilege,\n' - 'or any privilege on the dictionary either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateUser = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateUser', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CREATE USER` statement if and only if the user has **create user** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateUser_DefaultRole = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateUser.DefaultRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CREATE USER` statement with `DEFAULT ROLE ` clause if and only if\n' - 'the user has **create user** privilege and the role with **admin option**, or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterUser = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterUser', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER USER` statement if and only if the user has **alter user** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DropUser = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DropUser', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DROP USER` statement if and only if the user has **drop user** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateRole = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CREATE ROLE` statement if and only if the user has **create role** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterRole = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER ROLE` statement if and only if the user has **alter role** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DropRole = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DropRole', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DROP ROLE` statement if and only if the user has **drop role** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateRowPolicy = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateRowPolicy', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CREATE ROW POLICY` statement if and only if the user has **create row policy** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterRowPolicy = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterRowPolicy', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER ROW POLICY` statement if and only if the user has **alter row policy** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DropRowPolicy = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DropRowPolicy', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DROP ROW POLICY` statement if and only if the user has **drop row policy** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateQuota = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateQuota', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CREATE QUOTA` statement if and only if the user has **create quota** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterQuota = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterQuota', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER QUOTA` statement if and only if the user has **alter quota** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DropQuota = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DropQuota', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DROP QUOTA` statement if and only if the user has **drop quota** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_CreateSettingsProfile = Requirement( - name='RQ.SRS-006.RBAC.Privileges.CreateSettingsProfile', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `CREATE SETTINGS PROFILE` statement if and only if the user has **create settings profile** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AlterSettingsProfile = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AlterSettingsProfile', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `ALTER SETTINGS PROFILE` statement if and only if the user has **alter settings profile** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_DropSettingsProfile = Requirement( - name='RQ.SRS-006.RBAC.Privileges.DropSettingsProfile', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `DROP SETTINGS PROFILE` statement if and only if the user has **drop settings profile** privilege,\n' - 'or either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_RoleAdmin = Requirement( - name='RQ.SRS-006.RBAC.Privileges.RoleAdmin', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute any role grant or revoke by a user with `ROLE ADMIN` privilege.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowUsers_Privilege = Requirement( - name='RQ.SRS-006.RBAC.ShowUsers.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SHOW USERS` privilege when\n' - 'the user is granted `SHOW USERS`, `SHOW CREATE USER`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowUsers_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowUsers.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW USERS` statement if and only if the user has **show users** privilege,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowCreateUser_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowCreateUser.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW CREATE USER` statement if and only if the user has **show users** privilege,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowRoles_Privilege = Requirement( - name='RQ.SRS-006.RBAC.ShowRoles.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SHOW ROLES` privilege when\n' - 'the user is granted `SHOW ROLES`, `SHOW CREATE ROLE`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowRoles_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowRoles.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW ROLES` statement if and only if the user has **show roles** privilege,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowCreateRole_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowCreateRole.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW CREATE ROLE` statement if and only if the user has **show roles** privilege,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowRowPolicies_Privilege = Requirement( - name='RQ.SRS-006.RBAC.ShowRowPolicies.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SHOW ROW POLICIES` privilege when\n' - 'the user is granted `SHOW ROW POLICIES`, `SHOW POLICIES`, `SHOW CREATE ROW POLICY`,\n' - '`SHOW CREATE POLICY`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowRowPolicies_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowRowPolicies.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW ROW POLICIES` or `SHOW POLICIES` statement if and only if\n' - 'the user has **show row policies** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowCreateRowPolicy_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowCreateRowPolicy.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW CREATE ROW POLICY` or `SHOW CREATE POLICY` statement\n' - 'if and only if the user has **show row policies** privilege,either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowQuotas_Privilege = Requirement( - name='RQ.SRS-006.RBAC.ShowQuotas.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SHOW QUOTAS` privilege when\n' - 'the user is granted `SHOW QUOTAS`, `SHOW CREATE QUOTA`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowQuotas_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowQuotas.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW QUOTAS` statement if and only if the user has **show quotas** privilege,\n' - 'either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowCreateQuota_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowCreateQuota.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW CREATE QUOTA` statement if and only if\n' - 'the user has **show quotas** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowSettingsProfiles_Privilege = Requirement( - name='RQ.SRS-006.RBAC.ShowSettingsProfiles.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SHOW SETTINGS PROFILES` privilege when\n' - 'the user is granted `SHOW SETTINGS PROFILES`, `SHOW PROFILES`, `SHOW CREATE SETTINGS PROFILE`,\n' - '`SHOW SETTINGS PROFILE`, `SHOW ACCESS`, or `ACCESS MANAGEMENT`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowSettingsProfiles_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowSettingsProfiles.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW SETTINGS PROFILES` or `SHOW PROFILES` statement\n' - 'if and only if the user has **show settings profiles** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_ShowCreateSettingsProfile_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.ShowCreateSettingsProfile.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `SHOW CREATE SETTINGS PROFILE` or `SHOW CREATE PROFILE` statement\n' - 'if and only if the user has **show settings profiles** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_dictGet_Privilege = Requirement( - name='RQ.SRS-006.RBAC.dictGet.Privilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `dictGet` privilege when\n' - 'the user is granted `dictGet`, `dictHas`, `dictGetHierarchy`, or `dictIsIn`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_dictGet_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.dictGet.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `dictGet` statement\n' - 'if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_dictGet_Type_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.dictGet.Type.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `dictGet[TYPE]` statement\n' - 'if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role.\n' - 'Available types:\n' - '\n' - '* Int8\n' - '* Int16\n' - '* Int32\n' - '* Int64\n' - '* UInt8\n' - '* UInt16\n' - '* UInt32\n' - '* UInt64\n' - '* Float32\n' - '* Float64\n' - '* Date\n' - '* DateTime\n' - '* UUID\n' - '* String\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_dictGet_OrDefault_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.dictGet.OrDefault.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `dictGetOrDefault` statement\n' - 'if and only if the user has **dictGet** privilege on that dictionary, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_dictHas_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.dictHas.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `dictHas` statement\n' - 'if and only if the user has **dictGet** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_dictGetHierarchy_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.dictGetHierarchy.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `dictGetHierarchy` statement\n' - 'if and only if the user has **dictGet** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_dictIsIn_RequiredPrivilege = Requirement( - name='RQ.SRS-006.RBAC.dictIsIn.RequiredPrivilege', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `dictIsIn` statement\n' - 'if and only if the user has **dictGet** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Introspection = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Introspection', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `INTROSPECTION` privilege when\n' - 'the user is granted `INTROSPECTION` or `INTROSPECTION FUNCTIONS`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Introspection_addressToLine = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Introspection.addressToLine', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `addressToLine` statement if and only if\n' - 'the user has **introspection** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Introspection_addressToSymbol = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Introspection.addressToSymbol', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `addressToSymbol` statement if and only if\n' - 'the user has **introspection** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Introspection_demangle = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Introspection.demangle', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `demangle` statement if and only if\n' - 'the user has **introspection** privilege, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Shutdown = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Shutdown', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM SHUTDOWN` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM SHUTDOWN`, `SHUTDOWN`,or `SYSTEM KILL`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_DropCache = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.DropCache', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM DROP CACHE` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, or `DROP CACHE`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_DropCache_DNS = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.DropCache.DNS', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM DROP DNS CACHE` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP DNS CACHE`,\n' - '`SYSTEM DROP DNS`, `DROP DNS CACHE`, or `DROP DNS`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_DropCache_Mark = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.DropCache.Mark', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM DROP MARK CACHE` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP MARK CACHE`,\n' - '`SYSTEM DROP MARK`, `DROP MARK CACHE`, or `DROP MARKS`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_DropCache_Uncompressed = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.DropCache.Uncompressed', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM DROP UNCOMPRESSED CACHE` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM DROP CACHE`, `DROP CACHE`, `SYSTEM DROP UNCOMPRESSED CACHE`,\n' - '`SYSTEM DROP UNCOMPRESSED`, `DROP UNCOMPRESSED CACHE`, or `DROP UNCOMPRESSED`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Reload = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Reload', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD` privilege when\n' - 'the user is granted `SYSTEM` or `SYSTEM RELOAD`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Reload_Config = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Reload.Config', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD CONFIG` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD CONFIG`, or `RELOAD CONFIG`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionary = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionary', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD DICTIONARY` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARIES`, `RELOAD DICTIONARIES`, or `RELOAD DICTIONARY`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionaries = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Reload.Dictionaries', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD DICTIONARIES` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARIES`, `RELOAD DICTIONARIES`, or `RELOAD DICTIONARY`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Reload_EmbeddedDictionaries = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Reload.EmbeddedDictionaries', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM RELOAD EMBEDDED DICTIONARIES` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM RELOAD`, `SYSTEM RELOAD DICTIONARY ON *.*`, or `SYSTEM RELOAD EMBEDDED DICTIONARIES`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Merges = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Merges', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM MERGES` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM MERGES`, `SYSTEM STOP MERGES`, `SYSTEM START MERGES`, `STOP MERGES`, or `START MERGES`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_TTLMerges = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.TTLMerges', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM TTL MERGES` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM TTL MERGES`, `SYSTEM STOP TTL MERGES`, `SYSTEM START TTL MERGES`, `STOP TTL MERGES`, or `START TTL MERGES`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Fetches = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Fetches', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM FETCHES` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM FETCHES`, `SYSTEM STOP FETCHES`, `SYSTEM START FETCHES`, `STOP FETCHES`, or `START FETCHES`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Moves = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Moves', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM MOVES` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM MOVES`, `SYSTEM STOP MOVES`, `SYSTEM START MOVES`, `STOP MOVES`, or `START MOVES`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Sends = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Sends', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM SENDS` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM SENDS`, `SYSTEM STOP SENDS`, `SYSTEM START SENDS`, `STOP SENDS`, or `START SENDS`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Sends_Distributed = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Sends.Distributed', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM DISTRIBUTED SENDS` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM DISTRIBUTED SENDS`, `SYSTEM STOP DISTRIBUTED SENDS`,\n' - '`SYSTEM START DISTRIBUTED SENDS`, `STOP DISTRIBUTED SENDS`, or `START DISTRIBUTED SENDS`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Sends_Replicated = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Sends.Replicated', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM REPLICATED SENDS` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM REPLICATED SENDS`, `SYSTEM STOP REPLICATED SENDS`,\n' - '`SYSTEM START REPLICATED SENDS`, `STOP REPLICATED SENDS`, or `START REPLICATED SENDS`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_ReplicationQueues = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.ReplicationQueues', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM REPLICATION QUEUES` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM REPLICATION QUEUES`, `SYSTEM STOP REPLICATION QUEUES`,\n' - '`SYSTEM START REPLICATION QUEUES`, `STOP REPLICATION QUEUES`, or `START REPLICATION QUEUES`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_SyncReplica = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.SyncReplica', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM SYNC REPLICA` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM SYNC REPLICA`, or `SYNC REPLICA`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_RestartReplica = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.RestartReplica', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM RESTART REPLICA` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM RESTART REPLICA`, or `RESTART REPLICA`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Flush = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Flush', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM FLUSH` privilege when\n' - 'the user is granted `SYSTEM` or `SYSTEM FLUSH`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Flush_Distributed = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Flush.Distributed', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM FLUSH DISTRIBUTED` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM FLUSH DISTRIBUTED`, or `FLUSH DISTRIBUTED`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_System_Flush_Logs = Requirement( - name='RQ.SRS-006.RBAC.Privileges.System.Flush.Logs', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully grant `SYSTEM FLUSH LOGS` privilege when\n' - 'the user is granted `SYSTEM`, `SYSTEM FLUSH LOGS`, or `FLUSH LOGS`.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Sources = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Sources', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking `SOURCES` privilege from\n' - 'the user, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Sources_File = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Sources.File', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the use of `FILE` source by a user if and only if\n' - 'the user has `FILE` or `SOURCES` privileges granted to them directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Sources_URL = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Sources.URL', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the use of `URL` source by a user if and only if\n' - 'the user has `URL` or `SOURCES` privileges granted to them directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Sources_Remote = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Sources.Remote', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the use of `REMOTE` source by a user if and only if\n' - 'the user has `REMOTE` or `SOURCES` privileges granted to them directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Sources_MySQL = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Sources.MySQL', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the use of `MySQL` source by a user if and only if\n' - 'the user has `MySQL` or `SOURCES` privileges granted to them directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Sources_ODBC = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Sources.ODBC', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the use of `ODBC` source by a user if and only if\n' - 'the user has `ODBC` or `SOURCES` privileges granted to them directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Sources_JDBC = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Sources.JDBC', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the use of `JDBC` source by a user if and only if\n' - 'the user has `JDBC` or `SOURCES` privileges granted to them directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Sources_HDFS = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Sources.HDFS', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the use of `HDFS` source by a user if and only if\n' - 'the user has `HDFS` or `SOURCES` privileges granted to them directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_Sources_S3 = Requirement( - name='RQ.SRS-006.RBAC.Privileges.Sources.S3', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support the use of `S3` source by a user if and only if\n' - 'the user has `S3` or `SOURCES` privileges granted to them directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_GrantOption = Requirement( - name='RQ.SRS-006.RBAC.Privileges.GrantOption', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL successfully execute `GRANT` or `REVOKE` privilege statements by a user if and only if\n' - 'the user has that privilege with `GRANT OPTION`, either directly or through a role.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_All = Requirement( - name='RQ.SRS-006.RBAC.Privileges.All', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support granting or revoking `ALL` privilege.\n' - '\n' - ), - link=None) - -RQ_SRS_006_RBAC_Privileges_AdminOption = Requirement( - name='RQ.SRS-006.RBAC.Privileges.AdminOption', - version='1.0', - priority=None, - group=None, - type=None, - uid=None, - description=( - '[ClickHouse] SHALL support a user granting or revoking a role if and only if\n' - 'the user has that role with `ADMIN OPTION` privilege.\n' - '\n' - ), - link=None) diff --git a/tests/testflows/rbac/tests/privileges/admin_option.py b/tests/testflows/rbac/tests/privileges/admin_option.py index 88dadc8522c..f6115839bf5 100644 --- a/tests/testflows/rbac/tests/privileges/admin_option.py +++ b/tests/testflows/rbac/tests/privileges/admin_option.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(test=grant_role, flags=TE)(grant_target_name=user_name, user_name=user_name) + Suite(test=grant_role)(grant_target_name=user_name, user_name=user_name) @TestSuite def privileges_granted_via_role(self, node=None): @@ -35,7 +35,7 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(test=grant_role, flags=TE)(grant_target_name=role_name, user_name=user_name) + Suite(test=grant_role)(grant_target_name=role_name, user_name=user_name) @TestSuite def grant_role(self, grant_target_name, user_name, node=None): @@ -52,7 +52,13 @@ def grant_role(self, grant_target_name, user_name, node=None): with user(node, target_user_name), role(node, grant_role_name): - with When("I check the user can't grant a role"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't grant a role"): node.query(f"GRANT {grant_role_name} TO {target_user_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -109,6 +115,7 @@ def grant_role(self, grant_target_name, user_name, node=None): @Name("admin option") @Requirements( RQ_SRS_006_RBAC_Privileges_AdminOption("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of ADMIN OPTION. diff --git a/tests/testflows/rbac/tests/privileges/all_role.py b/tests/testflows/rbac/tests/privileges/all_role.py new file mode 100644 index 00000000000..629848a2746 --- /dev/null +++ b/tests/testflows/rbac/tests/privileges/all_role.py @@ -0,0 +1,37 @@ +from testflows.core import * +from testflows.asserts import error + +from rbac.requirements import * +from rbac.helper.common import * +import rbac.helper.errors as errors + +@TestScenario +def privilege_check(self, node=None): + '''Check that a role named ALL only grants privileges that it already has. + ''' + + user_name = f"user_{getuid()}" + + if node is None: + node = self.context.node + + with user(node, f"{user_name}"), role(node, "ALL"): + + with When("I grant the ALL role to the user"): + node.query(f"GRANT ALL TO {user_name}") + + with Then("I check the user doesn't have any privileges"): + output = node.query("SHOW TABLES", settings=[("user",user_name)]).output + assert output == '', error() + +@TestFeature +@Name("all role") +@Requirements( + RQ_SRS_006_RBAC_Privileges_RoleAll("1.0"), +) +def feature(self, node="clickhouse1"): + """Check the RBAC functionality of the role 'ALL'. + """ + self.context.node = self.context.cluster.node(node) + + Scenario(run=privilege_check, setup=instrument_clickhouse_server_log) diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_column.py b/tests/testflows/rbac/tests/privileges/alter/alter_column.py index 430872029b5..fe767ec15fa 100755 --- a/tests/testflows/rbac/tests/privileges/alter/alter_column.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_column.py @@ -354,6 +354,10 @@ def check_add_column_when_privilege_is_not_granted(table, user, node, column=Non node.query(f"ALTER TABLE {table} ADD COLUMN {column} String", settings = [("user", user)], exitcode=exitcode, message=message) + with Then("I try to ADD COLUMN"): + node.query(f"ALTER TABLE {table} ADD COLUMN {column} String", + settings = [("user", user)], exitcode=exitcode, message=message) + def check_clear_column_when_privilege_is_not_granted(table, user, node, column=None): """Ensures CLEAR COLUMN errors as expected without the required privilege for the specified user. @@ -366,6 +370,13 @@ def check_clear_column_when_privilege_is_not_granted(table, user, node, column=N node.query(f"ALTER TABLE {table} CLEAR COLUMN {column}", settings = [("user", user)], exitcode=exitcode, message=message) + with And(f"I grant NONE to the user"): + node.query(f"GRANT NONE TO {user}") + + with Then("I try to CLEAR COLUMN"): + node.query(f"ALTER TABLE {table} CLEAR COLUMN {column}", + settings = [("user", user)], exitcode=exitcode, message=message) + def check_modify_column_when_privilege_is_not_granted(table, user, node, column=None): """Ensures MODIFY COLUMN errors as expected without the required privilege for the specified user. @@ -378,6 +389,13 @@ def check_modify_column_when_privilege_is_not_granted(table, user, node, column= node.query(f"ALTER TABLE {table} MODIFY COLUMN {column} String", settings = [("user", user)], exitcode=exitcode, message=message) + with And(f"I grant NONE to the user"): + node.query(f"GRANT NONE TO {user}") + + with Then("I try to MODIFY COLUMN"): + node.query(f"ALTER TABLE {table} MODIFY COLUMN {column} String", + settings = [("user", user)], exitcode=exitcode, message=message) + def check_rename_column_when_privilege_is_not_granted(table, user, node, column=None): """Ensures RENAME COLUMN errors as expected without the required privilege for the specified user. @@ -392,6 +410,13 @@ def check_rename_column_when_privilege_is_not_granted(table, user, node, column= node.query(f"ALTER TABLE {table} RENAME COLUMN {column} TO {new_column}", settings = [("user", user)], exitcode=exitcode, message=message) + with And(f"I grant NONE to the user"): + node.query(f"GRANT NONE TO {user}") + + with Then("I try to RENAME COLUMN"): + node.query(f"ALTER TABLE {table} RENAME COLUMN {column} TO {new_column}", + settings = [("user", user)], exitcode=exitcode, message=message) + def check_comment_column_when_privilege_is_not_granted(table, user, node, column=None): """Ensures COMMENT COLUMN errors as expected without the required privilege for the specified user. @@ -404,6 +429,13 @@ def check_comment_column_when_privilege_is_not_granted(table, user, node, column node.query(f"ALTER TABLE {table} COMMENT COLUMN {column} 'This is a comment.'", settings = [("user", user)], exitcode=exitcode, message=message) + with And(f"I grant NONE to the user"): + node.query(f"GRANT NONE TO {user}") + + with When("I try to COMMENT COLUMN"): + node.query(f"ALTER TABLE {table} COMMENT COLUMN {column} 'This is a comment.'", + settings = [("user", user)], exitcode=exitcode, message=message) + def check_drop_column_when_privilege_is_not_granted(table, user, node, column=None): """Ensures DROP COLUMN errors as expected without the required privilege for the specified user. @@ -416,6 +448,13 @@ def check_drop_column_when_privilege_is_not_granted(table, user, node, column=No node.query(f"ALTER TABLE {table} DROP COLUMN {column}", settings = [("user", user)], exitcode=exitcode, message=message) + with And(f"I grant NONE to the user"): + node.query(f"GRANT NONE TO {user}") + + with Then("I try to DROP COLUMN"): + node.query(f"ALTER TABLE {table} DROP COLUMN {column}", + settings = [("user", user)], exitcode=exitcode, message=message) + @TestScenario def user_with_some_privileges(self, permutation, table_type, node=None): """Check that user with some privileges of ALTER COLUMN is able @@ -676,7 +715,8 @@ def scenario_parallelization(self, table_type, permutation): @Requirements( RQ_SRS_006_RBAC_Privileges_AlterColumn("1.0"), RQ_SRS_006_RBAC_Privileges_AlterColumn_TableEngines("1.0"), - RQ_SRS_006_RBAC_Privileges_All("1.0") + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_constraint.py b/tests/testflows/rbac/tests/privileges/alter/alter_constraint.py index 59ff1828222..58f4349459c 100755 --- a/tests/testflows/rbac/tests/privileges/alter/alter_constraint.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_constraint.py @@ -275,7 +275,8 @@ def user_with_privileges_on_cluster(self, table_type, node=None): @Requirements( RQ_SRS_006_RBAC_Privileges_AlterConstraint("1.0"), RQ_SRS_006_RBAC_Privileges_AlterConstraint_TableEngines("1.0"), - RQ_SRS_006_RBAC_Privileges_All("1.0") + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_delete.py b/tests/testflows/rbac/tests/privileges/alter/alter_delete.py index 9f46e6cdb3d..93d520f91bd 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_delete.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_delete.py @@ -1,5 +1,3 @@ -from multiprocessing.dummy import Pool - from testflows.core import * from testflows.asserts import error @@ -11,7 +9,8 @@ aliases = {"ALTER DELETE", "DELETE", "ALL"} @TestSuite def privilege_granted_directly_or_via_role(self, table_type, privilege, node=None): - """Check that user is only able to execute ALTER DELETE when they have required privilege, either directly or via role. + """Check that user is only able to execute ALTER DELETE when they have required privilege, + either directly or via role. """ role_name = f"role_{getuid()}" user_name = f"user_{getuid()}" @@ -21,13 +20,16 @@ def privilege_granted_directly_or_via_role(self, table_type, privilege, node=Non with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): with user(node, user_name): + with When(f"I run checks that {user_name} is only able to execute ALTER DELETE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, table_type=table_type, privilege=privilege, node=node) with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): with user(node, user_name), role(node, role_name): + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") + with And(f"I run checks that {user_name} with {role_name} is only able to execute ALTER DELETE with required privileges"): privilege_check(grant_target_name=role_name, user_name=user_name, table_type=table_type, privilege=privilege, node=node) @@ -38,26 +40,41 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No with Scenario("user without privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): - with When("I attempt to delete columns without privilege"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to delete columns without privilege"): node.query(f"ALTER TABLE {table_name} DELETE WHERE 1", settings = [("user", user_name)], exitcode=exitcode, message=message) with Scenario("user with privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): + with When("I grant the delete privilege"): node.query(f"GRANT {privilege} ON {table_name} TO {grant_target_name}") + with Then("I attempt to delete columns"): node.query(f"ALTER TABLE {table_name} DELETE WHERE 1", settings = [("user", user_name)]) with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): + with When("I grant the delete privilege"): node.query(f"GRANT {privilege} ON {table_name} TO {grant_target_name}") + with And("I revoke the delete privilege"): node.query(f"REVOKE {privilege} ON {table_name} FROM {grant_target_name}") + with Then("I attempt to delete columns"): node.query(f"ALTER TABLE {table_name} DELETE WHERE 1", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -65,7 +82,8 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AlterDelete("1.0"), - RQ_SRS_006_RBAC_Privileges_All("1.0") + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_fetch.py b/tests/testflows/rbac/tests/privileges/alter/alter_fetch.py index 56f2d48e7d2..b4ff0b65fd4 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_fetch.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_fetch.py @@ -1,5 +1,3 @@ -from multiprocessing.dummy import Pool - from testflows.core import * from testflows.asserts import error @@ -41,9 +39,16 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No with Scenario("user without privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): - with When("I attempt to fetch a partition without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to fetch a partition without privilege"): node.query(f"ALTER TABLE {table_name} FETCH PARTITION 1 FROM '/clickhouse/'", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -75,7 +80,8 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AlterFetch("1.0"), - RQ_SRS_006_RBAC_Privileges_All("1.0") + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type",[ ("ReplicatedMergeTree-sharded_cluster",), diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_freeze.py b/tests/testflows/rbac/tests/privileges/alter/alter_freeze.py index 32bd4602044..775e2be270d 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_freeze.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_freeze.py @@ -1,5 +1,3 @@ -from multiprocessing.dummy import Pool - from testflows.core import * from testflows.asserts import error @@ -38,14 +36,22 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No with Scenario("user without privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): - with When("I attempt to freeze partitions without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to freeze partitions without privilege"): node.query(f"ALTER TABLE {table_name} FREEZE", settings = [("user", user_name)], exitcode=exitcode, message=message) with Scenario("user with privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): with When("I grant the freeze privilege"): @@ -56,6 +62,7 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): with When("I grant the freeze privilege"): @@ -70,7 +77,8 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AlterFreeze("1.0"), - RQ_SRS_006_RBAC_Privileges_All("1.0") + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_index.py b/tests/testflows/rbac/tests/privileges/alter/alter_index.py index cd2729f5641..eeb126e95a5 100755 --- a/tests/testflows/rbac/tests/privileges/alter/alter_index.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_index.py @@ -26,7 +26,7 @@ aliases = { "MATERIALIZE INDEX" : ["ALTER MATERIALIZE INDEX", "MATERIALIZE INDEX"], "CLEAR INDEX": ["ALTER CLEAR INDEX", "CLEAR INDEX"], "DROP INDEX": ["ALTER DROP INDEX", "DROP INDEX"], - "ALTER INDEX": ["ALTER INDEX", "INDEX"] # super-privilege + "ALTER INDEX": ["ALTER INDEX", "INDEX", "ALL"] # super-privilege } # Extra permutation is for 'ALTER INDEX' super-privilege @@ -302,7 +302,6 @@ def check_drop_index_when_privilege_is_not_granted(table, user, node): settings = [("user", user)], exitcode=exitcode, message=message) @TestScenario -@Flags(TE) def user_with_some_privileges(self, table_type, node=None): """Check that user with any permutation of ALTER INDEX subprivileges is able to alter the table for privileges granted, and not for privileges not granted. @@ -325,7 +324,6 @@ def user_with_some_privileges(self, table_type, node=None): alter_index_privilege_handler(permutation, table_name, user_name, node) @TestScenario -@Flags(TE) @Requirements( RQ_SRS_006_RBAC_Privileges_AlterIndex_Revoke("1.0"), ) @@ -355,7 +353,6 @@ def user_with_revoked_privileges(self, table_type, node=None): alter_index_privilege_handler(0, table_name, user_name, node) @TestScenario -@Flags(TE) @Requirements( RQ_SRS_006_RBAC_Privileges_AlterIndex_Grant("1.0"), ) @@ -385,7 +382,6 @@ def role_with_some_privileges(self, table_type, node=None): alter_index_privilege_handler(permutation, table_name, user_name, node) @TestScenario -@Flags(TE) def user_with_revoked_role(self, table_type, node=None): """Check that user with a role that has ALTER INDEX privilege on a table is unable to ALTER INDEX from that table after the role with privilege has been revoked from the user. @@ -416,7 +412,6 @@ def user_with_revoked_role(self, table_type, node=None): alter_index_privilege_handler(0, table_name, user_name, node) @TestScenario -@Flags(TE) @Requirements( RQ_SRS_006_RBAC_Privileges_AlterIndex_Cluster("1.0"), ) @@ -451,12 +446,13 @@ def user_with_privileges_on_cluster(self, table_type, node=None): @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AlterIndex("1.0"), - RQ_SRS_006_RBAC_Privileges_AlterIndex_TableEngines("1.0") + RQ_SRS_006_RBAC_Privileges_AlterIndex_TableEngines("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() ]) -@Flags(TE) @Name("alter index") def feature(self, node="clickhouse1", stress=None, parallel=None): self.context.node = self.context.cluster.node(node) diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_move.py b/tests/testflows/rbac/tests/privileges/alter/alter_move.py index b53375434fe..d370edc35de 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_move.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_move.py @@ -7,7 +7,7 @@ from rbac.requirements import * from rbac.helper.common import * import rbac.helper.errors as errors -aliases = {"ALTER MOVE PARTITION", "ALTER MOVE PART", "MOVE PARTITION", "MOVE PART"} +aliases = {"ALTER MOVE PARTITION", "ALTER MOVE PART", "MOVE PARTITION", "MOVE PART", "ALL"} @TestSuite def privilege_granted_directly_or_via_role(self, table_type, privilege, node=None): @@ -45,7 +45,13 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No with table(node, f"{source_table_name},{target_table_name}", table_type): - with When("I attempt to move partition without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to move partition without privilege"): node.query(f"ALTER TABLE {source_table_name} MOVE PARTITION 1 TO TABLE {target_table_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -151,6 +157,8 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AlterMove("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_quota.py b/tests/testflows/rbac/tests/privileges/alter/alter_quota.py index 4d0d55c86de..faad7c001f4 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_quota.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_quota.py @@ -31,7 +31,7 @@ def alter_quota_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=alter_quota, flags=TE, + Suite(run=alter_quota, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in alter_quota.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -52,13 +52,14 @@ def alter_quota_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=alter_quota, flags=TE, + Suite(run=alter_quota, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in alter_quota.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("ALTER QUOTA",), ]) @@ -75,7 +76,13 @@ def alter_quota(self, privilege, grant_target_name, user_name, node=None): with quota(node, alter_quota_name): - with When("I check the user can't alter a quota"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't alter a quota"): node.query(f"ALTER QUOTA {alter_quota_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -127,6 +134,8 @@ def alter_quota(self, privilege, grant_target_name, user_name, node=None): @Name("alter quota") @Requirements( RQ_SRS_006_RBAC_Privileges_AlterQuota("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of ALTER QUOTA. diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_role.py b/tests/testflows/rbac/tests/privileges/alter/alter_role.py index cf98d66a689..49e8baa191b 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_role.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_role.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=alter_role, flags=TE, + Suite(run=alter_role, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in alter_role.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=alter_role, flags=TE, + Suite(run=alter_role, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in alter_role.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("ALTER ROLE",), ]) @@ -58,14 +59,22 @@ def alter_role(self, privilege, grant_target_name, user_name, node=None): with Scenario("ALTER ROLE without privilege"): alter_role_name = f"alter_role_{getuid()}" + with role(node, alter_role_name): - with When("I check the user can't alter a role"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't alter a role"): node.query(f"ALTER ROLE {alter_role_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) with Scenario("ALTER ROLE with privilege"): alter_role_name = f"alter_role_{getuid()}" + with role(node, alter_role_name): with When(f"I grant {privilege}"): @@ -93,6 +102,7 @@ def alter_role(self, privilege, grant_target_name, user_name, node=None): with Scenario("ALTER ROLE with revoked privilege"): alter_role_name = f"alter_role_{getuid()}" + with role(node, alter_role_name): with When(f"I grant {privilege} on the database"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -108,6 +118,8 @@ def alter_role(self, privilege, grant_target_name, user_name, node=None): @Name("alter role") @Requirements( RQ_SRS_006_RBAC_Privileges_AlterRole("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of ALTER ROLE. diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_row_policy.py b/tests/testflows/rbac/tests/privileges/alter/alter_row_policy.py index 6d13d30b823..a0d1e4271bc 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_row_policy.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_row_policy.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=alter_row_policy, flags=TE, + Suite(run=alter_row_policy, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in alter_row_policy.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=alter_row_policy, flags=TE, + Suite(run=alter_row_policy, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in alter_row_policy.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("ALTER ROW POLICY",), ("ALTER POLICY",), @@ -65,7 +66,13 @@ def alter_row_policy(self, privilege, grant_target_name, user_name, node=None): with Given("I have a row policy"): node.query(f"CREATE ROW POLICY {alter_row_policy_name} ON {table_name}") - with When("I check the user can't alter a row policy"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't alter a row policy"): node.query(f"ALTER ROW POLICY {alter_row_policy_name} ON {table_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -130,15 +137,986 @@ def alter_row_policy(self, privilege, grant_target_name, user_name, node=None): with Finally("I drop the row policy"): node.query(f"DROP ROW POLICY IF EXISTS {alter_row_policy_name} ON {table_name}") +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Restriction("1.0") +) +def no_grants(self, node=None): + """Check that user is unable to select from a table without a row policy + after a row policy has been altered to have a condition. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + with When("I alter the row policy to have a condition"): + node.query(f"ALTER POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Permissive("1.0"), +) +def permissive(self, node=None): + """Check that user is able to see from a table when they have a PERMISSIVE policy. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1), (2)") + + with When("I alter a row policy to be permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output and '2' not in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Restrictive("1.0") +) +def restrictive(self, node=None): + """Check that user is able to see values they have a RESTRICTIVE policy for. + """ + + table_name = f"table_{getuid()}" + perm_pol_name = f"perm_pol_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("I have a second row policy"): + row_policy(name=perm_pol_name, table=table_name) + + with And("I alter a row policy to be permissive"): + node.query(f"ALTER ROW POLICY {perm_pol_name} ON {table_name} FOR SELECT USING y=1 OR y=2 TO default") + + with And("I alter a row policy to be restrictive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} AS RESTRICTIVE FOR SELECT USING y=1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1), (2)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output and '2' not in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_ForSelect("1.0"), +) +def for_select(self, node=None): + """Check that user is able to see values allowed by the row policy condition in the FOR SELECT clause. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Given("I alter therow policy to use FOR SELECT"): + node.query(f"Alter ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1 TO default") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_Condition("1.0") +) +def condition(self, node=None): + """Check that user is able to see values allowed by the row policy condition. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with When("I alter a row policy to be permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_Condition_None("1.0") +) +def remove_condition(self, node=None): + """Check that user is able to see the table after row policy condition has been removed. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The row policy has a condition"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with When("I alter a row policy to not have a condition"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING NONE") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_IfExists("1.0") +) +def if_exists(self, node=None): + """Check that a row policy altered using IF EXISTS restricts rows as expected. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with When("I have alter a row policy to be permissive using IF EXISTS clause"): + node.query(f"ALTER ROW POLICY IF EXISTS {pol_name} ON {table_name} FOR SELECT USING 1 TO default") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_Rename("1.0") +) +def rename(self, node=None): + """Check that a row policy altered using RENAME restricts rows as expected. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + pol_new_name = f"pol_new_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with And("The row policy is permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with When("I have alter a row policy by renaming it"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} RENAME TO {pol_new_name}") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_new_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster("1.0") +) +def on_cluster(self, node=None): + """Check that a row policy altered using ON CLUSTER applies to the nodes of the cluster correctly. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy on a cluster on that table"): + node.query(f"CREATE ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("The table has some values on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with And("The table has some values on the second node"): + node2.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with When("I alter the row policy to have a condition"): + node.query(f"ALTER ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name} FOR SELECT USING 1") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + with And("I select from another node on the cluster"): + output = node2.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE {table_name} ON CLUSTER sharded_cluster") + +@TestScenario +def diff_policies_on_diff_nodes(self, node=None): + """Check that a row policy altered on a node, does not effect row policy on a different node. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy on the cluster"): + node.query(f"CREATE ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("The table has some values on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with And("The table has some values on the second node"): + node2.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with When("I alter the row policy on the first node"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + with And("I select from another node on the cluster"): + output = node2.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE {table_name} ON CLUSTER sharded_cluster") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment("1.0"), +) +def assignment(self, node=None): + """Check that user is able to see rows from a table when they have PERMISSIVE policy assigned to them. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The row policy is permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with When("I alter a row policy to be assigned to default"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} TO default") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_None("1.0"), +) +def assignment_none(self, node=None): + """Check that no one is affected when a row policy is altered to be assigned to NONE. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The row policy is permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with When("I alter a row policy to be assigned to NONE"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} TO NONE") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_All("1.0"), +) +def assignment_all(self, node=None): + """Check that everyone is effected with a row policy is altered to be assigned to ALL. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The row policy is permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with When("I alter a row policy to be assigned to ALL"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} TO ALL") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_AllExcept("1.0"), +) +def assignment_all_except(self, node=None): + """Check that everyone is except the specified user is effect by a row policy is altered to be assigned to ALL EXCEPT. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The row policy is permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with When("I alter a row policy to be assigned to ALL EXCEPT default"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} TO ALL EXCEPT default") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def nested_view(self, node=None): + """Check that if a user has a row policy on a table and a view is altered to use a condition on that table, + the user is only able to access the rows specified by the assigned policies. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + + try: + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with And("There is a view on the table"): + node.query(f"CREATE VIEW {view_name} AS SELECT * FROM {table_name}") + + with When("I alter the row policy to be permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def nested_live_view_before_policy(self, node=None): + """Check that if a live view exists on a table and then a row policy is created, + the user is only able to select rows specified by the assigned policies from the view. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I add allow_experimental_live_view to the default query settings"): + default_query_settings = getsattr(current().context, "default_query_settings", []) + default_query_settings.append(("allow_experimental_live_view", 1)) + + with And("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with And("There exists a live view on the table"): + node.query(f"CREATE LIVE VIEW {view_name} AS SELECT * FROM {table_name}") + + with When("I alter the row policy to be permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the live view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + + with And("I remove allow_experimental_live_view from the default query settings", flags=TE): + if default_query_settings: + try: + default_query_settings.pop(default_query_settings.index(("allow_experimental_live_view", 1))) + except ValueError: + pass + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def nested_live_view_after_policy(self, node=None): + """Check that if a user has a row policy on a table and a materialized view is created on that table, + the user is only able to select rows specified by the assigned policies from the view. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I add allow_experimental_live_view to the default query settings"): + default_query_settings = getsattr(current().context, "default_query_settings", []) + default_query_settings.append(("allow_experimental_live_view", 1)) + + with And("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with When("I alter the row policy to be permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with And("I create a live view on the table"): + node.query(f"CREATE LIVE VIEW {view_name} AS SELECT * FROM {table_name}") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the live view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + + with And("I remove allow_experimental_live_view from the default query settings", flags=TE): + if default_query_settings: + try: + default_query_settings.pop(default_query_settings.index(("allow_experimental_live_view", 1))) + except ValueError: + pass + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def nested_mat_view_before_policy(self, node=None): + """Check that if a materialized view exists on a table and then a row policy is created, + the user is only able to select rows specified by the assigned policies from the view. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("There exists a mat view on the table"): + node.query(f"CREATE MATERIALIZED VIEW {view_name} ENGINE = Memory AS SELECT * FROM {table_name}") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with When("I alter the row policy"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the materialized view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def nested_mat_view_after_policy(self, node=None): + """Check that if a user has a row policy on a table and a materialized view is created on that table, + the user is only able to select rows specified by the assigned policies from the view. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("I alter the row policy"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with When("I create a mat view on the table"): + node.query(f"CREATE MATERIALIZED VIEW {view_name} ENGINE = Memory AS SELECT * FROM {table_name}") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the materialized view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def populate_mat_view(self, node=None): + """Check that if a user has a row policy on a table and a materialized view is created using POPULATE from that table, + the user can only select the rows from the materialized view specified in the row policy. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("I alter a row policy on the table"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with When("I create a mat view populated by the table"): + node.query(f"CREATE MATERIALIZED VIEW {view_name} ENGINE = Memory POPULATE AS SELECT * FROM {table_name}") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the materialized view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def dist_table(self, node=None): + """Check that if a user has a row policy on a table and a distributed table is created on that table, + the user is only able to access the rows specified by the assigned policies. + """ + + table_name = f"table_{getuid()}" + dist_table_name = f"dist_table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I have a distributed table"): + node.query(f"CREATE TABLE {dist_table_name} (x UInt64) ENGINE = Distributed(sharded_cluster, default, {table_name}, rand())") + + with And("The table has some values on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with When("I alter the row policy to be permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} ON CLUSTER sharded_cluster FOR SELECT USING 1") + + with Then("I select from the distributed table"): + output = node.query(f"SELECT * FROM {dist_table_name}").output + assert '' == output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name} ON CLUSTER sharded_cluster") + + with And("I drop the distributed table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {dist_table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def dist_table_diff_policies_on_diff_nodes(self, node=None): + """Check that user is only able to select from the distributed table what is allowed by the row policies on each node. + """ + + table_name = f"table_{getuid()}" + dist_table_name = f"dist_table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I have a distributed table"): + node.query(f"CREATE TABLE {dist_table_name} (x UInt64) ENGINE = Distributed(sharded_cluster, default, {table_name}, rand())") + + with And("The table has some values on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with And("The table has some values on the second node"): + node2.query(f"INSERT INTO {table_name} (x) VALUES (2)") + + with When("I alter the row policy to be permissive on the first node"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with Then("I select from the distributed table"): + output = node.query(f"SELECT * FROM {dist_table_name}").output + assert '1' not in output and '2' in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name} ON CLUSTER sharded_cluster") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name} ON CLUSTER sharded_cluster") + + with And("I drop the distributed table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {dist_table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def dist_table_on_dist_table(self, node=None): + """Check that if a user has a row policy on a table and a distributed table is created on that table, + and another distributed table is created on top of that, + the user is only able to access rows on any of the tables specified by the assigned policies. + """ + table_name = f"table_{getuid()}" + dist_table_name = f"dist_table_{getuid()}" + dist_table_2_name = f"dist_table_2_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I have a distributed table on a cluster"): + node.query(f"CREATE TABLE {dist_table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Distributed(sharded_cluster, default, {table_name}, rand())") + + with And("I have a distributed table on the other distributed table"): + node.query(f"CREATE TABLE {dist_table_2_name} (x UInt64) ENGINE = Distributed(sharded_cluster, default, {dist_table_name}, rand())") + + with And("The table has some values on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with When("I alter the row policy to be permissive on the first node"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with Then("I select from the second distributed table"): + output = node.query(f"SELECT * FROM {dist_table_2_name}").output + assert '' == output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name} ON CLUSTER sharded_cluster") + + with And("I drop the distributed table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {dist_table_name} ON CLUSTER sharded_cluster") + + with And("I drop the outer distributed table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {dist_table_2_name}") + +@TestScenario +def policy_before_table(self, node=None): + """Check that if the policy is created and altered before the table, + then it is still applied correctly. + """ + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("I alter the row policy"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with table(node, table_name): + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1), (2)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output and '2' not in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0"), +) +def dict(self, node=None): + """Check that if a user has a row policy on a table and a dictionary is created on that table, + the user is only able to access the rows specified by the assigned policies. + """ + + table_name = f"table_{getuid()}" + dict_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + try: + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("I have a table"): + node.query(f"CREATE TABLE {table_name} (key UInt64, val UInt64 DEFAULT 5) ENGINE = Memory") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (key) VALUES (1),(2)") + + with And("I create a dict on the table"): + node.query(f"CREATE DICTIONARY {dict_name} (key UInt64 DEFAULT 0, val UInt64 DEFAULT 5) PRIMARY KEY key SOURCE(CLICKHOUSE(HOST 'localhost' PORT tcpPort() USER 'default' TABLE {table_name} PASSWORD '' DB 'default')) LIFETIME(MIN 0 MAX 0) LAYOUT(FLAT())") + + with When("I alter the row policy to be permissive"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING key=1 TO default") + + with Then("I try to select from the dict"): + output = node.query(f"SELECT * FROM {dict_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the materialized view", flags=TE): + node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name}") + + @TestFeature @Name("alter row policy") @Requirements( RQ_SRS_006_RBAC_Privileges_AlterRowPolicy("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of ALTER ROW POLICY. """ self.context.node = self.context.cluster.node(node) + self.context.node2 = self.context.cluster.node("clickhouse2") Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log) Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log) + + Scenario(run=no_grants, setup=instrument_clickhouse_server_log) + Scenario(run=permissive, setup=instrument_clickhouse_server_log) + Scenario(run=restrictive, setup=instrument_clickhouse_server_log) + Scenario(run=for_select, setup=instrument_clickhouse_server_log) + Scenario(run=condition, setup=instrument_clickhouse_server_log) + Scenario(run=remove_condition, setup=instrument_clickhouse_server_log) + Scenario(run=if_exists, setup=instrument_clickhouse_server_log) + Scenario(run=rename, setup=instrument_clickhouse_server_log) + Scenario(run=on_cluster, setup=instrument_clickhouse_server_log) + Scenario(run=assignment, setup=instrument_clickhouse_server_log) + Scenario(run=assignment_none, setup=instrument_clickhouse_server_log) + Scenario(run=assignment_all, setup=instrument_clickhouse_server_log) + Scenario(run=assignment_all_except, setup=instrument_clickhouse_server_log) + Scenario(run=nested_view, setup=instrument_clickhouse_server_log) + Scenario(run=nested_live_view_before_policy, setup=instrument_clickhouse_server_log) + Scenario(run=nested_live_view_after_policy, setup=instrument_clickhouse_server_log) + Scenario(run=nested_mat_view_before_policy, setup=instrument_clickhouse_server_log) + Scenario(run=nested_mat_view_after_policy, setup=instrument_clickhouse_server_log) + Scenario(run=populate_mat_view, setup=instrument_clickhouse_server_log) + Scenario(run=dist_table, setup=instrument_clickhouse_server_log) + Scenario(run=dist_table_on_dist_table, setup=instrument_clickhouse_server_log) + Scenario(run=dist_table_diff_policies_on_diff_nodes, setup=instrument_clickhouse_server_log) + Scenario(run=diff_policies_on_diff_nodes, setup=instrument_clickhouse_server_log) + Scenario(run=policy_before_table, setup=instrument_clickhouse_server_log) + Scenario(run=dict, setup=instrument_clickhouse_server_log) diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_settings.py b/tests/testflows/rbac/tests/privileges/alter/alter_settings.py index 6ac482fa33d..c2c2110ddf0 100755 --- a/tests/testflows/rbac/tests/privileges/alter/alter_settings.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_settings.py @@ -1,7 +1,5 @@ import json -from multiprocessing.dummy import Pool - from testflows.core import * from testflows.asserts import error @@ -10,7 +8,7 @@ from rbac.helper.common import * import rbac.helper.errors as errors from rbac.helper.tables import table_types -aliases = {"ALTER SETTINGS", "ALTER SETTING", "ALTER MODIFY SETTING", "MODIFY SETTING"} +aliases = {"ALTER SETTINGS", "ALTER SETTING", "ALTER MODIFY SETTING", "MODIFY SETTING", "ALL"} def check_alter_settings_when_privilege_is_granted(table, user, node): """Ensures ADD SETTINGS runs as expected when the privilege is granted to the specified user @@ -21,7 +19,7 @@ def check_alter_settings_when_privilege_is_granted(table, user, node): with And(f"I modify settings"): node.query(f"ALTER TABLE {table} MODIFY SETTING merge_with_ttl_timeout=5", - settings = [("user", user)]) + settings=[("user", user)]) with Then("I verify that the setting is in the table"): output = json.loads(node.query(f"SHOW CREATE TABLE {table} FORMAT JSONEachRow").output) @@ -30,10 +28,16 @@ def check_alter_settings_when_privilege_is_granted(table, user, node): def check_alter_settings_when_privilege_is_not_granted(table, user, node): """Ensures CLEAR SETTINGS runs as expected when the privilege is granted to the specified user """ - with When("I try to use ALTER SETTING, has not been granted"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {user}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {user}") + + with Then("I try to use ALTER SETTING, has not been granted"): exitcode, message = errors.not_enough_privileges(user) node.query(f"ALTER TABLE {table} MODIFY SETTING merge_with_ttl_timeout=5", - settings = [("user", user)], exitcode=exitcode, message=message) + settings=[("user", user)], exitcode=exitcode, message=message) @TestScenario def user_with_privileges(self, privilege, table_type, node=None): @@ -53,6 +57,7 @@ def user_with_privileges(self, privilege, table_type, node=None): with Then(f"I try to ALTER SETTINGS"): check_alter_settings_when_privilege_is_granted(table_name, user_name, node) + @TestScenario @Requirements( RQ_SRS_006_RBAC_Privileges_AlterSettings_Revoke("1.0"), @@ -180,7 +185,9 @@ def scenario_parallelization(self, table_type, privilege): @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AlterSettings("1.0"), - RQ_SRS_006_RBAC_Privileges_AlterSettings_TableEngines("1.0") + RQ_SRS_006_RBAC_Privileges_AlterSettings_TableEngines("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() @@ -208,7 +215,9 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): tasks = [] try: for alias in aliases: - run_scenario(pool, tasks, Suite(test=scenario_parallelization, name=alias, setup=instrument_clickhouse_server_log), {"table_type": table_type, "privilege": alias}) + run_scenario(pool, tasks, Suite(test=scenario_parallelization, name=alias, + setup=instrument_clickhouse_server_log), + {"table_type": table_type, "privilege": alias}) finally: join(tasks) finally: diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_settings_profile.py b/tests/testflows/rbac/tests/privileges/alter/alter_settings_profile.py index 9212b745544..cd4648305f7 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_settings_profile.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_settings_profile.py @@ -31,7 +31,7 @@ def alter_settings_profile_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=alter_settings_profile, flags=TE, + Suite(run=alter_settings_profile, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in alter_settings_profile.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -52,13 +52,14 @@ def alter_settings_profile_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=alter_settings_profile, flags=TE, + Suite(run=alter_settings_profile, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in alter_settings_profile.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("ALTER SETTINGS PROFILE",), ("ALTER PROFILE",), @@ -76,7 +77,13 @@ def alter_settings_profile(self, privilege, grant_target_name, user_name, node=N with settings_profile(node, alter_settings_profile_name): - with When("I check the user can't alter a settings_profile"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't alter a settings_profile"): node.query(f"ALTER SETTINGS PROFILE {alter_settings_profile_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -128,6 +135,8 @@ def alter_settings_profile(self, privilege, grant_target_name, user_name, node=N @Name("alter settings profile") @Requirements( RQ_SRS_006_RBAC_Privileges_AlterSettingsProfile("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of ALTER SETTINGS PROFILE. diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_ttl.py b/tests/testflows/rbac/tests/privileges/alter/alter_ttl.py index 00240f19bb4..8fa7136076e 100755 --- a/tests/testflows/rbac/tests/privileges/alter/alter_ttl.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_ttl.py @@ -16,7 +16,7 @@ subprivileges = { aliases = { "TTL" : ["ALTER TTL", "ALTER MODIFY TTL", "MODIFY TTL"], - "MATERIALIZE TTL": ["ALTER MATERIALIZE TTL", "MATERIALIZE TTL"], + "MATERIALIZE TTL": ["ALTER MATERIALIZE TTL", "MATERIALIZE TTL", "ALL"], } permutation_count = (1 << len(subprivileges)) @@ -250,7 +250,9 @@ def user_with_privileges_on_cluster(self, table_type, node=None): @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AlterTTL("1.0"), - RQ_SRS_006_RBAC_Privileges_AlterTTL_TableEngines("1.0") + RQ_SRS_006_RBAC_Privileges_AlterTTL_TableEngines("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_update.py b/tests/testflows/rbac/tests/privileges/alter/alter_update.py index 3b3e3990497..d205740b901 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_update.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_update.py @@ -7,7 +7,7 @@ from rbac.requirements import * from rbac.helper.common import * import rbac.helper.errors as errors -aliases = {"ALTER UPDATE", "UPDATE"} +aliases = {"ALTER UPDATE", "UPDATE", "ALL"} @TestSuite def privilege_granted_directly_or_via_role(self, table_type, privilege, node=None): @@ -38,26 +38,41 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No with Scenario("user without privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): - with When("I attempt to update a column without privilege"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to update a column without privilege"): node.query(f"ALTER TABLE {table_name} UPDATE a = x WHERE 1", settings = [("user", user_name)], exitcode=exitcode, message=message) with Scenario("user with privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): + with When("I grant the update privilege"): node.query(f"GRANT {privilege} ON {table_name} TO {grant_target_name}") + with Then("I attempt to update a column"): node.query(f"ALTER TABLE {table_name} UPDATE a = x WHERE 1", settings = [("user", user_name)]) with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): table_name = f"merge_tree_{getuid()}" + with table(node, table_name, table_type): + with When("I grant the update privilege"): node.query(f"GRANT {privilege} ON {table_name} TO {grant_target_name}") + with And("I revoke the update privilege"): node.query(f"REVOKE {privilege} ON {table_name} FROM {grant_target_name}") + with Then("I attempt to update a column"): node.query(f"ALTER TABLE {table_name} UPDATE a = x WHERE 1", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -65,7 +80,9 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AlterUpdate("1.0"), - RQ_SRS_006_RBAC_Privileges_AlterUpdate_TableEngines("1.0") + RQ_SRS_006_RBAC_Privileges_AlterUpdate_TableEngines("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() diff --git a/tests/testflows/rbac/tests/privileges/alter/alter_user.py b/tests/testflows/rbac/tests/privileges/alter/alter_user.py index 2531f4a3451..bcf3014c9be 100644 --- a/tests/testflows/rbac/tests/privileges/alter/alter_user.py +++ b/tests/testflows/rbac/tests/privileges/alter/alter_user.py @@ -17,7 +17,7 @@ def alter_user_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=alter_user, flags=TE, + Suite(run=alter_user, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in alter_user.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def alter_user_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=alter_user, flags=TE, + Suite(run=alter_user, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in alter_user.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("ALTER USER",), ]) @@ -61,7 +62,13 @@ def alter_user(self, privilege, grant_target_name, user_name, node=None): alter_user_name = f"alter_user_{getuid()}" with user(node, alter_user_name): - with When("I check the user can't alter a user"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't alter a user"): node.query(f"ALTER USER {alter_user_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -108,6 +115,8 @@ def alter_user(self, privilege, grant_target_name, user_name, node=None): @Name("alter user") @Requirements( RQ_SRS_006_RBAC_Privileges_AlterUser("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of ALTER USER. diff --git a/tests/testflows/rbac/tests/privileges/attach/attach_database.py b/tests/testflows/rbac/tests/privileges/attach/attach_database.py index 0f1a9a07975..3fecbe2571f 100644 --- a/tests/testflows/rbac/tests/privileges/attach/attach_database.py +++ b/tests/testflows/rbac/tests/privileges/attach/attach_database.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute CREATE DATABASE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,11 +32,17 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): db_name = f"db_{getuid()}" try: - with When("I attempt to attach a database without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to attach a database without privilege"): node.query(f"ATTACH DATABASE {db_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -44,14 +50,14 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the database"): node.query(f"DROP DATABASE IF EXISTS {db_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): db_name = f"db_{getuid()}" try: with When("I grant create database privilege"): node.query(f"GRANT CREATE DATABASE ON {db_name}.* TO {grant_target_name}") - with Then("I attempt to attach aa database"): + with Then("I attempt to attach a database"): node.query(f"ATTACH DATABASE {db_name}", settings = [("user", user_name)], exitcode=80, message="DB::Exception: Received from localhost:9000. DB::Exception: Database engine must be specified for ATTACH DATABASE query") @@ -59,7 +65,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the database"): node.query(f"DROP DATABASE IF EXISTS {db_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): db_name = f"db_{getuid()}" try: @@ -77,9 +83,44 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the database"): node.query(f"DROP DATABASE IF EXISTS {db_name}") + with Scenario("user with revoked ALL privilege"): + db_name = f"db_{getuid()}" + + try: + with When("I grant the create database privilege"): + node.query(f"GRANT CREATE DATABASE ON {db_name}.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to attach a database"): + node.query(f"ATTACH DATABASE {db_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the database"): + node.query(f"DROP DATABASE IF EXISTS {db_name}") + + with Scenario("user with ALL privilege"): + db_name = f"db_{getuid()}" + + try: + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to attach a database"): + node.query(f"ATTACH DATABASE {db_name}", settings = [("user", user_name)], + exitcode=80, message="DB::Exception: Received from localhost:9000. DB::Exception: Database engine must be specified for ATTACH DATABASE query") + + finally: + with Finally("I drop the database"): + node.query(f"DROP DATABASE IF EXISTS {db_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AttachDatabase("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("attach database") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -92,5 +133,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/attach/attach_dictionary.py b/tests/testflows/rbac/tests/privileges/attach/attach_dictionary.py index 62ff70ac75a..390a7f03aba 100644 --- a/tests/testflows/rbac/tests/privileges/attach/attach_dictionary.py +++ b/tests/testflows/rbac/tests/privileges/attach/attach_dictionary.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute CREATE DICTIONARY with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,11 +32,17 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): dict_name = f"dict_{getuid()}" try: - with When("I attempt to attach a dictionary without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to attach a dictionary without privilege"): node.query(f"ATTACH DICTIONARY {dict_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -44,7 +50,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the dictionary"): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): dict_name = f"dict_{getuid()}" try: @@ -59,7 +65,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the dictionary"): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): dict_name = f"dict_{getuid()}" try: @@ -77,9 +83,44 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the dictionary"): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + with Scenario("user with revoked ALL privilege"): + db_name = f"db_{getuid()}" + + try: + with When("I grant the create database privilege"): + node.query(f"GRANT CREATE DATABASE ON {db_name}.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to attach a database"): + node.query(f"ATTACH DATABASE {db_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the database"): + node.query(f"DROP DATABASE IF EXISTS {db_name}") + + with Scenario("user with ALL privilege"): + dict_name = f"dict_{getuid()}" + + try: + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to attach a dictionary"): + node.query(f"ATTACH DICTIONARY {dict_name}", settings = [("user", user_name)], + exitcode=231, message=f"DB::Exception: Dictionary `{dict_name}` doesn't exist.") + + finally: + with Finally("I drop the dictionary"): + node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AttachDictionary("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("attach dictionary") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -92,5 +133,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/attach/attach_table.py b/tests/testflows/rbac/tests/privileges/attach/attach_table.py index 55c9efd369c..411140506ea 100644 --- a/tests/testflows/rbac/tests/privileges/attach/attach_table.py +++ b/tests/testflows/rbac/tests/privileges/attach/attach_table.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute CREATE TABLE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,12 +32,17 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): table_name = f"table_{getuid()}" try: + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") - with When("I attempt to attach a table without privilege"): + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to attach a table without privilege"): node.query(f"ATTACH TABLE {table_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -45,7 +50,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the table"): node.query(f"DROP TABLE IF EXISTS {table_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): table_name = f"table_{getuid()}" try: @@ -60,7 +65,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the table"): node.query(f"DROP TABLE IF EXISTS {table_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): table_name = f"table_{getuid()}" try: @@ -78,9 +83,44 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the table"): node.query(f"DROP TABLE IF EXISTS {table_name}") + with Scenario("user with revoked ALL privilege"): + table_name = f"table_{getuid()}" + + try: + with When("I grant the create table privilege"): + node.query(f"GRANT CREATE TABLE ON *.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to attach a table"): + node.query(f"ATTACH TABLE {table_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the table"): + node.query(f"DROP TABLE IF EXISTS {table_name}") + + with Scenario("user with ALL privilege"): + table_name = f"table_{getuid()}" + + try: + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to attach a table"): + node.query(f"ATTACH TABLE {table_name}", settings = [("user", user_name)], + exitcode=134, message=f"DB::Exception: Table `{table_name}` doesn't exist.") + + finally: + with Finally("I drop the table"): + node.query(f"DROP TABLE IF EXISTS {table_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AttachTable("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("attach table") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -93,5 +133,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/attach/attach_temp_table.py b/tests/testflows/rbac/tests/privileges/attach/attach_temp_table.py index fad47e71967..2662a24d5a2 100644 --- a/tests/testflows/rbac/tests/privileges/attach/attach_temp_table.py +++ b/tests/testflows/rbac/tests/privileges/attach/attach_temp_table.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute CREATE TEMPORARY TABLE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,10 +32,16 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): temp_table_name = f"temp_table_{getuid()}" try: + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + with When("I attempt to attach a temporary table without privilege"): node.query(f"ATTACH TEMPORARY TABLE {temp_table_name} (x Int8)", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -44,12 +50,13 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the temporary table"): node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): temp_table_name = f"temp_table_{getuid()}" try: with When("I grant create temporary table privilege"): node.query(f"GRANT CREATE TEMPORARY TABLE ON *.* TO {grant_target_name}") + with Then("I attempt to attach a temporary table"): node.query(f"ATTACH TEMPORARY TABLE {temp_table_name} (x Int8)", settings = [("user", user_name)]) @@ -57,7 +64,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the temporary table"): node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): temp_table_name = f"temp_table_{getuid()}" try: @@ -75,9 +82,43 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the temporary table"): node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") + with Scenario("user with revoked ALL privilege"): + temp_table_name = f"temp_table_{getuid()}" + + try: + with When("I grant the create temporary table privilege"): + node.query(f"GRANT CREATE TEMPORARY TABLE ON *.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to attach a temporary table"): + node.query(f"ATTACH TEMPORARY TABLE {temp_table_name} (x Int8)", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the temporary table"): + node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") + + with Scenario("user with ALL privilege"): + temp_table_name = f"temp_table_{getuid()}" + + try: + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to attach a temporary table"): + node.query(f"ATTACH TEMPORARY TABLE {temp_table_name} (x Int8)", settings = [("user", user_name)]) + + finally: + with Finally("I drop the temporary table"): + node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_AttachTemporaryTable("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("attach temporary table") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -90,5 +131,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/create/create_database.py b/tests/testflows/rbac/tests/privileges/create/create_database.py index deefe4b4ce8..8367d49e050 100644 --- a/tests/testflows/rbac/tests/privileges/create/create_database.py +++ b/tests/testflows/rbac/tests/privileges/create/create_database.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute CREATE DATABASE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,11 +32,17 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): db_name = f"db_{getuid()}" try: - with When("I attempt to create a database without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to create a database without privilege"): node.query(f"CREATE DATABASE {db_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -44,7 +50,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the database"): node.query(f"DROP DATABASE IF EXISTS {db_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): db_name = f"db_{getuid()}" try: @@ -58,7 +64,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the database"): node.query(f"DROP DATABASE IF EXISTS {db_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): db_name = f"db_{getuid()}" try: @@ -76,9 +82,43 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the database"): node.query(f"DROP DATABASE IF EXISTS {db_name}") + with Scenario("user with revoked ALL privilege"): + db_name = f"db_{getuid()}" + + try: + with When("I grant the create database privilege"): + node.query(f"GRANT CREATE DATABASE ON {db_name}.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to create a database"): + node.query(f"CREATE DATABASE {db_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the database"): + node.query(f"DROP DATABASE IF EXISTS {db_name}") + + with Scenario("user with ALL privilege"): + db_name = f"db_{getuid()}" + + try: + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to create a database"): + node.query(f"CREATE DATABASE {db_name}", settings = [("user", user_name)]) + + finally: + with Finally("I drop the database"): + node.query(f"DROP DATABASE IF EXISTS {db_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_CreateDatabase("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("create database") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -91,5 +131,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/create/create_dictionary.py b/tests/testflows/rbac/tests/privileges/create/create_dictionary.py index 0dbc3e1f6bb..73734f5d556 100644 --- a/tests/testflows/rbac/tests/privileges/create/create_dictionary.py +++ b/tests/testflows/rbac/tests/privileges/create/create_dictionary.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute CREATE DICTIONARY with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,11 +32,17 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): dict_name = f"dict_{getuid()}" try: - with When("I attempt to create a dictionary without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to create a dictionary without privilege"): node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -44,7 +50,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the dictionary"): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): dict_name = f"dict_{getuid()}" try: @@ -58,7 +64,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the dictionary"): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): dict_name = f"dict_{getuid()}" try: @@ -76,9 +82,44 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the dictionary"): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + + with Scenario("user with revoked ALL privilege"): + dict_name = f"dict_{getuid()}" + + try: + with When("I grant the create dictionary privilege"): + node.query(f"GRANT CREATE DICTIONARY ON {dict_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to create a dictionary"): + node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the dictionary"): + node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + + with Scenario("user with ALL privilege"): + dict_name = f"dict_{getuid()}" + + try: + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to create a dictionary"): + node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)", settings = [("user", user_name)]) + + finally: + with Finally("I drop the dictionary"): + node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_CreateDictionary("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("create dictionary") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -91,5 +132,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/create/create_quota.py b/tests/testflows/rbac/tests/privileges/create/create_quota.py index e7f4f4d5f7c..d6e50ea904e 100644 --- a/tests/testflows/rbac/tests/privileges/create/create_quota.py +++ b/tests/testflows/rbac/tests/privileges/create/create_quota.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=create_quota, flags=TE, + Suite(run=create_quota, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in create_quota.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=create_quota, flags=TE, + Suite(run=create_quota, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in create_quota.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("CREATE QUOTA",), ]) @@ -60,7 +61,13 @@ def create_quota(self, privilege, grant_target_name, user_name, node=None): create_quota_name = f"create_quota_{getuid()}" try: - with When("I check the user can't create a quota"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't create a quota"): node.query(f"CREATE QUOTA {create_quota_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -118,6 +125,8 @@ def create_quota(self, privilege, grant_target_name, user_name, node=None): @Name("create quota") @Requirements( RQ_SRS_006_RBAC_Privileges_CreateQuota("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of CREATE QUOTA. diff --git a/tests/testflows/rbac/tests/privileges/create/create_role.py b/tests/testflows/rbac/tests/privileges/create/create_role.py index 9d8af913893..c442036b625 100644 --- a/tests/testflows/rbac/tests/privileges/create/create_role.py +++ b/tests/testflows/rbac/tests/privileges/create/create_role.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=create_role, flags=TE, + Suite(run=create_role, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in create_role.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=create_role, flags=TE, + Suite(run=create_role, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in create_role.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("CREATE ROLE",), ]) @@ -60,7 +61,13 @@ def create_role(self, privilege, grant_target_name, user_name, node=None): create_role_name = f"create_role_{getuid()}" try: - with When("I check the user can't create a role"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't create a role"): node.query(f"CREATE ROLE {create_role_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -118,6 +125,8 @@ def create_role(self, privilege, grant_target_name, user_name, node=None): @Name("create role") @Requirements( RQ_SRS_006_RBAC_Privileges_CreateRole("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of CREATE ROLE. diff --git a/tests/testflows/rbac/tests/privileges/create/create_row_policy.py b/tests/testflows/rbac/tests/privileges/create/create_row_policy.py index 040cc631cc3..8e670333492 100644 --- a/tests/testflows/rbac/tests/privileges/create/create_row_policy.py +++ b/tests/testflows/rbac/tests/privileges/create/create_row_policy.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=create_row_policy, flags=TE, + Suite(run=create_row_policy, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in create_row_policy.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=create_row_policy, flags=TE, + Suite(run=create_row_policy, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in create_row_policy.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("CREATE ROW POLICY",), ("CREATE POLICY",), @@ -62,7 +63,13 @@ def create_row_policy(self, privilege, grant_target_name, user_name, node=None): table_name = f"table_name_{getuid()}" try: - with When("I check the user can't create a row policy"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't create a row policy"): node.query(f"CREATE ROW POLICY {create_row_policy_name} ON {table_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -119,15 +126,962 @@ def create_row_policy(self, privilege, grant_target_name, user_name, node=None): with Finally("I drop the row policy"): node.query(f"DROP ROW POLICY IF EXISTS {create_row_policy_name} ON {table_name}") +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Restriction("1.0") +) +def no_grants(self, node=None): + """Check that user is unable to select from a table without a row policy + after a row policy with a condition has been created on that table. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name}") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + with When("I create a row policy with a condition"): + node.query(f"CREATE ROW POLICY OR REPLACE {pol_name} ON {table_name} FOR SELECT USING 1") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_Access_Permissive("1.0"), +) +def permissive(self, node=None): + """Check that user is able to see from a table when they have a PERMISSIVE policy. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1), (2)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_Access_Restrictive("1.0") +) +def restrictive(self, node=None): + """Check that user is able to see values they have a RESTRICTIVE policy for. + """ + + table_name = f"table_{getuid()}" + perm_pol_name = f"perm_pol_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a permissive row policy"): + node.query(f"CREATE ROW POLICY {perm_pol_name} ON {table_name} FOR SELECT USING y=1 OR y=2 TO default") + + with And("I have a restrictive row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS RESTRICTIVE FOR SELECT USING y=1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1), (2)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the restrictive row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + + with And("I drop the permissive row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {perm_pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_ForSelect("1.0"), +) +def for_select(self, node=None): + """Check that user is able to see values allowed by the row policy condition in the FOR SELECT clause. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a restrictive row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_Condition("1.0") +) +def condition(self, node=None): + """Check that user is able to see values allowed by the row policy condition. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a restrictive row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_IfNotExists("1.0") +) +def if_not_exists(self, node=None): + """Check that a row policy created using IF NOT EXISTS does not replace a row policy with the same name. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + with When("I create another row policy with the same name using IF NOT EXISTS"): + node.query(f"CREATE ROW POLICY IF NOT EXISTS {pol_name} ON {table_name}") + + with Then("I select from the table again"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_Replace("1.0") +) +def or_replace(self, node=None): + """Check that a row policy created using OR REPLACE does replace the row policy with the same name. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + with When("I create another row policy with the same name using OR REPLACE"): + node.query(f"CREATE ROW POLICY OR REPLACE {pol_name} ON {table_name} AS RESTRICTIVE FOR SELECT USING 1 TO default") + + with Then("I can no longer select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert output == '', error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster("1.0") +) +def on_cluster(self, node=None): + """Check that a row policy created using ON CLUSTER applies to the nodes of the cluster correctly. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name} FOR SELECT USING 1") + + with When("I insert some values into the table on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with And("I insert some values into the table on the second node"): + node2.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + with And("I select from another node on the cluster"): + output = node2.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE {table_name} ON CLUSTER sharded_cluster") + +@TestScenario +def diff_policies_on_diff_nodes(self, node=None): + """Check that a row policy created on a node, does not effect a different node. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy on one node"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with When("I insert some values into the table on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with And("I insert some values into the table on the second node"): + node2.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + with And("I select from another node on the cluster"): + output = node2.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE {table_name} ON CLUSTER sharded_cluster") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_Assignment("1.0"), +) +def assignment(self, node=None): + """Check that user is able to see rows from a table when they have PERMISSIVE policy assigned to them. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_None("1.0"), +) +def assignment_none(self, node=None): + """Check that no one is affected when a row policy is assigned to NONE. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO NONE") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_All("1.0"), +) +def assignment_all(self, node=None): + """Check that everyone is effected with a row policy is assigned to ALL. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO ALL") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_AllExcept("1.0"), +) +def assignment_all_except(self, node=None): + """Check that everyone is except the specified user is effect by a row policy assigned to ALL EXCEPT. + """ + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO ALL EXCEPT default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0"), +) +def nested_view(self, node=None): + """Check that if a user has a row policy on a table and a view is created on that table, + the user is only able to select rows specified by the assigned policies from the view. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with And("I create a view on the table"): + node.query(f"CREATE VIEW {view_name} AS SELECT * FROM {table_name}") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + + with And("I drop the view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0"), +) +def nested_live_view_after_policy(self, node=None): + """Check that if a user has a row policy on a table and a live view is created on that table, + the user is only able to select rows specified by the assigned policies from the view. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I add allow_experimental_live_view to the default query settings"): + default_query_settings = getsattr(current().context, "default_query_settings", []) + default_query_settings.append(("allow_experimental_live_view", 1)) + + with And("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with And("I create a live view on the table"): + node.query(f"CREATE LIVE VIEW {view_name} AS SELECT * FROM {table_name}") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + + with And("I drop the live view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + + with And("I remove allow_experimental_live_view from the default query settings", flags=TE): + if default_query_settings: + try: + default_query_settings.pop(default_query_settings.index(("allow_experimental_live_view", 1))) + except ValueError: + pass + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0"), +) +def nested_live_view_before_policy(self, node=None): + """Check that if a live view exists on a table and then a row policy is created, + the user is only able to select rows specified by the assigned policies from the view. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I add allow_experimental_live_view to the default query settings"): + default_query_settings = getsattr(current().context, "default_query_settings", []) + default_query_settings.append(("allow_experimental_live_view", 1)) + + with And("There is a live view on the table"): + node.query(f"CREATE LIVE VIEW {view_name} AS SELECT * FROM {table_name}") + + with And("There is a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with When("I insert values into the table"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + + with And("I drop the live view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + + with And("I remove allow_experimental_live_view from the default query settings", flags=TE): + if default_query_settings: + try: + default_query_settings.pop(default_query_settings.index(("allow_experimental_live_view", 1))) + except ValueError: + pass + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0"), +) +def nested_mat_view_after_policy(self, node=None): + """Check that if a user has a row policy on a table and a materialized view is created on that table, + the user is only able to select rows specified by the assigned policies from the view. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with When("I create a view on the table"): + node.query(f"CREATE MATERIALIZED VIEW {view_name} ENGINE = Memory AS SELECT * FROM {table_name}") + + with And("I insert some values on the table"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + + with And("I drop the materialized view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0"), +) +def nested_mat_view_before_policy(self, node=None): + """Check that if a materialized view exists on a table and then a row policy is created, + the user is only able to select rows specified by the assigned policies from the view. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a view on the table"): + node.query(f"CREATE MATERIALIZED VIEW {view_name} ENGINE = Memory AS SELECT * FROM {table_name}") + + with And("I have some values on the table"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with When("I create a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + + with And("I drop the materialized view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + +@TestScenario +def populate_mat_view(self, node=None): + """Check that if a user has a row policy on a table and a materialized view is created using POPULATE from that table, + the user can only select the rows from the materialized view specified in the row policy. + """ + + table_name = f"table_{getuid()}" + view_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name): + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with When("I create a mat view with POPULATE from the table"): + node.query(f"CREATE MATERIALIZED VIEW {view_name} ENGINE = Memory POPULATE AS SELECT * FROM {table_name}") + + with Then("I try to select from the view"): + output = node.query(f"SELECT * FROM {view_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + + with And("I drop the materialized view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def dist_table(self, node=None): + """Check that if a user has a row policy on a table and a distributed table is created on that table, + the user is only able to select rows specified by the assigned policies from the distributed table. + """ + + table_name = f"table_{getuid()}" + dist_table_name = f"dist_table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name} FOR SELECT USING 1") + + with And("I have a distributed table"): + node.query(f"CREATE TABLE {dist_table_name} (x UInt64) ENGINE = Distributed(sharded_cluster, default, {table_name}, rand())") + + with When("I insert some values into the table on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {dist_table_name}").output + assert '' == output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name} ON CLUSTER sharded_cluster") + + with And("I drop the distributed table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {dist_table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def dist_table_diff_policies_on_diff_nodes(self, node=None): + """Check that the user can only access the rows of the distributed table that are allowed + by row policies on the the source tables. The row policies are different on different nodes. + """ + + table_name = f"table_{getuid()}" + dist_table_name = f"dist_table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with And("I have a distributed table"): + node.query(f"CREATE TABLE {dist_table_name} (x UInt64) ENGINE = Distributed(sharded_cluster, default, {table_name}, rand())") + + with When("I insert some values into the table on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with And("I insert some values into the table on the second node"): + node2.query(f"INSERT INTO {table_name} (x) VALUES (2)") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {dist_table_name}").output + assert '2' in output and '1' not in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name} ON CLUSTER sharded_cluster") + + with And("I drop the distributed table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {dist_table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0") +) +def dist_table_on_dist_table(self, node=None): + """Check that if a user has a row policy on a table and a distributed table is created on that table, + and another distributed table is created on top of that, + the user is only able to access rows on any of the tables specified by the assigned policies. + """ + table_name = f"table_{getuid()}" + dist_table_name = f"dist_table_{getuid()}" + dist_table_2_name = f"dist_table_2_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + node2 = self.context.node2 + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name} FOR SELECT USING 1") + + with And("I have a distributed table on a cluster"): + node.query(f"CREATE TABLE {dist_table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Distributed(sharded_cluster, default, {table_name}, rand())") + + with And("I have a distributed table on the other distributed table"): + node.query(f"CREATE TABLE {dist_table_2_name} (x UInt64) ENGINE = Distributed(sharded_cluster, default, {dist_table_name}, rand())") + + with When("I insert some values into the table on the first node"): + node.query(f"INSERT INTO {dist_table_2_name} (x) VALUES (1)") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {dist_table_2_name}").output + assert '' == output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name} ON CLUSTER sharded_cluster") + + with And("I drop the distributed table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {dist_table_name} ON CLUSTER sharded_cluster") + + with And("I drop the outer distributed table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {dist_table_2_name}") + +@TestScenario +def no_table(self, node=None): + """Check that row policy is not created when the table is not specified. + """ + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + with When("I try to create a row policy without a table"): + node.query(f"CREATE ROW POLICY {pol_name}", + exitcode=62, message='Exception: Syntax error') + + with And("I try to create a row policy on a database"): + node.query(f"CREATE ROW POLICY {pol_name} ON default.*", + exitcode=62, message='Exception: Syntax error') + +@TestScenario +def policy_before_table(self, node=None): + """Check that if the policy is created before the table, + then it is still applied correctly. + """ + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING y=1 TO default") + + with table(node, table_name): + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1), (2)") + + with Then("I try to select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the row policy"): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Nesting("1.0"), +) +def dict(self, node=None): + """Check that if a user has a row policy on a table and a dictionary is created on that table, + the user is only able to select rows specified by the assigned policies from the dict. + """ + + table_name = f"table_{getuid()}" + dict_name = f"view_{getuid()}" + pol_name = f"pol_{getuid()}" + + if node is None: + node = self.context.node + + try: + with Given("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON {table_name} AS PERMISSIVE FOR SELECT USING key=1 TO default") + + with And("I have a table"): + node.query(f"CREATE TABLE {table_name} (key UInt64, val UInt64 DEFAULT 5) ENGINE = Memory") + + with When("The table has some values"): + node.query(f"INSERT INTO {table_name} (key) VALUES (1),(2)") + + with And("I create a dict on the table"): + node.query(f"CREATE DICTIONARY {dict_name} (key UInt64 DEFAULT 0, val UInt64 DEFAULT 5) PRIMARY KEY key SOURCE(CLICKHOUSE(HOST 'localhost' PORT tcpPort() USER 'default' TABLE {table_name} PASSWORD '' DB 'default')) LIFETIME(MIN 0 MAX 0) LAYOUT(FLAT())") + + with Then("I try to select from the dict"): + output = node.query(f"SELECT * FROM {dict_name}").output + assert '1' in output and '2' not in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON {table_name}") + + with And("I drop the materialized view", flags=TE): + node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name}") + @TestFeature @Name("create row policy") @Requirements( RQ_SRS_006_RBAC_Privileges_CreateRowPolicy("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of CREATE ROW POLICY. """ self.context.node = self.context.cluster.node(node) + self.context.node2 = self.context.cluster.node("clickhouse2") Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log) Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log) + + Scenario(run=no_grants, setup=instrument_clickhouse_server_log) + Scenario(run=permissive, setup=instrument_clickhouse_server_log) + Scenario(run=restrictive, setup=instrument_clickhouse_server_log) + Scenario(run=for_select, setup=instrument_clickhouse_server_log) + Scenario(run=condition, setup=instrument_clickhouse_server_log) + Scenario(run=if_not_exists, setup=instrument_clickhouse_server_log) + Scenario(run=or_replace, setup=instrument_clickhouse_server_log) + Scenario(run=on_cluster, setup=instrument_clickhouse_server_log) + Scenario(run=assignment, setup=instrument_clickhouse_server_log) + Scenario(run=assignment_none, setup=instrument_clickhouse_server_log) + Scenario(run=assignment_all, setup=instrument_clickhouse_server_log) + Scenario(run=assignment_all_except, setup=instrument_clickhouse_server_log) + Scenario(run=nested_view, setup=instrument_clickhouse_server_log) + Scenario(run=nested_live_view_before_policy, setup=instrument_clickhouse_server_log) + Scenario(run=nested_live_view_after_policy, setup=instrument_clickhouse_server_log) + Scenario(run=nested_mat_view_before_policy, setup=instrument_clickhouse_server_log) + Scenario(run=nested_mat_view_after_policy, setup=instrument_clickhouse_server_log) + Scenario(run=populate_mat_view, setup=instrument_clickhouse_server_log) + Scenario(run=dist_table, setup=instrument_clickhouse_server_log) + Scenario(run=dist_table_on_dist_table, setup=instrument_clickhouse_server_log) + Scenario(run=dist_table_diff_policies_on_diff_nodes, setup=instrument_clickhouse_server_log) + Scenario(run=diff_policies_on_diff_nodes, setup=instrument_clickhouse_server_log) + Scenario(run=no_table, setup=instrument_clickhouse_server_log) + Scenario(run=policy_before_table, setup=instrument_clickhouse_server_log) + Scenario(run=dict, setup=instrument_clickhouse_server_log) diff --git a/tests/testflows/rbac/tests/privileges/create/create_settings_profile.py b/tests/testflows/rbac/tests/privileges/create/create_settings_profile.py index 8b206564647..938de560391 100644 --- a/tests/testflows/rbac/tests/privileges/create/create_settings_profile.py +++ b/tests/testflows/rbac/tests/privileges/create/create_settings_profile.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=create_settings_profile, flags=TE, + Suite(run=create_settings_profile, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in create_settings_profile.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=create_settings_profile, flags=TE, + Suite(run=create_settings_profile, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in create_settings_profile.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("CREATE SETTINGS PROFILE",), ("CREATE PROFILE",), @@ -61,7 +62,13 @@ def create_settings_profile(self, privilege, grant_target_name, user_name, node= create_settings_profile_name = f"create_settings_profile_{getuid()}" try: - with When("I check the user can't create a settings_profile"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't create a settings_profile"): node.query(f"CREATE SETTINGS PROFILE {create_settings_profile_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -119,6 +126,8 @@ def create_settings_profile(self, privilege, grant_target_name, user_name, node= @Name("create settings profile") @Requirements( RQ_SRS_006_RBAC_Privileges_CreateSettingsProfile("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of CREATE SETTINGS PROFILE. diff --git a/tests/testflows/rbac/tests/privileges/create/create_table.py b/tests/testflows/rbac/tests/privileges/create/create_table.py index 919e683f0f1..88d055f2915 100644 --- a/tests/testflows/rbac/tests/privileges/create/create_table.py +++ b/tests/testflows/rbac/tests/privileges/create/create_table.py @@ -6,6 +6,9 @@ from rbac.helper.common import * import rbac.helper.errors as errors @TestScenario +@Requirements( + RQ_SRS_006_RBAC_Privileges_None("1.0") +) def create_without_create_table_privilege(self, node=None): """Check that user is unable to create a table without CREATE TABLE privilege. """ @@ -21,7 +24,13 @@ def create_without_create_table_privilege(self, node=None): with Given("I don't have a table"): node.query(f"DROP TABLE IF EXISTS {table_name}") - with When("I try to create a table without CREATE TABLE privilege as the user"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {user_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {user_name}") + + with Then("I try to create a table without CREATE TABLE privilege as the user"): node.query(f"CREATE TABLE {table_name} (x Int8) ENGINE = Memory", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) @@ -74,6 +83,54 @@ def create_with_create_table_privilege(self, grant_target_name, user_name, node= with Then("I drop the table"): node.query(f"DROP TABLE IF EXISTS {table_name}") +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_Privileges_All("1.0") +) +def create_with_all_privilege_granted_directly_or_via_role(self, node=None): + """Check that user is able to create a table with ALL privilege, either granted directly or through a role. + """ + user_name = f"user_{getuid()}" + role_name = f"role_{getuid()}" + + if node is None: + node = self.context.node + + with user(node, f"{user_name}"): + + Scenario(test=create_with_all_privilege, + name="create with ALL privilege granted directly")(grant_target_name=user_name, user_name=user_name) + + with user(node, f"{user_name}"), role(node, f"{role_name}"): + + with When("I grant the role to the user"): + node.query(f"GRANT {role_name} TO {user_name}") + + Scenario(test=create_with_all_privilege, + name="create with ALL privilege granted through a role")(grant_target_name=role_name, user_name=user_name) + +@TestOutline +def create_with_all_privilege(self, grant_target_name, user_name, node=None): + """Check that user is able to create a table with the granted privileges. + """ + table_name = f"table_{getuid()}" + + if node is None: + node = self.context.node + try: + with Given("I don't have a table"): + node.query(f"DROP TABLE IF EXISTS {table_name}") + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I try to create a table without privilege as the user"): + node.query(f"CREATE TABLE {table_name} (x Int8) ENGINE = Memory", settings = [("user", f"{user_name}")]) + + finally: + with Then("I drop the table"): + node.query(f"DROP TABLE IF EXISTS {table_name}") + @TestScenario def create_with_revoked_create_table_privilege_revoked_directly_or_from_role(self, node=None): """Check that user is unable to create table after the CREATE TABLE privilege is revoked, either directly or from a role. @@ -125,6 +182,57 @@ def create_with_revoked_create_table_privilege(self, grant_target_name, user_nam with Finally("I drop the table"): node.query(f"DROP TABLE IF EXISTS {table_name}") +@TestScenario +def create_with_all_privileges_revoked_directly_or_from_role(self, node=None): + """Check that user is unable to create table after ALL privileges are revoked, either directly or from a role. + """ + user_name = f"user_{getuid()}" + role_name = f"role_{getuid()}" + + if node is None: + node = self.context.node + + with user(node, f"{user_name}"): + + Scenario(test=create_with_revoked_all_privilege, + name="create with all privilege revoked directly")(grant_target_name=user_name, user_name=user_name) + + with user(node, f"{user_name}"), role(node, f"{role_name}"): + + with When("I grant the role to the user"): + node.query(f"GRANT {role_name} TO {user_name}") + + Scenario(test=create_with_revoked_all_privilege, + name="create with all privilege revoked from a role")(grant_target_name=role_name, user_name=user_name) + +@TestOutline +def create_with_revoked_all_privilege(self, grant_target_name, user_name, node=None): + """Revoke ALL privilege and check the user is unable to create a table. + """ + table_name = f"table_{getuid()}" + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") + + if node is None: + node = self.context.node + + try: + with Given("I don't have a table"): + node.query(f"DROP TABLE IF EXISTS {table_name}") + + with When("I grant CREATE TABLE privilege"): + node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I try to create a table on the table as the user"): + node.query(f"CREATE TABLE {table_name} (x Int8) ENGINE = Memory", settings = [("user", f"{user_name}")], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the table"): + node.query(f"DROP TABLE IF EXISTS {table_name}") + @TestScenario def create_without_source_table_privilege(self, node=None): """Check that user is unable to create a table without select diff --git a/tests/testflows/rbac/tests/privileges/create/create_temp_table.py b/tests/testflows/rbac/tests/privileges/create/create_temp_table.py index 5dbbcc04732..ac38e0269cf 100644 --- a/tests/testflows/rbac/tests/privileges/create/create_temp_table.py +++ b/tests/testflows/rbac/tests/privileges/create/create_temp_table.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute CREATE TEMPORARY TABLE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,11 +32,17 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): temp_table_name = f"temp_table_{getuid()}" try: - with When("I attempt to create a temporary table without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to create a temporary table without privilege"): node.query(f"CREATE TEMPORARY TABLE {temp_table_name} (x Int8)", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -44,7 +50,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the temporary table"): node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): temp_table_name = f"temp_table_{getuid()}" try: @@ -58,7 +64,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the temporary table"): node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): temp_table_name = f"temp_table_{getuid()}" try: @@ -76,9 +82,43 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the temporary table"): node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") + with Scenario("user with revoked ALL privilege"): + temp_table_name = f"temp_table_{getuid()}" + + try: + with When("I grant the create temporary table privilege"): + node.query(f"GRANT CREATE TEMPORARY TABLE ON *.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to create a temporary table"): + node.query(f"CREATE TEMPORARY TABLE {temp_table_name} (x Int8)", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the temporary table"): + node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") + + with Scenario("user with ALL privilege"): + temp_table_name = f"temp_table_{getuid()}" + + try: + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to create aa temporary table"): + node.query(f"CREATE TEMPORARY TABLE {temp_table_name} (x Int8)", settings = [("user", user_name)]) + + finally: + with Finally("I drop the temporary table"): + node.query(f"DROP TEMPORARY TABLE IF EXISTS {temp_table_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_CreateTemporaryTable("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("create temporary table") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -91,5 +131,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/create/create_user.py b/tests/testflows/rbac/tests/privileges/create/create_user.py index 02fe238b618..b055deecea2 100644 --- a/tests/testflows/rbac/tests/privileges/create/create_user.py +++ b/tests/testflows/rbac/tests/privileges/create/create_user.py @@ -17,7 +17,7 @@ def create_user_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=create_user, flags=TE, + Suite(run=create_user, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in create_user.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def create_user_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=create_user, flags=TE, + Suite(run=create_user, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in create_user.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("CREATE USER",), ]) @@ -60,7 +61,13 @@ def create_user(self, privilege, grant_target_name, user_name, node=None): create_user_name = f"create_user_{getuid()}" try: - with When("I check the user can't create a user"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't create a user"): node.query(f"CREATE USER {create_user_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -127,7 +134,7 @@ def default_role_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(test=default_role, flags=TE)(grant_target_name=user_name, user_name=user_name) + Suite(test=default_role)(grant_target_name=user_name, user_name=user_name) @TestSuite def default_role_granted_via_role(self, node=None): @@ -145,7 +152,7 @@ def default_role_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(test=default_role, flags=TE)(grant_target_name=role_name, user_name=user_name) + Suite(test=default_role)(grant_target_name=role_name, user_name=user_name) @TestSuite @Requirements( @@ -215,7 +222,7 @@ def default_role(self, grant_target_name, user_name, node=None): settings = [("user", f"{user_name}")]) finally: - with Finally("I drop the user", flags=TE): + with Finally("I drop the user"): node.query(f"DROP USER IF EXISTS {create_user_name} ON CLUSTER sharded_cluster") with And("I drop the role from the cluster"): @@ -264,6 +271,8 @@ def default_role(self, grant_target_name, user_name, node=None): @Name("create user") @Requirements( RQ_SRS_006_RBAC_Privileges_CreateUser("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of CREATE USER. diff --git a/tests/testflows/rbac/tests/privileges/detach/detach_database.py b/tests/testflows/rbac/tests/privileges/detach/detach_database.py index 8f4576c3399..12eeb39aa1b 100644 --- a/tests/testflows/rbac/tests/privileges/detach/detach_database.py +++ b/tests/testflows/rbac/tests/privileges/detach/detach_database.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute DETACH DATABASE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -39,7 +39,13 @@ def privilege_check(grant_target_name, user_name, node=None): with Given("I have a database"): node.query(f"CREATE DATABASE {db_name}") - with When("I attempt to detach the database"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to detach the database"): node.query(f"DETACH DATABASE {db_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) finally: @@ -48,7 +54,7 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the database", flags=TE): node.query(f"DROP DATABASE IF EXISTS {db_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): db_name = f"db_{getuid()}" try: @@ -67,7 +73,7 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the database", flags=TE): node.query(f"DROP DATABASE IF EXISTS {db_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): db_name = f"db_{getuid()}" try: @@ -90,9 +96,53 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the database", flags=TE): node.query(f"DROP DATABASE IF EXISTS {db_name}") + with Scenario("user with revoked ALL privilege"): + db_name = f"db_{getuid()}" + + try: + with Given("I have a database"): + node.query(f"CREATE DATABASE {db_name}") + + with When("I grant the drop database privilege"): + node.query(f"GRANT DROP DATABASE ON {db_name}.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to detach a database"): + node.query(f"DETACH DATABASE {db_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I reattach the database", flags=TE): + node.query(f"ATTACH DATABASE IF NOT EXISTS {db_name}") + with And("I drop the database", flags=TE): + node.query(f"DROP DATABASE IF EXISTS {db_name}") + + with Scenario("user with ALL privilege"): + db_name = f"db_{getuid()}" + + try: + with Given("I have a database"): + node.query(f"CREATE DATABASE {db_name}") + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to detach a database"): + node.query(f"DETACH DATABASE {db_name}", settings = [("user", user_name)]) + + finally: + with Finally("I reattach the database", flags=TE): + node.query(f"ATTACH DATABASE IF NOT EXISTS {db_name}") + with And("I drop the database", flags=TE): + node.query(f"DROP DATABASE IF EXISTS {db_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_DetachDatabase("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("detach database") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -105,5 +155,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/detach/detach_dictionary.py b/tests/testflows/rbac/tests/privileges/detach/detach_dictionary.py index 5ae992e3623..17b37ce6dc0 100644 --- a/tests/testflows/rbac/tests/privileges/detach/detach_dictionary.py +++ b/tests/testflows/rbac/tests/privileges/detach/detach_dictionary.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute DETACH DICTIONARY with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,14 +32,20 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): dict_name = f"dict_{getuid()}" try: with Given("I have a dictionary"): node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)") - with When("I attempt to detach a dictionary without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to detach a dictionary without privilege"): node.query(f"DETACH DICTIONARY {dict_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) finally: @@ -48,7 +54,7 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the dictionary", flags=TE): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): dict_name = f"dict_{getuid()}" try: @@ -67,7 +73,7 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the dictionary", flags=TE): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): dict_name = f"dict_{getuid()}" try: @@ -89,9 +95,52 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the dictionary", flags=TE): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + with Scenario("user with revoked ALL privilege"): + dict_name = f"dict_{getuid()}" + + try: + with Given("I have a dictionary"): + node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)") + + with When("I grant the drop dictionary privilege"): + node.query(f"GRANT DROP DICTIONARY ON {dict_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to detach a dictionary"): + node.query(f"DETACH DICTIONARY {dict_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) + + finally: + with Finally("I reattach the dictionary", flags=TE): + node.query(f"ATTACH DICTIONARY IF NOT EXISTS {dict_name}") + with And("I drop the dictionary", flags=TE): + node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + + with Scenario("user with ALL privilege"): + dict_name = f"dict_{getuid()}" + + try: + with Given("I have a dictionary"): + node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)") + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to detach a dictionary"): + node.query(f"DETACH DICTIONARY {dict_name}", settings = [("user", user_name)]) + + finally: + with Finally("I reattach the dictionary", flags=TE): + node.query(f"ATTACH DICTIONARY IF NOT EXISTS {dict_name}") + with And("I drop the dictionary", flags=TE): + node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_DetachDictionary("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("detach dictionary") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -104,5 +153,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/detach/detach_table.py b/tests/testflows/rbac/tests/privileges/detach/detach_table.py index 38a4a5dfde1..b5a01b361fc 100644 --- a/tests/testflows/rbac/tests/privileges/detach/detach_table.py +++ b/tests/testflows/rbac/tests/privileges/detach/detach_table.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute DETACH TABLE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,13 +32,19 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): table_name = f"table_{getuid()}" try: with Given("I have a table"): node.query(f"CREATE TABLE {table_name} (x Int8) ENGINE=Memory") + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + with When("I attempt to detach a table without privilege"): node.query(f"DETACH TABLE {table_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -49,7 +55,7 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the table", flags=TE): node.query(f"DROP TABLE IF EXISTS {table_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): table_name = f"table_{getuid()}" try: @@ -68,7 +74,7 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the table", flags=TE): node.query(f"DROP TABLE IF EXISTS {table_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): table_name = f"table_{getuid()}" try: @@ -91,9 +97,53 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the table", flags=TE): node.query(f"DROP TABLE IF EXISTS {table_name}") + with Scenario("user with revoked ALL privilege"): + table_name = f"table_{getuid()}" + + try: + with Given("I have a table"): + node.query(f"CREATE TABLE {table_name} (x Int8) ENGINE=Memory") + + with When("I grant the drop table privilege"): + node.query(f"GRANT DROP TABLE ON *.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to detach a table"): + node.query(f"DETACH TABLE {table_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I reattach the table", flags=TE): + node.query(f"ATTACH TABLE IF NOT EXISTS {table_name}") + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name}") + + with Scenario("user with ALL privilege"): + table_name = f"table_{getuid()}" + + try: + with Given("I have a table"): + node.query(f"CREATE TABLE {table_name} (x Int8) ENGINE=Memory") + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to detach a table"): + node.query(f"DETACH TABLE {table_name}", settings = [("user", user_name)]) + + finally: + with Finally("I reattach the table", flags=TE): + node.query(f"ATTACH TABLE IF NOT EXISTS {table_name}") + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE IF EXISTS {table_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_DetachTable("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("detach table") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -106,5 +156,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/detach/detach_view.py b/tests/testflows/rbac/tests/privileges/detach/detach_view.py index e6e8adad065..c3c9f70a35a 100644 --- a/tests/testflows/rbac/tests/privileges/detach/detach_view.py +++ b/tests/testflows/rbac/tests/privileges/detach/detach_view.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute DETACH VIEW with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,13 +32,19 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): view_name = f"view_{getuid()}" try: with Given("I have a view"): node.query(f"CREATE VIEW {view_name} AS SELECT 1") + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + with When("I attempt to drop a view without privilege"): node.query(f"DETACH VIEW {view_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -49,7 +55,7 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the view", flags=TE): node.query(f"DROP VIEW IF EXISTS {view_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): view_name = f"view_{getuid()}" try: @@ -68,7 +74,7 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the table", flags=TE): node.query(f"DROP VIEW IF EXISTS {view_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): view_name = f"view_{getuid()}" try: @@ -91,9 +97,53 @@ def privilege_check(grant_target_name, user_name, node=None): with And("I drop the view", flags=TE): node.query(f"DROP VIEW IF EXISTS {view_name}") + with Scenario("user with revoked ALL privilege"): + view_name = f"view_{getuid()}" + + try: + with Given("I have a view"): + node.query(f"CREATE VIEW {view_name} AS SELECT 1") + + with When("I grant the drop view privilege"): + node.query(f"GRANT DROP VIEW ON {view_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to drop a view"): + node.query(f"DETACH VIEW {view_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I reattach the view as a table", flags=TE): + node.query(f"ATTACH VIEW IF NOT EXISTS {view_name} AS SELECT 1") + with And("I drop the view", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + + with Scenario("user with ALL privilege"): + view_name = f"view_{getuid()}" + + try: + with Given("I have a view"): + node.query(f"CREATE VIEW {view_name} AS SELECT 1") + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to drop a view"): + node.query(f"DETACH VIEW {view_name}", settings = [("user", user_name)]) + + finally: + with Finally("I reattach the view as a table", flags=TE): + node.query(f"ATTACH VIEW IF NOT EXISTS {view_name} AS SELECT 1") + with And("I drop the table", flags=TE): + node.query(f"DROP VIEW IF EXISTS {view_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_DetachView("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("detach view") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -106,5 +156,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/dictGet.py b/tests/testflows/rbac/tests/privileges/dictGet.py index 532fa798eb2..21de4a36b77 100644 --- a/tests/testflows/rbac/tests/privileges/dictGet.py +++ b/tests/testflows/rbac/tests/privileges/dictGet.py @@ -39,8 +39,8 @@ def dictGet_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=dictGet_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictGet_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in dictGet_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -60,60 +60,67 @@ def dictGet_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=dictGet_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictGet_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in dictGet_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) -@Examples("privilege",[ - ("dictGet",), - ("dictHas",), - ("dictGetHierarchy",), - ("dictIsIn",), +@Examples("privilege on",[ + ("ALL", "*.*"), + ("dictGet", "dict"), + ("dictHas", "dict"), + ("dictGetHierarchy", "dict"), + ("dictIsIn", "dict"), ]) @Requirements( RQ_SRS_006_RBAC_dictGet_RequiredPrivilege("1.0") ) -def dictGet_check(self, privilege, grant_target_name, user_name, node=None): +def dictGet_check(self, privilege, on, grant_target_name, user_name, node=None): """Check that user is able to execute `dictGet` if and only if they have the necessary privileges. """ if node is None: node = self.context.node + dict_name = f"dict_{getuid()}" + table_name = f"table_{getuid()}" + + on = on.replace("dict", f"{dict_name}") + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user without privilege"): with dict_setup(node, table_name, dict_name): - with When("I attempt to dictGet without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to dictGet without privilege"): node.query(f"SELECT dictGet ({dict_name},'y',toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user with privilege"): with dict_setup(node, table_name, dict_name): with When(f"I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with Then("I attempt to dictGet with privilege"): node.query(f"SELECT dictGet ({dict_name},'y',toUInt64(1))", settings = [("user", user_name)]) - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" + with Scenario("user with revoked privilege"): with dict_setup(node, table_name, dict_name): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with And("I revoke privilege"): - node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}") + node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}") with When("I attempt to dictGet without privilege"): node.query(f"SELECT dictGet ({dict_name},'y',toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -130,8 +137,8 @@ def dictGetOrDefault_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=dictGetOrDefault_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictGetOrDefault_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in dictGetOrDefault_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -151,60 +158,67 @@ def dictGetOrDefault_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=dictGetOrDefault_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictGetOrDefault_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in dictGetOrDefault_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) -@Examples("privilege",[ - ("dictGet",), - ("dictHas",), - ("dictGetHierarchy",), - ("dictIsIn",), +@Examples("privilege on",[ + ("ALL", "*.*"), + ("dictGet", "dict"), + ("dictHas", "dict"), + ("dictGetHierarchy", "dict"), + ("dictIsIn", "dict"), ]) @Requirements( RQ_SRS_006_RBAC_dictGet_OrDefault_RequiredPrivilege("1.0") ) -def dictGetOrDefault_check(self, privilege, grant_target_name, user_name, node=None): +def dictGetOrDefault_check(self, privilege, on, grant_target_name, user_name, node=None): """Check that user is able to execute `dictGetOrDefault` if and only if they have the necessary privileges. """ if node is None: node = self.context.node + dict_name = f"dict_{getuid()}" + table_name = f"table_{getuid()}" + + on = on.replace("dict", f"{dict_name}") + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user without privilege"): with dict_setup(node, table_name, dict_name): - with When("I attempt to dictGetOrDefault without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to dictGetOrDefault without privilege"): node.query(f"SELECT dictGetOrDefault ({dict_name},'y',toUInt64(1),toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user with privilege"): with dict_setup(node, table_name, dict_name): with When(f"I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with Then("I attempt to dictGetOrDefault with privilege"): node.query(f"SELECT dictGetOrDefault ({dict_name},'y',toUInt64(1),toUInt64(1))", settings = [("user", user_name)]) - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" + with Scenario("user with revoked privilege"): with dict_setup(node, table_name, dict_name): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with And("I revoke privilege"): - node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}") + node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}") with When("I attempt to dictGetOrDefault without privilege"): node.query(f"SELECT dictGetOrDefault ({dict_name},'y',toUInt64(1),toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -221,8 +235,8 @@ def dictHas_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=dictHas_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictHas_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in dictHas_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -242,60 +256,67 @@ def dictHas_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=dictHas_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictHas_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in dictHas_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) -@Examples("privilege",[ - ("dictGet",), - ("dictHas",), - ("dictGetHierarchy",), - ("dictIsIn",), +@Examples("privilege on",[ + ("ALL", "*.*"), + ("dictGet", "dict"), + ("dictHas", "dict"), + ("dictGetHierarchy", "dict"), + ("dictIsIn", "dict"), ]) @Requirements( RQ_SRS_006_RBAC_dictHas_RequiredPrivilege("1.0") ) -def dictHas_check(self, privilege, grant_target_name, user_name, node=None): +def dictHas_check(self, privilege, on, grant_target_name, user_name, node=None): """Check that user is able to execute `dictHas` if and only if they have the necessary privileges. """ if node is None: node = self.context.node + dict_name = f"dict_{getuid()}" + table_name = f"table_{getuid()}" + + on = on.replace("dict", f"{dict_name}") + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user without privilege"): with dict_setup(node, table_name, dict_name): - with When("I attempt to dictHas without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to dictHas without privilege"): node.query(f"SELECT dictHas({dict_name},toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user with privilege"): with dict_setup(node, table_name, dict_name): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with Then("I attempt to dictHas with privilege"): node.query(f"SELECT dictHas({dict_name},toUInt64(1))", settings = [("user", user_name)]) - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" + with Scenario("user with revoked privilege"): with dict_setup(node, table_name, dict_name): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with And("I revoke privilege"): - node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}") + node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}") with When("I attempt to dictHas without privilege"): node.query(f"SELECT dictHas({dict_name},toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -311,8 +332,8 @@ def dictGetHierarchy_granted_directly(self, node=None): node = self.context.node with user(node, f"{user_name}"): - Suite(run=dictGetHierarchy_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictGetHierarchy_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in dictGetHierarchy_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -332,60 +353,67 @@ def dictGetHierarchy_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=dictGetHierarchy_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictGetHierarchy_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in dictGetHierarchy_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) -@Examples("privilege",[ - ("dictGet",), - ("dictHas",), - ("dictGetHierarchy",), - ("dictIsIn",), +@Examples("privilege on",[ + ("ALL", "*.*"), + ("dictGet", "dict"), + ("dictHas", "dict"), + ("dictGetHierarchy", "dict"), + ("dictIsIn", "dict"), ]) @Requirements( RQ_SRS_006_RBAC_dictGetHierarchy_RequiredPrivilege("1.0") ) -def dictGetHierarchy_check(self, privilege, grant_target_name, user_name, node=None): +def dictGetHierarchy_check(self, privilege, on, grant_target_name, user_name, node=None): """Check that user is able to execute `dictGetHierarchy` if and only if they have the necessary privileges. """ if node is None: node = self.context.node + dict_name = f"dict_{getuid()}" + table_name = f"table_{getuid()}" + + on = on.replace("dict", f"{dict_name}") + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user without privilege"): with dict_setup(node, table_name, dict_name): - with When("I attempt to dictGetHierarchy without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to dictGetHierarchy without privilege"): node.query(f"SELECT dictGetHierarchy({dict_name},toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user with privilege"): with dict_setup(node, table_name, dict_name): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with Then("I attempt to dictGetHierarchy with privilege"): node.query(f"SELECT dictGetHierarchy({dict_name},toUInt64(1))", settings = [("user", user_name)]) - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" + with Scenario("user with revoked privilege"): with dict_setup(node, table_name, dict_name): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with And("I revoke privilege"): - node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}") + node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}") with When("I attempt to dictGetHierarchy without privilege"): node.query(f"SELECT dictGetHierarchy({dict_name},toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -401,8 +429,8 @@ def dictIsIn_granted_directly(self, node=None): node = self.context.node with user(node, f"{user_name}"): - Suite(run=dictIsIn_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictIsIn_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in dictIsIn_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -422,60 +450,67 @@ def dictIsIn_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=dictIsIn_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name", [ + Suite(run=dictIsIn_check, + examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in dictIsIn_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) -@Examples("privilege",[ - ("dictGet",), - ("dictHas",), - ("dictGetHierarchy",), - ("dictIsIn",), +@Examples("privilege on",[ + ("ALL", "*.*"), + ("dictGet", "dict"), + ("dictHas", "dict"), + ("dictGetHierarchy", "dict"), + ("dictIsIn", "dict"), ]) @Requirements( RQ_SRS_006_RBAC_dictIsIn_RequiredPrivilege("1.0") ) -def dictIsIn_check(self, privilege, grant_target_name, user_name, node=None): +def dictIsIn_check(self, privilege, on, grant_target_name, user_name, node=None): """Check that user is able to execute `dictIsIn` if and only if they have the necessary privileges. """ if node is None: node = self.context.node + dict_name = f"dict_{getuid()}" + table_name = f"table_{getuid()}" + + on = on.replace("dict", f"{dict_name}") + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user without privilege"): with dict_setup(node, table_name, dict_name): - with When("I attempt to dictIsIn without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to dictIsIn without privilege"): node.query(f"SELECT dictIsIn({dict_name},toUInt64(1),toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user with privilege"): with dict_setup(node, table_name, dict_name): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with Then("I attempt to dictIsIn with privilege"): node.query(f"SELECT dictIsIn({dict_name},toUInt64(1),toUInt64(1))", settings = [("user", user_name)]) - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" + with Scenario("user with revoked privilege"): with dict_setup(node, table_name, dict_name): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with And("I revoke privilege"): - node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}") + node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}") with When("I attempt to dictIsIn without privilege"): node.query(f"SELECT dictIsIn({dict_name},toUInt64(1),toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -507,8 +542,8 @@ def dictGetType_granted_directly(self, type, node=None): node = self.context.node with user(node, f"{user_name}"): - Suite(run=dictGetType_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name type", [ + Suite(run=dictGetType_check, + examples=Examples("privilege on grant_target_name user_name type", [ tuple(list(row)+[user_name,user_name,type]) for row in dictGetType_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -544,67 +579,76 @@ def dictGetType_granted_via_role(self, type, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=dictGetType_check, setup=instrument_clickhouse_server_log, - examples=Examples("privilege grant_target_name user_name type", [ + Suite(run=dictGetType_check, + examples=Examples("privilege on grant_target_name user_name type", [ tuple(list(row)+[role_name,user_name,type]) for row in dictGetType_check.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) -@Examples("privilege",[ - ("dictGet",), - ("dictHas",), - ("dictGetHierarchy",), - ("dictIsIn",), +@Examples("privilege on",[ + ("ALL", "*.*"), + ("dictGet", "dict"), + ("dictHas", "dict"), + ("dictGetHierarchy", "dict"), + ("dictIsIn", "dict"), ]) @Requirements( RQ_SRS_006_RBAC_dictGet_Type_RequiredPrivilege("1.0") ) -def dictGetType_check(self, privilege, grant_target_name, user_name, type, node=None): +def dictGetType_check(self, privilege, on, grant_target_name, user_name, type, node=None): """Check that user is able to execute `dictGet` if and only if they have the necessary privileges. """ if node is None: node = self.context.node + dict_name = f"dict_{getuid()}" + table_name = f"table_{getuid()}" + + on = on.replace("dict", f"{dict_name}") + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user without privilege"): with dict_setup(node, table_name, dict_name, type): - with When("I attempt to dictGet without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to dictGet without privilege"): node.query(f"SELECT dictGet{type}({dict_name},'z',toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" - table_name = f"table_{getuid()}" + with Scenario("user with privilege"): with dict_setup(node, table_name, dict_name, type): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with Then("I attempt to dictGet with privilege"): node.query(f"SELECT dictGet{type}({dict_name},'z',toUInt64(1))", settings = [("user", user_name)]) - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): - dict_name = f"dict_{getuid()}" + with Scenario("user with revoked privilege"): with dict_setup(node, table_name, dict_name, type): with When("I grant privilege"): - node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}") + node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") with And("I revoke privilege"): - node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}") + node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}") with When("I attempt to dictGet without privilege"): node.query(f"SELECT dictGet{type}({dict_name},'z',toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message) @TestFeature @Requirements( - RQ_SRS_006_RBAC_dictGet_Privilege("1.0") + RQ_SRS_006_RBAC_dictGet_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("dictGet") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -622,23 +666,23 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): tasks = [] try: - run_scenario(pool, tasks, Suite(test=dictGet_granted_directly)) - run_scenario(pool, tasks, Suite(test=dictGet_granted_via_role)) - run_scenario(pool, tasks, Suite(test=dictGetOrDefault_granted_directly)) - run_scenario(pool, tasks, Suite(test=dictGetOrDefault_granted_via_role)) - run_scenario(pool, tasks, Suite(test=dictHas_granted_directly)) - run_scenario(pool, tasks, Suite(test=dictHas_granted_via_role)) - run_scenario(pool, tasks, Suite(test=dictGetHierarchy_granted_directly)) - run_scenario(pool, tasks, Suite(test=dictGetHierarchy_granted_via_role)) - run_scenario(pool, tasks, Suite(test=dictIsIn_granted_directly)) - run_scenario(pool, tasks, Suite(test=dictIsIn_granted_via_role)) + run_scenario(pool, tasks, Suite(test=dictGet_granted_directly, setup=instrument_clickhouse_server_log)) + run_scenario(pool, tasks, Suite(test=dictGet_granted_via_role, setup=instrument_clickhouse_server_log)) + run_scenario(pool, tasks, Suite(test=dictGetOrDefault_granted_directly, setup=instrument_clickhouse_server_log)) + run_scenario(pool, tasks, Suite(test=dictGetOrDefault_granted_via_role, setup=instrument_clickhouse_server_log)) + run_scenario(pool, tasks, Suite(test=dictHas_granted_directly, setup=instrument_clickhouse_server_log)) + run_scenario(pool, tasks, Suite(test=dictHas_granted_via_role, setup=instrument_clickhouse_server_log)) + run_scenario(pool, tasks, Suite(test=dictGetHierarchy_granted_directly, setup=instrument_clickhouse_server_log)) + run_scenario(pool, tasks, Suite(test=dictGetHierarchy_granted_via_role, setup=instrument_clickhouse_server_log)) + run_scenario(pool, tasks, Suite(test=dictIsIn_granted_directly, setup=instrument_clickhouse_server_log)) + run_scenario(pool, tasks, Suite(test=dictIsIn_granted_via_role, setup=instrument_clickhouse_server_log)) for example in dictGetType_granted_directly.examples: type, = example with Example(example): - run_scenario(pool, tasks, Suite(test=dictGetType_granted_directly),{"type" : type}) - run_scenario(pool, tasks, Suite(test=dictGetType_granted_via_role),{"type" : type}) + run_scenario(pool, tasks, Suite(test=dictGetType_granted_directly, setup=instrument_clickhouse_server_log),{"type" : type}) + run_scenario(pool, tasks, Suite(test=dictGetType_granted_via_role, setup=instrument_clickhouse_server_log),{"type" : type}) finally: join(tasks) diff --git a/tests/testflows/rbac/tests/privileges/distributed_table.py b/tests/testflows/rbac/tests/privileges/distributed_table.py index 5b62448a446..ba001ea7f2c 100755 --- a/tests/testflows/rbac/tests/privileges/distributed_table.py +++ b/tests/testflows/rbac/tests/privileges/distributed_table.py @@ -69,6 +69,7 @@ def create(self): create_scenarios=[ create_without_privilege, create_with_privilege_granted_directly_or_via_role, + create_with_all_privilege_granted_directly_or_via_role, ] for scenario in create_scenarios: @@ -79,18 +80,30 @@ def create_without_privilege(self, node=None): """Check that user is unable to create a distributed table without privileges. """ user_name = f"user_{getuid()}" + table0_name = f"table0_{getuid()}" table1_name = f"table1_{getuid()}" + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") + cluster = self.context.cluster_name + if node is None: node = self.context.node with Given("I have a user"): user(name=user_name) + with And("I have a table on a cluster"): table(name=table0_name, cluster=cluster) - with When("I attempt to create the distributed table without privilege"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {user_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {user_name}") + + with Then("I attempt to create the distributed table without privilege"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed(sharded_cluster, default, {table0_name}, rand())", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) @@ -101,20 +114,25 @@ def create_with_privilege_granted_directly_or_via_role(self, node=None): """ user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" + if node is None: node = self.context.node with Given("I have a user"): user(name=user_name) + Scenario(test=create_with_privilege, name="create with privilege granted directly")(grant_target_name=user_name, user_name=user_name) with Given("I have a user"): user(name=user_name) + with And("I have a role"): role(name=role_name) + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") + Scenario(test=create_with_privilege, name="create with privilege granted through a role")(grant_target_name=role_name, user_name=user_name) @@ -138,20 +156,24 @@ def create_with_privilege(self, user_name, grant_target_name, node=None): with When("I grant create table privilege"): node.query(f"GRANT CREATE ON {table1_name} TO {grant_target_name}") + with Then("I attempt to create the distributed table as the user"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I revoke the create table privilege"): node.query(f"REVOKE CREATE TABLE ON {table1_name} FROM {grant_target_name}") + with And("I grant remote privilege"): node.query(f"GRANT REMOTE ON *.* to {grant_target_name}") + with Then("I attempt to create the distributed table as the user"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant create table privilege"): node.query(f"GRANT CREATE ON {table1_name} TO {grant_target_name}") + with Then("I attempt to create the distributed table as the user"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())", settings = [("user", f"{user_name}")]) @@ -159,6 +181,62 @@ def create_with_privilege(self, user_name, grant_target_name, node=None): with Finally("I drop the distributed table"): node.query(f"DROP TABLE IF EXISTS {table1_name}") +@TestScenario +def create_with_all_privilege_granted_directly_or_via_role(self, node=None): + """Check that user is able to create a distributed table if and only if + they have ALL privilege granted either directly or through a role. + """ + user_name = f"user_{getuid()}" + role_name = f"role_{getuid()}" + + if node is None: + node = self.context.node + + with Given("I have a user"): + user(name=user_name) + + Scenario(test=create_with_privilege, + name="create with privilege granted directly")(grant_target_name=user_name, user_name=user_name) + + with Given("I have a user"): + user(name=user_name) + + with And("I have a role"): + role(name=role_name) + + with When("I grant the role to the user"): + node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") + + Scenario(test=create_with_privilege, + name="create with privilege granted through a role")(grant_target_name=role_name, user_name=user_name) + +@TestOutline +def create_with_privilege(self, user_name, grant_target_name, node=None): + """Grant ALL privilege and check the user is able is create the table. + """ + table0_name = f"table0_{getuid()}" + table1_name = f"table1_{getuid()}" + + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") + cluster = self.context.cluster_name + + if node is None: + node = self.context.node + + try: + with Given("I have a table on a cluster"): + table(name=table0_name, cluster=cluster) + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I create the distributed table as the user"): + node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())", settings = [("user", f"{user_name}")]) + + finally: + with Finally("I drop the distributed table"): + node.query(f"DROP TABLE IF EXISTS {table1_name}") + @TestSuite @Requirements( RQ_SRS_006_RBAC_DistributedTable_Select("1.0"), @@ -169,6 +247,7 @@ def select(self): select_scenarios = [ select_without_privilege, select_with_privilege_granted_directly_or_via_role, + select_with_all_privilege_granted_directly_or_via_role ] for scenario in select_scenarios: @@ -191,11 +270,19 @@ def select_without_privilege(self, node=None): try: with Given("I have a user"): user(name=user_name) + with And("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a distributed table"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {user_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {user_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) @@ -222,8 +309,10 @@ def select_with_privilege_granted_directly_or_via_role(self, node=None): with Given("I have a user"): user(name=user_name) + with And("I have a role"): role(name=role_name) + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") @@ -247,25 +336,89 @@ def select_with_privilege(self, user_name, grant_target_name, node=None): try: with Given("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a distributed table"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") with When("I grant select privilege on the distributed table"): node.query(f"GRANT SELECT ON {table1_name} TO {grant_target_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I revoke select privilege on the distributed table"): node.query(f"REVOKE SELECT ON {table1_name} FROM {grant_target_name}") + with And("I grant select privilege on the table used by the distributed table"): node.query(f"GRANT SELECT ON {table0_name} to {grant_target_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant the user select privilege on the distributed table"): node.query(f"GRANT SELECT ON {table1_name} TO {grant_target_name}") + + with Then("I attempt to select from the distributed table as the user"): + node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")]) + + finally: + with Finally("I drop the distributed table"): + node.query(f"DROP TABLE IF EXISTS {table1_name}") + +@TestScenario +def select_with_all_privilege_granted_directly_or_via_role(self, node=None): + """Check that user is able to select from a distributed table if and only if + they have ALL privilege. + """ + user_name = f"user_{getuid()}" + role_name = f"role_{getuid()}" + + if node is None: + node = self.context.node + + with Given("I have a user"): + user(name=user_name) + + Scenario(test=select_with_privilege, + name="select with privilege granted directly")(grant_target_name=user_name, user_name=user_name) + + with Given("I have a user"): + user(name=user_name) + + with And("I have a role"): + role(name=role_name) + + with When("I grant the role to the user"): + node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") + + Scenario(test=select_with_privilege, + name="select with privilege granted through a role")(grant_target_name=role_name, user_name=user_name) + +@TestOutline +def select_with_privilege(self, user_name, grant_target_name, node=None): + """Grant ALL and check the user is able to select from the distributed table. + """ + table0_name = f"table0_{getuid()}" + table1_name = f"table1_{getuid()}" + + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") + cluster = self.context.cluster_name + + if node is None: + node = self.context.node + + try: + with Given("I have a table on a cluster"): + table(name=table0_name, cluster=cluster) + + with And("I have a distributed table"): + node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")]) @@ -293,10 +446,12 @@ def insert_without_privilege(self, node=None): """Check that user is unable to insert into a distributed table without privileges. """ user_name = f"user_{getuid()}" + table0_name = f"table0_{getuid()}" table1_name = f"table1_{getuid()}" exitcode, message = errors.not_enough_privileges(name=f"{user_name}") + cluster = self.context.cluster_name if node is None: @@ -305,11 +460,19 @@ def insert_without_privilege(self, node=None): try: with Given("I have a user"): user(name=user_name) + with And("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a distributed table"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {user_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {user_name}") + with Then("I attempt to insert into the distributed table as the user"): node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) @@ -336,8 +499,10 @@ def insert_with_privilege_granted_directly_or_via_role(self, node=None): with Given("I have a user"): user(name=user_name) + with And("I have a role"): role(name=role_name) + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") @@ -361,25 +526,43 @@ def insert_with_privilege(self, user_name, grant_target_name, node=None): try: with Given("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a distributed table"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") with When("I grant insert privilege on the distributed table"): node.query(f"GRANT INSERT ON {table1_name} TO {grant_target_name}") + with Then("I attempt to insert into the distributed table as the user"): node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I revoke the insert privilege on the distributed table"): node.query(f"REVOKE INSERT ON {table1_name} FROM {grant_target_name}") + with And("I grant insert privilege on the table used by the distributed table"): node.query(f"GRANT INSERT ON {table0_name} to {grant_target_name}") + with Then("I attempt to insert into the distributed table as the user"): node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant insert privilege on the distributed table"): node.query(f"GRANT INSERT ON {table1_name} TO {grant_target_name}") + + with Then("I attempt to insert into the distributed table as the user"): + node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")]) + + with When("I revoke ALL privileges"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to insert into the distributed table as the user"): + node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")], + exitcode=exitcode, message=message) + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* To {grant_target_name}") + with Then("I attempt to insert into the distributed table as the user"): node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")]) @@ -426,8 +609,10 @@ def select_with_table_on_materialized_view_privilege_granted_directly_or_via_rol with Given("I have a user"): user(name=user_name) + with And("I have a role"): role(name=role_name) + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") @@ -452,33 +637,63 @@ def select_with_table_on_materialized_view(self, user_name, grant_target_name, n try: with Given("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a materialized view on a cluster"): node.query(f"CREATE MATERIALIZED VIEW {view_name} ON CLUSTER {cluster} ENGINE = Memory() AS SELECT * FROM {table0_name}") + with And("I have a distributed table on the materialized view"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {view_name}, rand())") + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to select from the distributed table as the user"): + node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], + exitcode=exitcode, message=message) + with When("I grant select privilege on the distributed table"): node.query(f"GRANT SELECT ON {table1_name} TO {grant_target_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I revoke the select privilege on the distributed table"): node.query(f"REVOKE SELECT ON {table1_name} FROM {grant_target_name}") + with And("I grant select privilege on the materialized view"): node.query(f"GRANT SELECT ON {view_name} to {grant_target_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant select privilege on the distributed table"): node.query(f"GRANT SELECT ON {table1_name} TO {grant_target_name}") + + with Then("I attempt to select from the distributed table as the user"): + node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")]) + + with When("I revoke ALL privileges"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to select from the distributed table as the user"): + node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], + exitcode=exitcode, message=message) + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* To {grant_target_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")]) finally: with Finally("I drop the distributed table"): node.query(f"DROP TABLE IF EXISTS {table1_name}") + with And("I drop the view"): node.query(f"DROP VIEW IF EXISTS {view_name}") @@ -501,8 +716,10 @@ def select_with_table_on_source_table_of_materialized_view_privilege_granted_dir with Given("I have a user"): user(name=user_name) + with And("I have a role"): role(name=role_name) + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") @@ -527,33 +744,53 @@ def select_with_table_on_source_table_of_materialized_view(self, user_name, gran try: with Given("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a materialized view on a cluster"): node.query(f"CREATE MATERIALIZED VIEW {view_name} ON CLUSTER {cluster} ENGINE = Memory() AS SELECT * FROM {table0_name}") + with And("I have a distributed table using the source table of the materialized view"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") with When("I grant select privilege on the distributed table"): node.query(f"GRANT SELECT ON {table1_name} TO {grant_target_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I revoke select privilege on the distributed table"): node.query(f"REVOKE SELECT ON {table1_name} FROM {grant_target_name}") + with And("I grant select privilege on the source table"): node.query(f"GRANT SELECT ON {table0_name} to {grant_target_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant select privilege on the distributed table"): node.query(f"GRANT SELECT ON {table1_name} TO {grant_target_name}") + + with Then("I attempt to select from the distributed table as the user"): + node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")]) + + with When("I revoke ALL privileges"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to select from the distributed table as the user"): + node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")], + exitcode=exitcode, message=message) + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* To {grant_target_name}") + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")]) finally: with Finally("I drop the distributed table"): node.query(f"DROP TABLE IF EXISTS {table1_name}") + with And("I drop the view"): node.query(f"DROP VIEW IF EXISTS {view_name}") @@ -576,8 +813,10 @@ def select_with_table_on_distributed_table_privilege_granted_directly_or_via_rol with Given("I have a user"): user(name=user_name) + with And("I have a role"): role(name=role_name) + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") @@ -602,26 +841,47 @@ def select_with_table_on_distributed_table(self, user_name, grant_target_name, n try: with Given("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a distributed table on a cluster"): node.query(f"CREATE TABLE {table1_name} ON CLUSTER {cluster} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") + with And("I have a distributed table on that distributed table"): node.query(f"CREATE TABLE {table2_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table1_name}, rand())") for permutation in permutations(table_count=3): + with grant_select_on_table(node, permutation, grant_target_name, table0_name, table1_name, table2_name) as tables_granted: + with When(f"permutation={permutation}, tables granted = {tables_granted}"): + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table2_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant select on all tables"): + with grant_select_on_table(node, max(permutations(table_count=3))+1, grant_target_name, table0_name, table1_name, table2_name): + with Then("I attempt to select from the distributed table as the user"): node.query(f"SELECT * FROM {table2_name}", settings = [("user", f"{user_name}")]) + with When("I revoke ALL privileges"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to select from the distributed table as the user"): + node.query(f"SELECT * FROM {table2_name}", settings = [("user", f"{user_name}")], + exitcode=exitcode, message=message) + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* To {grant_target_name}") + + with Then("I attempt to select from the distributed table as the user"): + node.query(f"SELECT * FROM {table2_name}", settings = [("user", f"{user_name}")]) + finally: with Finally("I drop the first distributed table"): node.query(f"DROP TABLE IF EXISTS {table1_name}") + with And("I drop the other distributed table"): node.query(f"DROP TABLE IF EXISTS {table2_name}") @@ -644,8 +904,10 @@ def insert_with_table_on_materialized_view_privilege_granted_directly_or_via_rol with Given("I have a user"): user(name=user_name) + with And("I have a role"): role(name=role_name) + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") @@ -671,35 +933,56 @@ def insert_with_table_on_materialized_view(self, user_name, grant_target_name, n try: with Given(f"I have a table on cluster {cluster}"): table(name=table0_name, cluster=cluster) + with And("I have another table on the same cluster"): table(name=table1_name, cluster=cluster) + with And("I have a materialized view on a cluster"): node.query(f"CREATE MATERIALIZED VIEW {view_name} ON CLUSTER {cluster} TO {table0_name} AS SELECT * FROM {table1_name}") + with And("I have a distributed table on the materialized view"): node.query(f"CREATE TABLE {table2_name} (a UInt64) ENGINE = Distributed({cluster}, default, {view_name}, rand())") with When("I grant insert privilege on the distributed table"): node.query(f"GRANT INSERT ON {table2_name} TO {grant_target_name}") + with Then("I attempt to insert into the distributed table as the user"): node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I revoke the insert privilege on the distributed table"): node.query(f"REVOKE INSERT ON {table2_name} FROM {grant_target_name}") + with And("I grant insert privilege on the view"): node.query(f"GRANT INSERT ON {view_name} to {grant_target_name}") + with Then("I attempt insert into the distributed table as the user"): node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant insert privilege on the distributed table"): node.query(f"GRANT INSERT ON {table2_name} TO {grant_target_name}") + + with Then("I attempt to insert into the distributed table as the user"): + node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")]) + + with When("I revoke ALL privileges"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt insert into the distributed table as the user"): + node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")], + exitcode=exitcode, message=message) + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* To {grant_target_name}") + with Then("I attempt to insert into the distributed table as the user"): node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")]) finally: with Finally("I drop the distributed table"): node.query(f"DROP TABLE IF EXISTS {table2_name}") + with And("I drop the view"): node.query(f"DROP VIEW IF EXISTS {view_name}") @@ -722,8 +1005,10 @@ def insert_with_table_on_source_table_of_materialized_view_privilege_granted_dir with Given("I have a user"): user(name=user_name) + with And("I have a role"): role(name=role_name) + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") @@ -748,33 +1033,53 @@ def insert_with_table_on_source_table_of_materialized_view(self, user_name, gran try: with Given("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a materialized view on a cluster"): node.query(f"CREATE MATERIALIZED VIEW {view_name} ON CLUSTER {cluster} ENGINE = Memory() AS SELECT * FROM {table0_name}") + with And("I have a distributed table on the materialized view"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") with When("I grant insert privilege on the distributed table"): node.query(f"GRANT INSERT ON {table1_name} TO {grant_target_name}") + with Then("I attempt to insert into the distributed table as the user"): node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I revoke insert privilege on the distributed table"): node.query(f"REVOKE INSERT ON {table1_name} FROM {grant_target_name}") + with And("I grant insert privilege on the source table"): node.query(f"GRANT INSERT ON {table0_name} to {grant_target_name}") + with Then("I attempt insert into the distributed table as the user"): node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant insert privilege on the distributed table"): node.query(f"GRANT INSERT ON {table1_name} TO {grant_target_name}") + + with Then("I attempt to insert into the distributed table as the user"): + node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")]) + + with When("I revoke ALL privileges"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt insert into the distributed table as the user"): + node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")], + exitcode=exitcode, message=message) + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* To {grant_target_name}") + with Then("I attempt to insert into the distributed table as the user"): node.query(f"INSERT INTO {table1_name} VALUES (8888)", settings = [("user", f"{user_name}")]) finally: with Finally("I drop the distributed table"): node.query(f"DROP TABLE IF EXISTS {table1_name}") + with And("I drop the view"): node.query(f"DROP VIEW IF EXISTS {view_name}") @@ -797,8 +1102,10 @@ def insert_with_table_on_distributed_table_privilege_granted_directly_or_via_rol with Given("I have a user"): user(name=user_name) + with And("I have a role"): role(name=role_name) + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name} ON CLUSTER one_shard_cluster") @@ -823,47 +1130,70 @@ def insert_with_table_on_distributed_table(self, user_name, grant_target_name, n try: with Given("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a distributed table on a cluster"): node.query(f"CREATE TABLE {table1_name} ON CLUSTER {cluster} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") + with And("I have a distributed table on that distributed table"): node.query(f"CREATE TABLE {table2_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table1_name}, rand())") with When("I grant insert privilege on the outer distributed table"): node.query(f"GRANT INSERT ON {table2_name} TO {grant_target_name}") + with Then("I attempt to insert into the outer distributed table as the user"): node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I revoke the insert privilege on the outer distributed table"): node.query(f"REVOKE INSERT ON {table2_name} FROM {grant_target_name}") + with And("I grant insert privilege on the inner distributed table"): node.query(f"GRANT INSERT ON {table1_name} to {grant_target_name}") + with Then("I attempt insert into the outer distributed table as the user"): node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I revoke the insert privilege on the inner distributed table"): node.query(f"REVOKE INSERT ON {table1_name} FROM {grant_target_name}") + with And("I grant insert privilege on the innermost table"): node.query(f"GRANT INSERT ON {table0_name} to {grant_target_name}") + with Then("I attempt insert into the outer distributed table as the user"): node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant insert privilege on the inner distributed table"): node.query(f"GRANT INSERT ON {table1_name} to {grant_target_name}") + with Then("I attempt insert into the outer distributed table as the user"): node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant insert privilege on the outer distributed table"): node.query(f"GRANT INSERT ON {table2_name} to {grant_target_name}") + + with Then("I attempt insert into the outer distributed table as the user"): + node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")]) + + with When("I revoke ALL privileges"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt insert into the outer distributed table as the user"): + node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")], + exitcode=exitcode, message=message) + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* To {grant_target_name}") + with Then("I attempt insert into the outer distributed table as the user"): node.query(f"INSERT INTO {table2_name} VALUES (8888)", settings = [("user", f"{user_name}")]) finally: with Finally("I drop the outer distributed table"): node.query(f"DROP TABLE IF EXISTS {table1_name}") + with And("I drop the inner distributed table"): node.query(f"DROP TABLE IF EXISTS {table2_name}") @@ -882,6 +1212,7 @@ def local_user(self, cluster, node=None): is able to execute queries they have privileges to. """ user_name = f"user_{getuid()}" + table0_name = f"table0_{getuid()}" table1_name = f"table1_{getuid()}" @@ -891,22 +1222,35 @@ def local_user(self, cluster, node=None): try: with Given("I have a user on one node"): node.query(f"CREATE USER {user_name}") + with And("I have a table on a cluster"): table(name=table0_name, cluster=cluster) + with And("I have a distributed table"): node.query(f"CREATE TABLE {table1_name} (a UInt64) ENGINE = Distributed({cluster}, default, {table0_name}, rand())") with When("I grant select privilege on the distributed table"): node.query(f"GRANT SELECT ON {table1_name} TO {user_name}") + with And("I grant select privilege on the other table"): node.query(f"GRANT SELECT ON {table0_name} TO {user_name}") with Then("I select from the distributed table as the user"): node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")]) + with When("I revoke ALL privileges"): + node.query(f"REVOKE ALL ON *.* FROM {user_name}") + + with And("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* To {user_name}") + + with Then("I select from the distributed table as the user"): + node.query(f"SELECT * FROM {table1_name}", settings = [("user", f"{user_name}")]) + finally: with Finally("I drop the user"): node.query(f"DROP USER IF EXISTS {user_name}") + with And("I drop the distributed table"): node.query(f"DROP TABLE IF EXISTS {table1_name}") @@ -919,8 +1263,10 @@ def multiple_node_user(self, node=None): if and only if they have the required privileges on the node they are executing the query from. """ user_name = f"user_{getuid()}" + table0_name = f"table0_{getuid()}" table1_name = f"table1_{getuid()}" + exitcode, message = errors.not_enough_privileges(name=f"{user_name}") if node is None: @@ -931,13 +1277,16 @@ def multiple_node_user(self, node=None): try: with Given("I have a user on a cluster with two nodes"): node.query(f"CREATE USER {user_name} ON CLUSTER sharded_cluster12") + with And("I have a table on a cluster"): table(name=table0_name, cluster="sharded_cluster12") + with And("I have a distributed table"): node.query(f"CREATE TABLE {table1_name} ON CLUSTER sharded_cluster12 (a UInt64) ENGINE = Distributed(sharded_cluster12, default, {table0_name}, rand())") with When("I grant select privilege on the distributed table on one node"): node.query(f"GRANT SELECT ON {table1_name} TO {user_name}") + with And("I grant select privilege on the other table on one node"): node.query(f"GRANT SELECT ON {table0_name} TO {user_name}") @@ -951,6 +1300,7 @@ def multiple_node_user(self, node=None): finally: with Finally("I drop the user"): node.query(f"DROP USER IF EXISTS {user_name}") + with And("I drop the distributed table"): node.query(f"DROP TABLE IF EXISTS {table1_name}") @@ -973,13 +1323,19 @@ def cluster_tests(self, cluster, node=None): pool = Pool(3) try: - for suite in loads(current_module(), Suite): - run_scenario(pool, tasks, Suite(test=suite)) + try: + for suite in loads(current_module(), Suite): + run_scenario(pool, tasks, Suite(test=suite)) + finally: + join(tasks) finally: - join(tasks) - + pool.close() @TestFeature +@Requirements( + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") +) @Name("distributed table") def feature(self, node="clickhouse1"): """Check the RBAC functionality of queries executed using distributed tables. @@ -992,9 +1348,13 @@ def feature(self, node="clickhouse1"): pool = Pool(3) try: - run_scenario(pool, tasks, Feature(test=cluster_tests)) - run_scenario(pool, tasks, Scenario(test=local_user)) - run_scenario(pool, tasks, Scenario(test=multiple_node_user)) + try: + run_scenario(pool, tasks, Feature(test=cluster_tests)) + run_scenario(pool, tasks, Scenario(test=local_user)) + run_scenario(pool, tasks, Scenario(test=multiple_node_user)) + finally: + join(tasks) finally: - join(tasks) + pool.close() + diff --git a/tests/testflows/rbac/tests/privileges/drop/drop_database.py b/tests/testflows/rbac/tests/privileges/drop/drop_database.py index fd31b8d5411..274003e763f 100644 --- a/tests/testflows/rbac/tests/privileges/drop/drop_database.py +++ b/tests/testflows/rbac/tests/privileges/drop/drop_database.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute DROP DATABASE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,21 +32,27 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): db_name = f"db_{getuid()}" try: with Given("I have a database"): node.query(f"CREATE DATABASE {db_name}") - with When("I attempt to drop the database"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to drop the database"): node.query(f"DROP DATABASE {db_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) finally: with Finally("I drop the database"): node.query(f"DROP DATABASE IF EXISTS {db_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): db_name = f"db_{getuid()}" try: @@ -63,7 +69,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the database"): node.query(f"DROP DATABASE IF EXISTS {db_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): db_name = f"db_{getuid()}" try: @@ -84,9 +90,49 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the database"): node.query(f"DROP DATABASE IF EXISTS {db_name}") + with Scenario("user with revoked ALL privilege"): + db_name = f"db_{getuid()}" + + try: + with Given("I have a database"): + node.query(f"CREATE DATABASE {db_name}") + + with When("I grant the drop database privilege"): + node.query(f"GRANT DROP DATABASE ON {db_name}.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to drop a database"): + node.query(f"DROP DATABASE {db_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the database"): + node.query(f"DROP DATABASE IF EXISTS {db_name}") + + with Scenario("user with ALL privilege"): + db_name = f"db_{getuid()}" + + try: + with Given("I have a database"): + node.query(f"CREATE DATABASE {db_name}") + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to drop a database"): + node.query(f"DROP DATABASE {db_name}", settings = [("user", user_name)]) + + finally: + with Finally("I drop the database"): + node.query(f"DROP DATABASE IF EXISTS {db_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_DropDatabase("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("drop database") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -99,5 +145,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/drop/drop_dictionary.py b/tests/testflows/rbac/tests/privileges/drop/drop_dictionary.py index 14e6da0ebe9..c3f07885bd5 100644 --- a/tests/testflows/rbac/tests/privileges/drop/drop_dictionary.py +++ b/tests/testflows/rbac/tests/privileges/drop/drop_dictionary.py @@ -12,12 +12,12 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute DROP DICTIONARY with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") @@ -29,21 +29,27 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): dict_name = f"dict_{getuid()}" try: with Given("I have a dictionary"): node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)") - with When("I attempt to drop a dictionary without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to drop a dictionary without privilege"): node.query(f"DROP DICTIONARY {dict_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) finally: with Finally("I drop the dictionary"): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): dict_name = f"dict_{getuid()}" try: @@ -60,7 +66,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the dictionary"): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): dict_name = f"dict_{getuid()}" try: @@ -80,9 +86,27 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the dictionary"): node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") + with Scenario("user with ALL privilege"): + dict_name = f"db_{getuid()}" + + try: + with Given("I have a dictionary"): + node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)") + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I drop the dictionary"): + node.query(f"DROP DICTIONARY {dict_name}", settings = [("user", user_name)]) + + finally: + with Finally("I drop the dictionary"): + node.query(f"DROP DICTIONARY IF EXISTS {dict_name}") @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_DropDictionary("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("drop dictionary") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -95,5 +119,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/drop/drop_quota.py b/tests/testflows/rbac/tests/privileges/drop/drop_quota.py index de25f0e15b1..b8727556a26 100644 --- a/tests/testflows/rbac/tests/privileges/drop/drop_quota.py +++ b/tests/testflows/rbac/tests/privileges/drop/drop_quota.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=drop_quota, flags=TE, + Suite(run=drop_quota, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in drop_quota.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=drop_quota, flags=TE, + Suite(run=drop_quota, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in drop_quota.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("DROP QUOTA",), ]) @@ -63,7 +64,13 @@ def drop_quota(self, privilege, grant_target_name, user_name, node=None): with Given("I have a quota"): node.query(f"CREATE QUOTA {drop_row_policy_name}") - with When("I check the user can't drop a quota"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't drop a quota"): node.query(f"DROP QUOTA {drop_row_policy_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -129,6 +136,8 @@ def drop_quota(self, privilege, grant_target_name, user_name, node=None): @Name("drop quota") @Requirements( RQ_SRS_006_RBAC_Privileges_DropQuota("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of DROP QUOTA. diff --git a/tests/testflows/rbac/tests/privileges/drop/drop_role.py b/tests/testflows/rbac/tests/privileges/drop/drop_role.py index 4b6b7c04741..ca9eb1b0947 100644 --- a/tests/testflows/rbac/tests/privileges/drop/drop_role.py +++ b/tests/testflows/rbac/tests/privileges/drop/drop_role.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=drop_role, flags=TE, + Suite(run=drop_role, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in drop_role.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=drop_role, flags=TE, + Suite(run=drop_role, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in drop_role.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("DROP ROLE",), ]) @@ -58,14 +59,22 @@ def drop_role(self, privilege, grant_target_name, user_name, node=None): with Scenario("DROP ROLE without privilege"): drop_role_name = f"drop_role_{getuid()}" + with role(node, drop_role_name): - with When("I check the user can't drop a role"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't drop a role"): node.query(f"DROP ROLE {drop_role_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) with Scenario("DROP ROLE with privilege"): drop_role_name = f"drop_role_{getuid()}" + with role(node, drop_role_name): with When(f"I grant {privilege}"): @@ -93,6 +102,7 @@ def drop_role(self, privilege, grant_target_name, user_name, node=None): with Scenario("DROP ROLE with revoked privilege"): drop_role_name = f"drop_role_{getuid()}" + with role(node, drop_role_name): with When(f"I grant {privilege}"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -108,6 +118,8 @@ def drop_role(self, privilege, grant_target_name, user_name, node=None): @Name("drop role") @Requirements( RQ_SRS_006_RBAC_Privileges_DropRole("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of DROP ROLE. diff --git a/tests/testflows/rbac/tests/privileges/drop/drop_row_policy.py b/tests/testflows/rbac/tests/privileges/drop/drop_row_policy.py index 6e8a2aaa3d5..ad7fed94df0 100644 --- a/tests/testflows/rbac/tests/privileges/drop/drop_row_policy.py +++ b/tests/testflows/rbac/tests/privileges/drop/drop_row_policy.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=drop_row_policy, flags=TE, + Suite(run=drop_row_policy, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in drop_row_policy.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=drop_row_policy, flags=TE, + Suite(run=drop_row_policy, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in drop_row_policy.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("DROP ROW POLICY",), ("DROP POLICY",), @@ -65,7 +66,13 @@ def drop_row_policy(self, privilege, grant_target_name, user_name, node=None): with Given("I have a row policy"): node.query(f"CREATE ROW POLICY {drop_row_policy_name} ON {table_name}") - with When("I check the user can't drop a row policy"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't drop a row policy"): node.query(f"DROP ROW POLICY {drop_row_policy_name} ON {table_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -130,15 +137,140 @@ def drop_row_policy(self, privilege, grant_target_name, user_name, node=None): with Finally("I drop the row policy"): node.query(f"DROP ROW POLICY IF EXISTS {drop_row_policy_name} ON {table_name}") +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Restriction("1.0") +) +def drop_all_pol_with_conditions(self, node=None): + """Check that when all policies with conditions are dropped, the table becomes unrestricted. + """ + + if node is None: + node = self.context.node + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The row policy has a condition"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING 1") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with And("I can't see any of the rows on the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '' == output, error() + + with When("I drop the row policy"): + node.query(f"DROP ROW POLICY {pol_name} ON {table_name}") + + with Then("I select all the rows from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output and '2' in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0"), +) +def drop_on(self, node=None): + """Check that when a row policy is dropped, users are able to access rows restricted by that policy. + """ + + if node is None: + node = self.context.node + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + with table(node, table_name): + + with Given("I have a row policy"): + row_policy(name=pol_name, table=table_name) + + with And("The row policy has a condition"): + node.query(f"ALTER ROW POLICY {pol_name} ON {table_name} FOR SELECT USING y=1 TO default") + + with And("The table has some values"): + node.query(f"INSERT INTO {table_name} (y) VALUES (1),(2)") + + with And("I can't see one of the rows on the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output and '2' not in output, error() + + with When("I drop the row policy"): + node.query(f"DROP ROW POLICY {pol_name} ON {table_name}") + + with Then("I select all the rows from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output and '2' in output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster("1.0"), +) +def drop_on_cluster(self, node=None): + """Check that when a row policy is dropped on a cluster, it works on all nodes. + """ + + if node is None: + node = self.context.node + node2 = self.context.node2 + + table_name = f"table_{getuid()}" + pol_name = f"pol_{getuid()}" + + try: + with Given("I have a table on a cluster"): + node.query(f"CREATE TABLE {table_name} ON CLUSTER sharded_cluster (x UInt64) ENGINE = Memory") + + with And("I have a row policy"): + node.query(f"CREATE ROW POLICY {pol_name} ON CLUSTER sharded_cluster ON {table_name} FOR SELECT USING 1") + + with And("There are some values on the table on the first node"): + node.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with And("There are some values on the table on the second node"): + node2.query(f"INSERT INTO {table_name} (x) VALUES (1)") + + with When("I drop the row policy on cluster"): + node.query(f"DROP ROW POLICY {pol_name} ON {table_name} ON CLUSTER sharded_cluster") + + with Then("I select from the table"): + output = node.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + with And("I select from another node on the cluster"): + output = node2.query(f"SELECT * FROM {table_name}").output + assert '1' in output, error() + + finally: + with Finally("I drop the row policy", flags=TE): + node.query(f"DROP ROW POLICY IF EXISTS {pol_name} ON CLUSTER sharded_cluster ON {table_name}") + + with And("I drop the table", flags=TE): + node.query(f"DROP TABLE {table_name} ON CLUSTER sharded_cluster") + @TestFeature @Name("drop row policy") @Requirements( RQ_SRS_006_RBAC_Privileges_DropRowPolicy("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of DROP ROW POLICY. """ self.context.node = self.context.cluster.node(node) + self.context.node2 = self.context.cluster.node("clickhouse2") Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log) Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log) + + Scenario(run=drop_all_pol_with_conditions, setup=instrument_clickhouse_server_log) + Scenario(run=drop_on, setup=instrument_clickhouse_server_log) + Scenario(run=drop_on_cluster, setup=instrument_clickhouse_server_log) diff --git a/tests/testflows/rbac/tests/privileges/drop/drop_settings_profile.py b/tests/testflows/rbac/tests/privileges/drop/drop_settings_profile.py index 51139653283..3aa9ef2c369 100644 --- a/tests/testflows/rbac/tests/privileges/drop/drop_settings_profile.py +++ b/tests/testflows/rbac/tests/privileges/drop/drop_settings_profile.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=drop_settings_profile, flags=TE, + Suite(run=drop_settings_profile, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in drop_settings_profile.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=drop_settings_profile, flags=TE, + Suite(run=drop_settings_profile, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in drop_settings_profile.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("DROP SETTINGS PROFILE",), ("DROP PROFILE",), @@ -64,7 +65,13 @@ def drop_settings_profile(self, privilege, grant_target_name, user_name, node=No with Given("I have a settings_profile"): node.query(f"CREATE SETTINGS PROFILE {drop_row_policy_name}") - with When("I check the user can't drop a settings_profile"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't drop a settings_profile"): node.query(f"DROP SETTINGS PROFILE {drop_row_policy_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -130,6 +137,8 @@ def drop_settings_profile(self, privilege, grant_target_name, user_name, node=No @Name("drop settings profile") @Requirements( RQ_SRS_006_RBAC_Privileges_DropSettingsProfile("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of DROP SETTINGS PROFILE. diff --git a/tests/testflows/rbac/tests/privileges/drop/drop_table.py b/tests/testflows/rbac/tests/privileges/drop/drop_table.py index e5deac646eb..1fd394daf96 100644 --- a/tests/testflows/rbac/tests/privileges/drop/drop_table.py +++ b/tests/testflows/rbac/tests/privileges/drop/drop_table.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute DROP TABLE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,14 +32,20 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): table_name = f"table_{getuid()}" try: with Given("I have a table"): node.query(f"CREATE TABLE {table_name} (x Int8) ENGINE=Memory") - with When("I attempt to drop a table without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to drop a table without privilege"): node.query(f"DROP TABLE {table_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) @@ -47,7 +53,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the table"): node.query(f"DROP TABLE IF EXISTS {table_name}") - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): table_name = f"table_{getuid()}" try: @@ -64,7 +70,7 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the table"): node.query(f"DROP TABLE IF EXISTS {table_name}") - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): table_name = f"table_{getuid()}" try: with Given("I have a table"): @@ -84,9 +90,48 @@ def privilege_check(grant_target_name, user_name, node=None): with Finally("I drop the table"): node.query(f"DROP TABLE IF EXISTS {table_name}") + with Scenario("user with revoked ALL privilege"): + table_name = f"table_{getuid()}" + try: + with Given("I have a table"): + node.query(f"CREATE TABLE {table_name} (x Int8) ENGINE=Memory") + + with When("I grant the drop table privilege"): + node.query(f"GRANT DROP TABLE ON *.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to drop a table"): + node.query(f"DROP TABLE {table_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + finally: + with Finally("I drop the table"): + node.query(f"DROP TABLE IF EXISTS {table_name}") + + with Scenario("user with ALL privilege"): + table_name = f"table_{getuid()}" + + try: + with Given("I have a table"): + node.query(f"CREATE TABLE {table_name} (x Int8) ENGINE=Memory") + + with When("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I drop the table"): + node.query(f"DROP TABLE {table_name}", settings = [("user", user_name)]) + + finally: + with Finally("I drop the table"): + node.query(f"DROP TABLE IF EXISTS {table_name}") + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_DropTable("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("drop table") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -99,5 +144,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/drop/drop_user.py b/tests/testflows/rbac/tests/privileges/drop/drop_user.py index 9aec34cca81..c3f1df8ae15 100644 --- a/tests/testflows/rbac/tests/privileges/drop/drop_user.py +++ b/tests/testflows/rbac/tests/privileges/drop/drop_user.py @@ -17,7 +17,7 @@ def drop_user_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=drop_user, flags=TE, + Suite(run=drop_user, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in drop_user.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def drop_user_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=drop_user, flags=TE, + Suite(run=drop_user, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in drop_user.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("DROP USER",), ]) @@ -59,14 +60,22 @@ def drop_user(self, privilege, grant_target_name, user_name, node=None): with Scenario("DROP USER without privilege"): drop_user_name = f"drop_user_{getuid()}" + with user(node, drop_user_name): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + with When("I check the user can't drop a user"): node.query(f"DROP USER {drop_user_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) with Scenario("DROP USER with privilege"): drop_user_name = f"drop_user_{getuid()}" + with user(node, drop_user_name): with When(f"I grant {privilege}"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -76,6 +85,7 @@ def drop_user(self, privilege, grant_target_name, user_name, node=None): with Scenario("DROP USER on cluster"): drop_user_name = f"drop_user_{getuid()}" + try: with Given("I have a user on a cluster"): node.query(f"CREATE USER {drop_user_name} ON CLUSTER sharded_cluster") @@ -93,6 +103,7 @@ def drop_user(self, privilege, grant_target_name, user_name, node=None): with Scenario("DROP USER with revoked privilege"): drop_user_name = f"drop_user_{getuid()}" + with user(node, drop_user_name): with When(f"I grant {privilege}"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -108,6 +119,8 @@ def drop_user(self, privilege, grant_target_name, user_name, node=None): @Name("drop user") @Requirements( RQ_SRS_006_RBAC_Privileges_DropUser("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of DROP USER. diff --git a/tests/testflows/rbac/tests/privileges/feature.py b/tests/testflows/rbac/tests/privileges/feature.py index e7a0cf2d368..7302a971ec1 100755 --- a/tests/testflows/rbac/tests/privileges/feature.py +++ b/tests/testflows/rbac/tests/privileges/feature.py @@ -11,91 +11,92 @@ def feature(self): try: try: - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.insert", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.select", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.public_tables", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.distributed_table", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.grant_option", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.truncate", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.optimize", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.kill_query", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.kill_mutation", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.role_admin", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.dictGet", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.introspection", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.sources", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.admin_option", "feature"), flags=TE), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.insert", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.select", "feature"), ), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.public_tables", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.distributed_table", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.grant_option", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.truncate", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.optimize", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.kill_query", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.kill_mutation", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.role_admin", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.dictGet", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.introspection", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.sources", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.admin_option", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.all_role", "feature")), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_tables", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_dictionaries", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_databases", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_columns", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_users", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_roles", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_quotas", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_settings_profiles", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_row_policies", "feature"), flags=TE), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_tables", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_dictionaries", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_databases", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_columns", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_users", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_roles", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_quotas", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_settings_profiles", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_row_policies", "feature")), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_column", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_index", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_constraint", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_ttl", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_settings", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_update", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_delete", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_freeze", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_fetch", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_move", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_user", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_role", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_row_policy", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_quota", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_settings_profile", "feature"), flags=TE), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_column", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_index", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_constraint", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_ttl", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_settings", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_update", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_delete", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_freeze", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_fetch", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_move", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_user", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_role", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_row_policy", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_quota", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.alter.alter_settings_profile", "feature")), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_database", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_dictionary", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_temp_table", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_table", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_user", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_role", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_row_policy", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_quota", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_settings_profile", "feature"), flags=TE), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_database", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_dictionary", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_temp_table", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_table", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_user", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_role", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_row_policy", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_quota", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.create.create_settings_profile", "feature")), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.attach.attach_database", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.attach.attach_dictionary", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.attach.attach_temp_table", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.attach.attach_table", "feature"), flags=TE), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.attach.attach_database", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.attach.attach_dictionary", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.attach.attach_temp_table", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.attach.attach_table", "feature")), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_database", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_dictionary", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_table", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_user", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_role", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_row_policy", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_quota", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_settings_profile", "feature"), flags=TE), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_database", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_dictionary", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_table", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_user", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_role", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_row_policy", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_quota", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.drop.drop_settings_profile", "feature")), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_database", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_dictionary", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_table", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_view", "feature"), flags=TE), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_database", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_dictionary", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_table", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_view", "feature")), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.drop_cache", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.reload", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.flush", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.merges", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.moves", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.replication_queues", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.ttl_merges", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.restart_replica", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.sends", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.sync_replica", "feature"), flags=TE), {}) - run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.fetches", "feature"), flags=TE), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.drop_cache", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.reload", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.flush", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.merges", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.moves", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.replication_queues", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.ttl_merges", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.restart_replica", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.sends", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.sync_replica", "feature")), {}) + run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.fetches", "feature")), {}) finally: join(tasks) finally: pool.close() - Feature(test=load("rbac.tests.privileges.system.shutdown", "feature"), flags=TE) + Feature(test=load("rbac.tests.privileges.system.shutdown", "feature")) diff --git a/tests/testflows/rbac/tests/privileges/insert.py b/tests/testflows/rbac/tests/privileges/insert.py index 78478967d37..305ce62f5e4 100755 --- a/tests/testflows/rbac/tests/privileges/insert.py +++ b/tests/testflows/rbac/tests/privileges/insert.py @@ -16,6 +16,9 @@ def input_output_equality_check(node, input_columns, input_data, table_name): return input_dict == output_dict @TestScenario +@Requirements( + RQ_SRS_006_RBAC_Privileges_None("1.0") +) def without_privilege(self, table_type, node=None): """Check that user without insert privilege on a table is not able to insert on that table. """ @@ -28,7 +31,13 @@ def without_privilege(self, table_type, node=None): with table(node, table_name, table_type): with user(node, user_name): - with When("I run INSERT without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {user_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {user_name}") + + with Then("I run INSERT without privilege"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings = [("user", user_name)], @@ -60,6 +69,34 @@ def user_with_privilege(self, table_type, node=None): output = node.query(f"SELECT d FROM {table_name} FORMAT JSONEachRow").output assert output == '{"d":"2020-01-01"}', error() +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Grant_Privilege_Insert("1.0"), +) +def all_privilege(self, table_type, node=None): + """Check that user can insert into a table on which they have insert privilege. + """ + user_name = f"user_{getuid()}" + table_name = f"table_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name, table_type): + + with user(node, user_name): + + with When("I grant insert privilege"): + node.query(f"GRANT ALL ON *.* TO {user_name}") + + with And("I use INSERT"): + node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings=[("user",user_name)]) + + with Then("I check the insert functioned"): + output = node.query(f"SELECT d FROM {table_name} FORMAT JSONEachRow").output + assert output == '{"d":"2020-01-01"}', error() + @TestScenario @Requirements( RQ_SRS_006_RBAC_Revoke_Privilege_Insert("1.0"), @@ -82,7 +119,31 @@ def user_with_revoked_privilege(self, table_type, node=None): with And("I revoke insert privilege"): node.query(f"REVOKE INSERT ON {table_name} FROM {user_name}") - with And("I use INSERT"): + with Then("I use INSERT"): + exitcode, message = errors.not_enough_privileges(name=user_name) + node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", + settings=[("user",user_name)], exitcode=exitcode, message=message) + +@TestScenario +def user_with_all_revoked_privilege(self, table_type, node=None): + """Check that user is unable to insert into a table after ALL privilege has been revoked from user. + """ + user_name = f"user_{getuid()}" + table_name = f"table_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name, table_type): + with user(node, user_name): + + with When("I grant insert privilege"): + node.query(f"GRANT INSERT ON {table_name} TO {user_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {user_name}") + + with Then("I use INSERT"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -111,26 +172,36 @@ def user_column_privileges(self, grant_columns, insert_columns_pass, data_fail, """ user_name = f"user_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with user(node, user_name): + with When("I grant insert privilege"): node.query(f"GRANT INSERT({grant_columns}) ON {table_name} TO {user_name}") + if insert_columns_fail is not None: with And("I insert into a column without insert privilege"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} ({insert_columns_fail}) VALUES ({data_fail})", settings=[("user",user_name)], exitcode=exitcode, message=message) + with And("I insert into granted column"): node.query(f"INSERT INTO {table_name} ({insert_columns_pass}) VALUES ({data_pass})", settings=[("user",user_name)]) + with Then("I check the insert functioned"): input_equals_output = input_output_equality_check(node, insert_columns_pass, data_pass, table_name) assert input_equals_output, error() + if revoke_columns is not None: + with When("I revoke insert privilege from columns"): node.query(f"REVOKE INSERT({revoke_columns}) ON {table_name} FROM {user_name}") + with And("I insert into revoked columns"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} ({insert_columns_pass}) VALUES ({data_pass})", @@ -147,16 +218,23 @@ def role_with_privilege(self, table_type, node=None): user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with user(node, user_name), role(node, role_name): + with When("I grant insert privilege to a role"): node.query(f"GRANT INSERT ON {table_name} TO {role_name}") + with And("I grant the role to a user"): node.query(f"GRANT {role_name} TO {user_name}") + with And("I insert into the table"): node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings=[("user",user_name)]) + with Then("I check the data matches the input"): output = node.query(f"SELECT d FROM {table_name} FORMAT JSONEachRow").output assert output == '{"d":"2020-01-01"}', error() @@ -173,16 +251,23 @@ def role_with_revoked_privilege(self, table_type, node=None): user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with user(node, user_name), role(node, role_name): + with When("I grant privilege to a role"): node.query(f"GRANT INSERT ON {table_name} TO {role_name}") + with And("I grant the role to a user"): node.query(f"GRANT {role_name} TO {user_name}") + with And("I revoke privilege from the role"): node.query(f"REVOKE INSERT ON {table_name} FROM {role_name}") + with And("I insert into the table"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", @@ -196,16 +281,23 @@ def user_with_revoked_role(self, table_type, node=None): user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with user(node, user_name), role(node, role_name): + with When("I grant privilege to a role"): node.query(f"GRANT INSERT ON {table_name} TO {role_name}") + with And("I grant the role to a user"): node.query(f"GRANT {role_name} TO {user_name}") + with And("I revoke the role from the user"): node.query(f"REVOKE {role_name} FROM {user_name}") + with And("I insert into the table"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", @@ -235,32 +327,43 @@ def role_column_privileges(self, grant_columns, insert_columns_pass, data_fail, user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): with user(node, user_name), role(node, role_name): - with When("I grant insert privilege"): - node.query(f"GRANT INSERT({grant_columns}) ON {table_name} TO {role_name}") - with And("I grant the role to a user"): - node.query(f"GRANT {role_name} TO {user_name}") - if insert_columns_fail is not None: - with And("I insert into columns without insert privilege"): - exitcode, message = errors.not_enough_privileges(name=user_name) - node.query(f"INSERT INTO {table_name} ({insert_columns_fail}) VALUES ({data_fail})", - settings=[("user",user_name)], exitcode=exitcode, message=message) - with And("I insert into granted column"): + + with When("I grant insert privilege"): + node.query(f"GRANT INSERT({grant_columns}) ON {table_name} TO {role_name}") + + with And("I grant the role to a user"): + node.query(f"GRANT {role_name} TO {user_name}") + + if insert_columns_fail is not None: + with And("I insert into columns without insert privilege"): + exitcode, message = errors.not_enough_privileges(name=user_name) + + node.query(f"INSERT INTO {table_name} ({insert_columns_fail}) VALUES ({data_fail})", + settings=[("user",user_name)], exitcode=exitcode, message=message) + + with And("I insert into granted column"): + node.query(f"INSERT INTO {table_name} ({insert_columns_pass}) VALUES ({data_pass})", + settings=[("user",user_name)]) + + with Then("I check the insert functioned"): + input_equals_output = input_output_equality_check(node, insert_columns_pass, data_pass, table_name) + assert input_equals_output, error() + + if revoke_columns is not None: + with When("I revoke insert privilege from columns"): + node.query(f"REVOKE INSERT({revoke_columns}) ON {table_name} FROM {role_name}") + + with And("I insert into revoked columns"): + exitcode, message = errors.not_enough_privileges(name=user_name) + node.query(f"INSERT INTO {table_name} ({insert_columns_pass}) VALUES ({data_pass})", - settings=[("user",user_name)]) - with Then("I check the insert functioned"): - input_equals_output = input_output_equality_check(node, insert_columns_pass, data_pass, table_name) - assert input_equals_output, error() - if revoke_columns is not None: - with When("I revoke insert privilege from columns"): - node.query(f"REVOKE INSERT({revoke_columns}) ON {table_name} FROM {role_name}") - with And("I insert into revoked columns"): - exitcode, message = errors.not_enough_privileges(name=user_name) - node.query(f"INSERT INTO {table_name} ({insert_columns_pass}) VALUES ({data_pass})", - settings=[("user",user_name)], exitcode=exitcode, message=message) + settings=[("user",user_name)], exitcode=exitcode, message=message) @TestScenario @Requirements( @@ -272,29 +375,40 @@ def user_with_privilege_on_cluster(self, table_type, node=None): """ user_name = f"user_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + try: with Given("I have a user on a cluster"): node.query(f"CREATE USER OR REPLACE {user_name} ON CLUSTER sharded_cluster") + with When("I grant insert privilege on a cluster without the node with the table"): node.query(f"GRANT ON CLUSTER sharded_cluster23 INSERT ON {table_name} TO {user_name}") + with And("I insert into the table expecting a fail"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings=[("user",user_name)], exitcode=exitcode, message=message) + with And("I grant insert privilege on cluster including all nodes"): node.query(f"GRANT ON CLUSTER sharded_cluster INSERT ON {table_name} TO {user_name}") + with And("I revoke insert privilege on cluster without the node with the table"): node.query(f"REVOKE ON CLUSTER sharded_cluster23 INSERT ON {table_name} FROM {user_name}") + with And("I insert into the table"): node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings=[("user",user_name)]) + with And("I check that I can read inserted data"): output = node.query(f"SELECT d FROM {table_name} FORMAT JSONEachRow").output assert output == '{"d":"2020-01-01"}', error() + with And("I revoke insert privilege on cluster with all nodes"): node.query(f"REVOKE ON CLUSTER sharded_cluster INSERT ON {table_name} FROM {user_name}") + with Then("I insert into table expecting fail"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings=[("user",user_name)], @@ -314,33 +428,46 @@ def role_with_privilege_on_cluster(self, table_type, node=None): user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + try: with Given("I have a user on a cluster"): node.query(f"CREATE USER OR REPLACE {user_name} ON CLUSTER sharded_cluster") + with And("I have a role on a cluster"): node.query(f"CREATE ROLE OR REPLACE {role_name} ON CLUSTER sharded_cluster") + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") + with And("I grant insert privilege on a cluster without the node with the table"): node.query(f"GRANT ON CLUSTER sharded_cluster23 INSERT ON {table_name} TO {role_name}") + with And("I insert into the table expecting a fail"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings=[("user",user_name)], exitcode=exitcode, message=message) + with And("I grant insert privilege on cluster including all nodes"): node.query(f"GRANT ON CLUSTER sharded_cluster INSERT ON {table_name} TO {role_name}") + with And("I revoke insert privilege on cluster without the table node"): node.query(f"REVOKE ON CLUSTER sharded_cluster23 INSERT ON {table_name} FROM {role_name}") + with And("I insert into the table"): node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings=[("user",user_name)]) + with And("I check that I can read inserted data"): output = node.query(f"SELECT d FROM {table_name} FORMAT JSONEachRow").output assert output == '{"d":"2020-01-01"}', error() + with And("I revoke insert privilege on cluster with all nodes"): node.query(f"REVOKE ON CLUSTER sharded_cluster INSERT ON {table_name} FROM {role_name}") + with Then("I insert into table expecting fail"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')", settings=[("user",user_name)], @@ -357,7 +484,6 @@ def role_with_privilege_on_cluster(self, table_type, node=None): @Examples("table_type", [ (key,) for key in table_types.keys() ]) -@Flags(TE) @Name("insert") def feature(self, table_type, parallel=None, stress=None, node="clickhouse1"): """Check the RBAC functionality of INSERT. @@ -377,7 +503,10 @@ def feature(self, table_type, parallel=None, stress=None, node="clickhouse1"): pool = Pool(10) try: - for scenario in loads(current_module(), Scenario): - run_scenario(pool, tasks, Scenario(test=scenario, setup=instrument_clickhouse_server_log), {"table_type" : table_type}) + try: + for scenario in loads(current_module(), Scenario): + run_scenario(pool, tasks, Scenario(test=scenario, setup=instrument_clickhouse_server_log), {"table_type" : table_type}) + finally: + join(tasks) finally: - join(tasks) + pool.close() diff --git a/tests/testflows/rbac/tests/privileges/introspection.py b/tests/testflows/rbac/tests/privileges/introspection.py index f8d774902ab..a8d62cf8618 100644 --- a/tests/testflows/rbac/tests/privileges/introspection.py +++ b/tests/testflows/rbac/tests/privileges/introspection.py @@ -35,7 +35,7 @@ def addressToLine_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=addressToLine, flags=TE, + Suite(run=addressToLine, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in addressToLine.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -56,13 +56,14 @@ def addressToLine_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=addressToLine, flags=TE, + Suite(run=addressToLine, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in addressToLine.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("INTROSPECTION",), ("INTROSPECTION FUNCTIONS",), ("addressToLine",), @@ -80,7 +81,13 @@ def addressToLine(self, privilege, grant_target_name, user_name, node=None): with Scenario("addressToLine without privilege"): - with When("I check the user can't use addressToLine"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use addressToLine"): node.query(f"WITH addressToLine(toUInt64(dummy)) AS addr SELECT 1 WHERE addr = ''", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -116,7 +123,7 @@ def addressToSymbol_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=addressToSymbol, flags=TE, + Suite(run=addressToSymbol, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in addressToSymbol.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -137,13 +144,14 @@ def addressToSymbol_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=addressToSymbol, flags=TE, + Suite(run=addressToSymbol, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in addressToSymbol.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("INTROSPECTION",), ("INTROSPECTION FUNCTIONS",), ("addressToSymbol",), @@ -161,7 +169,13 @@ def addressToSymbol(self, privilege, grant_target_name, user_name, node=None): with Scenario("addressToSymbol without privilege"): - with When("I check the user can't use addressToSymbol"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use addressToSymbol"): node.query(f"WITH addressToSymbol(toUInt64(dummy)) AS addr SELECT 1 WHERE addr = ''", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -197,7 +211,7 @@ def demangle_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=demangle, flags=TE, + Suite(run=demangle, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in demangle.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -218,13 +232,14 @@ def demangle_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=demangle, flags=TE, + Suite(run=demangle, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in demangle.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("INTROSPECTION",), ("INTROSPECTION FUNCTIONS",), ("demangle",), @@ -242,7 +257,13 @@ def demangle(self, privilege, grant_target_name, user_name, node=None): with Scenario("demangle without privilege"): - with When("I check the user can't use demangle"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use demangle"): node.query(f"WITH demangle(toString(dummy)) AS addr SELECT 1 WHERE addr = ''", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -270,6 +291,8 @@ def demangle(self, privilege, grant_target_name, user_name, node=None): @Name("introspection") @Requirements( RQ_SRS_006_RBAC_Privileges_Introspection("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of INTROSPECTION. diff --git a/tests/testflows/rbac/tests/privileges/kill_mutation.py b/tests/testflows/rbac/tests/privileges/kill_mutation.py index 41d4a837480..9a27836cad4 100644 --- a/tests/testflows/rbac/tests/privileges/kill_mutation.py +++ b/tests/testflows/rbac/tests/privileges/kill_mutation.py @@ -14,8 +14,16 @@ def no_privilege(self, node=None): table_name = f"merge_tree_{getuid()}" with table(node, table_name): + with user(node, user_name): - with When("I attempt to kill mutation on table"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {user_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {user_name}") + + with Then("I attempt to kill mutation on table"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)]) with Scenario("kill mutation on cluster"): @@ -23,8 +31,16 @@ def no_privilege(self, node=None): table_name = f"merge_tree_{getuid()}" with table(node, table_name): + with user(node, user_name): - with When("I attempt to kill mutation on cluster"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {user_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {user_name}") + + with Then("I attempt to kill mutation on cluster"): node.query(f"KILL MUTATION ON CLUSTER sharded_cluster WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)]) @TestSuite @@ -40,9 +56,9 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(test=update, setup=instrument_clickhouse_server_log)(user_name=user_name, grant_target_name=user_name) - Suite(test=delete, setup=instrument_clickhouse_server_log)(user_name=user_name, grant_target_name=user_name) - Suite(test=drop_column, setup=instrument_clickhouse_server_log)(user_name=user_name, grant_target_name=user_name) + Suite(test=update)(user_name=user_name, grant_target_name=user_name) + Suite(test=delete)(user_name=user_name, grant_target_name=user_name) + Suite(test=drop_column)(user_name=user_name, grant_target_name=user_name) @TestSuite def privileges_granted_via_role(self, node=None): @@ -61,9 +77,9 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(test=update, setup=instrument_clickhouse_server_log)(user_name=user_name, grant_target_name=role_name) - Suite(test=delete, setup=instrument_clickhouse_server_log)(user_name=user_name, grant_target_name=role_name) - Suite(test=drop_column, setup=instrument_clickhouse_server_log)(user_name=user_name, grant_target_name=role_name) + Suite(test=update)(user_name=user_name, grant_target_name=role_name) + Suite(test=delete)(user_name=user_name, grant_target_name=role_name) + Suite(test=drop_column)(user_name=user_name, grant_target_name=role_name) @TestSuite @Requirements( @@ -78,6 +94,9 @@ def update(self, user_name, grant_target_name, node=None): if node is None: node = self.context.node + with Given("The user has no privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + with Scenario("KILL ALTER UPDATE without privilege"): table_name = f"merge_tree_{getuid()}" @@ -86,7 +105,13 @@ def update(self, user_name, grant_target_name, node=None): with Given("I have an ALTER UPDATE mutation"): node.query(f"ALTER TABLE {table_name} UPDATE a = x WHERE 1") - with When("I try to KILL MUTATION"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I try to KILL MUTATION"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)], exitcode=exitcode, message="Exception: Not allowed to kill mutation.") @@ -101,7 +126,7 @@ def update(self, user_name, grant_target_name, node=None): with When("I grant the ALTER UPDATE privilege"): node.query(f"GRANT ALTER UPDATE ON {table_name} TO {grant_target_name}") - with When("I try to KILL MUTATION"): + with Then("I try to KILL MUTATION"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)]) with Scenario("KILL ALTER UPDATE with revoked privilege"): @@ -118,10 +143,42 @@ def update(self, user_name, grant_target_name, node=None): with And("I revoke the ALTER UPDATE privilege"): node.query(f"REVOKE ALTER UPDATE ON {table_name} FROM {grant_target_name}") - with When("I try to KILL MUTATION"): + with Then("I try to KILL MUTATION"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)], exitcode=exitcode, message="Exception: Not allowed to kill mutation.") + with Scenario("KILL ALTER UPDATE with revoked ALL privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name): + + with Given("I have an ALTER UPDATE mutation"): + node.query(f"ALTER TABLE {table_name} UPDATE a = x WHERE 1") + + with When("I grant the ALTER UPDATE privilege"): + node.query(f"GRANT ALTER UPDATE ON {table_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I try to KILL MUTATION"): + node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)], + exitcode=exitcode, message="Exception: Not allowed to kill mutation.") + + with Scenario("KILL ALTER UPDATE with ALL privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name): + + with Given("I have an ALTER UPDATE mutation"): + node.query(f"ALTER TABLE {table_name} UPDATE a = x WHERE 1") + + with When("I grant the ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I try to KILL MUTATION"): + node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)]) + @TestSuite @Requirements( RQ_SRS_006_RBAC_Privileges_KillMutation_AlterDelete("1.0") @@ -135,6 +192,9 @@ def delete(self, user_name, grant_target_name, node=None): if node is None: node = self.context.node + with Given("The user has no privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + with Scenario("KILL ALTER DELETE without privilege"): table_name = f"merge_tree_{getuid()}" @@ -143,7 +203,13 @@ def delete(self, user_name, grant_target_name, node=None): with Given("I have an ALTER DELETE mutation"): node.query(f"ALTER TABLE {table_name} DELETE WHERE 1") - with When("I try to KILL MUTATION"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I try to KILL MUTATION"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)], exitcode=exitcode, message="Exception: Not allowed to kill mutation.") @@ -158,7 +224,7 @@ def delete(self, user_name, grant_target_name, node=None): with When("I grant the ALTER DELETE privilege"): node.query(f"GRANT ALTER DELETE ON {table_name} TO {grant_target_name}") - with When("I try to KILL MUTATION"): + with Then("I try to KILL MUTATION"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)]) with Scenario("KILL ALTER DELETE with revoked privilege"): @@ -175,10 +241,42 @@ def delete(self, user_name, grant_target_name, node=None): with And("I revoke the ALTER DELETE privilege"): node.query(f"REVOKE ALTER DELETE ON {table_name} FROM {grant_target_name}") - with When("I try to KILL MUTATION"): + with Then("I try to KILL MUTATION"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)], exitcode=exitcode, message="Exception: Not allowed to kill mutation.") + with Scenario("KILL ALTER DELETE with revoked ALL privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name): + + with Given("I have an ALTER DELETE mutation"): + node.query(f"ALTER TABLE {table_name} DELETE WHERE 1") + + with When("I grant the ALTER DELETE privilege"): + node.query(f"GRANT ALTER DELETE ON {table_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I try to KILL MUTATION"): + node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)], + exitcode=exitcode, message="Exception: Not allowed to kill mutation.") + + with Scenario("KILL ALTER DELETE with ALL privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name): + + with Given("I have an ALTER DELETE mutation"): + node.query(f"ALTER TABLE {table_name} DELETE WHERE 1") + + with When("I grant the ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I try to KILL MUTATION"): + node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)]) + @TestSuite @Requirements( RQ_SRS_006_RBAC_Privileges_KillMutation_AlterDropColumn("1.0") @@ -192,6 +290,9 @@ def drop_column(self, user_name, grant_target_name, node=None): if node is None: node = self.context.node + with Given("The user has no privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + with Scenario("KILL ALTER DROP COLUMN without privilege"): table_name = f"merge_tree_{getuid()}" @@ -200,7 +301,13 @@ def drop_column(self, user_name, grant_target_name, node=None): with Given("I have an ALTER DROP COLUMN mutation"): node.query(f"ALTER TABLE {table_name} DROP COLUMN x") - with When("I try to KILL MUTATION"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I try to KILL MUTATION"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)], exitcode=exitcode, message="Exception: Not allowed to kill mutation.") @@ -215,7 +322,7 @@ def drop_column(self, user_name, grant_target_name, node=None): with When("I grant the ALTER DROP COLUMN privilege"): node.query(f"GRANT ALTER DROP COLUMN ON {table_name} TO {grant_target_name}") - with When("I try to KILL MUTATION"): + with Then("I try to KILL MUTATION"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)]) with Scenario("KILL ALTER DROP COLUMN with revoked privilege"): @@ -232,13 +339,47 @@ def drop_column(self, user_name, grant_target_name, node=None): with And("I revoke the ALTER DROP COLUMN privilege"): node.query(f"REVOKE ALTER DROP COLUMN ON {table_name} FROM {grant_target_name}") - with When("I try to KILL MUTATION"): + with Then("I try to KILL MUTATION"): node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)], exitcode=exitcode, message="Exception: Not allowed to kill mutation.") + with Scenario("KILL ALTER DROP COLUMN with revoked privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name): + + with Given("I have an ALTER DROP COLUMN mutation"): + node.query(f"ALTER TABLE {table_name} DROP COLUMN x") + + with When("I grant the ALTER DROP COLUMN privilege"): + node.query(f"GRANT ALTER DROP COLUMN ON {table_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I try to KILL MUTATION"): + node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)], + exitcode=exitcode, message="Exception: Not allowed to kill mutation.") + + with Scenario("KILL ALTER DROP COLUMN with ALL privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name): + + with Given("I have an ALTER DROP COLUMN mutation"): + node.query(f"ALTER TABLE {table_name} DROP COLUMN x") + + with When("I grant the ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I try to KILL MUTATION"): + node.query(f"KILL MUTATION WHERE database = 'default' AND table = '{table_name}'", settings = [("user", user_name)]) + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_KillMutation("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("kill mutation") def feature(self, node="clickhouse1", stress=None, parallel=None): diff --git a/tests/testflows/rbac/tests/privileges/kill_query.py b/tests/testflows/rbac/tests/privileges/kill_query.py index 161ee7b35e0..d1f96e23fd8 100644 --- a/tests/testflows/rbac/tests/privileges/kill_query.py +++ b/tests/testflows/rbac/tests/privileges/kill_query.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute KILL QUERY with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,20 +32,27 @@ def privilege_check(grant_target_name, user_name, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): - with When("I attempt to kill a query without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to kill a query without privilege"): node.query(f"KILL QUERY WHERE user ='default'", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): + with When("I grant kill query privilege"): node.query(f"GRANT KILL QUERY TO {grant_target_name}") with Then("I attempt to kill a query"): node.query(f"KILL QUERY WHERE 1", settings = [("user", user_name)]) - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): with When("I grant the kill query privilege"): node.query(f"GRANT KILL QUERY TO {grant_target_name}") @@ -57,7 +64,19 @@ def privilege_check(grant_target_name, user_name, node=None): node.query(f"KILL QUERY WHERE 1", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("execute on cluster", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked ALL privilege"): + + with When("I grant the kill query privilege"): + node.query(f"GRANT KILL QUERY TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to kill a query"): + node.query(f"KILL QUERY WHERE 1", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + with Scenario("execute on cluster"): with When("I grant the truncate privilege"): node.query(f"GRANT KILL QUERY TO {grant_target_name}") @@ -65,9 +84,22 @@ def privilege_check(grant_target_name, user_name, node=None): with Then("I attempt to kill a query"): node.query(f"KILL QUERY ON CLUSTER WHERE 1'", settings = [("user", user_name)]) + with Scenario("user with ALL privilege"): + + with When("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with And("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* ON {grant_target_name}") + + with Then("I attempt to kill a query"): + node.query(f"KILL QUERY WHERE 1", settings = [("user", user_name)]) + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_KillQuery("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Name("kill query") def feature(self, node="clickhouse1", stress=None, parallel=None): @@ -80,5 +112,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): if stress is not None: self.context.stress = stress - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role() diff --git a/tests/testflows/rbac/tests/privileges/optimize.py b/tests/testflows/rbac/tests/privileges/optimize.py index b0e8b69e372..7d3f41a43b4 100644 --- a/tests/testflows/rbac/tests/privileges/optimize.py +++ b/tests/testflows/rbac/tests/privileges/optimize.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, table_type, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute OPTIMIZE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, table_type=table_type, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,16 +32,22 @@ def privilege_check(grant_target_name, user_name, table_type, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): table_name = f"merge_tree_{getuid()}" with table(node, table_name, table_type): - with When("I attempt to optimize a table without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to optimize a table without privilege"): node.query(f"OPTIMIZE TABLE {table_name} FINAL", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): table_name = f"merge_tree_{getuid()}" with table(node, table_name, table_type): @@ -52,7 +58,7 @@ def privilege_check(grant_target_name, user_name, table_type, node=None): with Then("I attempt to optimize a table"): node.query(f"OPTIMIZE TABLE {table_name}", settings = [("user", user_name)]) - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): table_name = f"merge_tree_{getuid()}" with table(node, table_name, table_type): @@ -67,7 +73,22 @@ def privilege_check(grant_target_name, user_name, table_type, node=None): node.query(f"OPTIMIZE TABLE {table_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("execute on cluster", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked ALL privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name, table_type): + + with When("I grant the optimize privilege"): + node.query(f"GRANT OPTIMIZE ON {table_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to optimize a table"): + node.query(f"OPTIMIZE TABLE {table_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + with Scenario("execute on cluster"): table_name = f"merge_tree_{getuid()}" try: @@ -84,9 +105,24 @@ def privilege_check(grant_target_name, user_name, table_type, node=None): with Finally("I drop the table from the cluster"): node.query(f"DROP TABLE IF EXISTS {table_name} ON CLUSTER sharded_cluster") + with Scenario("user with ALL privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name, table_type): + + with When("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with And("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to optimize a table"): + node.query(f"OPTIMIZE TABLE {table_name}", settings = [("user", user_name)]) @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_Optimize("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() @@ -109,5 +145,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): continue with Example(str(example)): - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role(table_type=table_type) diff --git a/tests/testflows/rbac/tests/privileges/public_tables.py b/tests/testflows/rbac/tests/privileges/public_tables.py index 98077438946..ed17c1a77ea 100755 --- a/tests/testflows/rbac/tests/privileges/public_tables.py +++ b/tests/testflows/rbac/tests/privileges/public_tables.py @@ -95,5 +95,5 @@ def sensitive_tables(self, node=None): def feature(self, node="clickhouse1"): self.context.node = self.context.cluster.node(node) - Scenario(run=public_tables, setup=instrument_clickhouse_server_log, flags=TE) - Scenario(run=sensitive_tables, setup=instrument_clickhouse_server_log, flags=TE) \ No newline at end of file + Scenario(run=public_tables, setup=instrument_clickhouse_server_log) + Scenario(run=sensitive_tables, setup=instrument_clickhouse_server_log) diff --git a/tests/testflows/rbac/tests/privileges/role_admin.py b/tests/testflows/rbac/tests/privileges/role_admin.py index 955b0fcd258..8deea7874cd 100644 --- a/tests/testflows/rbac/tests/privileges/role_admin.py +++ b/tests/testflows/rbac/tests/privileges/role_admin.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(test=role_admin, flags=TE)(grant_target_name=user_name, user_name=user_name) + Suite(test=role_admin)(grant_target_name=user_name, user_name=user_name) @TestSuite def privileges_granted_via_role(self, node=None): @@ -35,7 +35,7 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(test=role_admin, flags=TE)(grant_target_name=role_name, user_name=user_name) + Suite(test=role_admin)(grant_target_name=role_name, user_name=user_name) @TestSuite def role_admin(self, grant_target_name, user_name, node=None): @@ -52,7 +52,13 @@ def role_admin(self, grant_target_name, user_name, node=None): with user(node, target_user_name), role(node, role_admin_name): - with When("I check the user can't grant a role"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't grant a role"): node.query(f"GRANT {role_admin_name} TO {target_user_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -105,10 +111,40 @@ def role_admin(self, grant_target_name, user_name, node=None): node.query(f"GRANT {role_admin_name} TO {target_user_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) + with Scenario("Grant role with revoked ALL privilege"): + role_admin_name = f"role_admin_{getuid()}" + target_user_name = f"target_user_{getuid()}" + + with user(node, target_user_name), role(node, role_admin_name): + + with When(f"I grant ROLE ADMIN"): + node.query(f"GRANT ROLE ADMIN ON *.* TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I check the user cannot grant a role"): + node.query(f"GRANT {role_admin_name} TO {target_user_name}", settings=[("user",user_name)], + exitcode=exitcode, message=message) + + with Scenario("Grant role with ALL privilege"): + role_admin_name = f"role_admin_{getuid()}" + target_user_name = f"target_user_{getuid()}" + + with user(node, target_user_name), role(node, role_admin_name): + + with When(f"I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I check the user can grant a role"): + node.query(f"GRANT {role_admin_name} TO {target_user_name}", settings = [("user", f"{user_name}")]) + @TestFeature @Name("role admin") @Requirements( RQ_SRS_006_RBAC_Privileges_RoleAdmin("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of ROLE ADMIN. diff --git a/tests/testflows/rbac/tests/privileges/select.py b/tests/testflows/rbac/tests/privileges/select.py index e58dd8184d2..036ea944ae1 100755 --- a/tests/testflows/rbac/tests/privileges/select.py +++ b/tests/testflows/rbac/tests/privileges/select.py @@ -9,17 +9,31 @@ from rbac.helper.common import * import rbac.helper.errors as errors @TestScenario +@Requirements( + RQ_SRS_006_RBAC_Privileges_None("1.0") +) def without_privilege(self, table_type, node=None): """Check that user without select privilege on a table is not able to select on that table. """ user_name = f"user_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with user(node, user_name): - with When("I run SELECT without privilege"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {user_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {user_name}") + + with Then("I run SELECT without privilege"): exitcode, message = errors.not_enough_privileges(name=user_name) + node.query(f"SELECT * FROM {table_name}", settings = [("user",user_name)], exitcode=exitcode, message=message) @@ -32,16 +46,52 @@ def user_with_privilege(self, table_type, node=None): """ user_name = f"user_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with Given("I have some data inserted into table"): node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')") + with user(node, user_name): + with When("I grant privilege"): node.query(f"GRANT SELECT ON {table_name} TO {user_name}") + with Then("I verify SELECT command"): user_select = node.query(f"SELECT d FROM {table_name}", settings = [("user",user_name)]) + + default = node.query(f"SELECT d FROM {table_name}") + assert user_select.output == default.output, error() + +@TestScenario +@Requirements( + RQ_SRS_006_RBAC_Privileges_All("1.0") +) +def user_with_all_privilege(self, table_type, node=None): + """Check that user can select from a table if have ALL privilege. + """ + user_name = f"user_{getuid()}" + table_name = f"table_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name, table_type): + + with Given("I have some data inserted into table"): + node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')") + + with user(node, user_name): + + with When("I grant privilege"): + node.query(f"GRANT ALL ON *.* TO {user_name}") + + with Then("I verify SELECT command"): + user_select = node.query(f"SELECT d FROM {table_name}", settings = [("user",user_name)]) + default = node.query(f"SELECT d FROM {table_name}") assert user_select.output == default.output, error() @@ -55,15 +105,47 @@ def user_with_revoked_privilege(self, table_type, node=None): """ user_name = f"user_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with user(node, user_name): + with When("I grant privilege"): node.query(f"GRANT SELECT ON {table_name} TO {user_name}") + with And("I revoke privilege"): node.query(f"REVOKE SELECT ON {table_name} FROM {user_name}") - with And("I use SELECT, throws exception"): + + with Then("I use SELECT, throws exception"): + exitcode, message = errors.not_enough_privileges(name=user_name) + node.query(f"SELECT * FROM {table_name}", settings = [("user",user_name)], + exitcode=exitcode, message=message) + +@TestScenario +def user_with_revoked_all_privilege(self, table_type, node=None): + """Check that user is unable to select from a table after ALL privilege + on that table has been revoked from the user. + """ + user_name = f"user_{getuid()}" + table_name = f"table_{getuid()}" + + if node is None: + node = self.context.node + + with table(node, table_name, table_type): + + with user(node, user_name): + + with When("I grant privilege"): + node.query(f"GRANT SELECT ON {table_name} TO {user_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {user_name}") + + with Then("I use SELECT, throws exception"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"SELECT * FROM {table_name}", settings = [("user",user_name)], exitcode=exitcode, message=message) @@ -90,25 +172,35 @@ def user_column_privileges(self, grant_columns, select_columns_pass, data_pass, """ user_name = f"user_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type), user(node, user_name): + with Given("The table has some data on some columns"): node.query(f"INSERT INTO {table_name} ({select_columns_pass}) VALUES ({data_pass})") + with When("I grant select privilege"): node.query(f"GRANT SELECT({grant_columns}) ON {table_name} TO {user_name}") + if select_columns_fail is not None: + with And("I select from not granted column"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"SELECT ({select_columns_fail}) FROM {table_name}", settings = [("user",user_name)], exitcode=exitcode, message=message) + with Then("I select from granted column, verify correct result"): user_select = node.query(f"SELECT ({select_columns_pass}) FROM {table_name}", settings = [("user",user_name)]) default = node.query(f"SELECT ({select_columns_pass}) FROM {table_name}") assert user_select.output == default.output + if revoke_columns is not None: + with When("I revoke select privilege for columns from user"): node.query(f"REVOKE SELECT({revoke_columns}) ON {table_name} FROM {user_name}") + with And("I select from revoked columns"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"SELECT ({select_columns_pass}) FROM {table_name}", settings = [("user",user_name)], exitcode=exitcode, message=message) @@ -124,17 +216,25 @@ def role_with_privilege(self, table_type, node=None): user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with Given("I have some data inserted into table"): node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')") + with user(node, user_name): + with role(node, role_name): + with When("I grant select privilege to a role"): node.query(f"GRANT SELECT ON {table_name} TO {role_name}") + with And("I grant role to the user"): node.query(f"GRANT {role_name} TO {user_name}") + with Then("I verify SELECT command"): user_select = node.query(f"SELECT d FROM {table_name}", settings = [("user",user_name)]) default = node.query(f"SELECT d FROM {table_name}") @@ -151,16 +251,23 @@ def role_with_revoked_privilege(self, table_type, node=None): user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with user(node, user_name), role(node, role_name): + with When("I grant privilege to a role"): node.query(f"GRANT SELECT ON {table_name} TO {role_name}") + with And("I grant the role to a user"): node.query(f"GRANT {role_name} TO {user_name}") + with And("I revoke privilege from the role"): node.query(f"REVOKE SELECT ON {table_name} FROM {role_name}") + with And("I select from the table"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"SELECT * FROM {table_name}", settings = [("user",user_name)], @@ -174,16 +281,23 @@ def user_with_revoked_role(self, table_type, node=None): user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with user(node, user_name), role(node, role_name): + with When("I grant privilege to a role"): node.query(f"GRANT SELECT ON {table_name} TO {role_name}") + with And("I grant the role to a user"): node.query(f"GRANT {role_name} TO {user_name}") + with And("I revoke the role from the user"): node.query(f"REVOKE {role_name} FROM {user_name}") + with And("I select from the table"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"SELECT * FROM {table_name}", settings = [("user",user_name)], @@ -212,28 +326,39 @@ def role_column_privileges(self, grant_columns, select_columns_pass, data_pass, user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): + with Given("The table has some data on some columns"): node.query(f"INSERT INTO {table_name} ({select_columns_pass}) VALUES ({data_pass})") + with user(node, user_name), role(node, role_name): + with When("I grant select privilege"): node.query(f"GRANT SELECT({grant_columns}) ON {table_name} TO {role_name}") + with And("I grant the role to a user"): node.query(f"GRANT {role_name} TO {user_name}") + if select_columns_fail is not None: with And("I select from not granted column"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"SELECT ({select_columns_fail}) FROM {table_name}", settings = [("user",user_name)], exitcode=exitcode, message=message) + with Then("I verify SELECT command"): user_select = node.query(f"SELECT d FROM {table_name}", settings = [("user",user_name)]) default = node.query(f"SELECT d FROM {table_name}") assert user_select.output == default.output, error() + if revoke_columns is not None: + with When("I revoke select privilege for columns from role"): node.query(f"REVOKE SELECT({revoke_columns}) ON {table_name} FROM {role_name}") + with And("I select from revoked columns"): exitcode, message = errors.not_enough_privileges(name=user_name) node.query(f"SELECT ({select_columns_pass}) FROM {table_name}", @@ -250,20 +375,26 @@ def user_with_privilege_on_cluster(self, table_type, node=None): user_name = f"user_{getuid()}" role_name = f"role_{getuid()}" table_name = f"table_{getuid()}" + if node is None: node = self.context.node + with table(node, table_name, table_type): try: with Given("I have some data inserted into table"): node.query(f"INSERT INTO {table_name} (d) VALUES ('2020-01-01')") + with Given("I have a user on a cluster"): node.query(f"CREATE USER OR REPLACE {user_name} ON CLUSTER sharded_cluster") + with When("I grant select privilege on a cluster"): node.query(f"GRANT ON CLUSTER sharded_cluster SELECT ON {table_name} TO {user_name}") + with Then("I verify SELECT command"): user_select = node.query(f"SELECT d FROM {table_name}", settings = [("user",user_name)]) default = node.query(f"SELECT d FROM {table_name}") assert user_select.output == default.output, error() + finally: with Finally("I drop the user"): node.query(f"DROP USER {user_name} ON CLUSTER sharded_cluster") @@ -291,7 +422,10 @@ def feature(self, table_type, parallel=None, stress=None, node="clickhouse1"): pool = Pool(10) try: - for scenario in loads(current_module(), Scenario): - run_scenario(pool, tasks, Scenario(test=scenario, setup=instrument_clickhouse_server_log), {"table_type" : table_type}) + try: + for scenario in loads(current_module(), Scenario): + run_scenario(pool, tasks, Scenario(test=scenario, setup=instrument_clickhouse_server_log), {"table_type" : table_type}) + finally: + join(tasks) finally: - join(tasks) + pool.close() diff --git a/tests/testflows/rbac/tests/privileges/show/show_columns.py b/tests/testflows/rbac/tests/privileges/show/show_columns.py index 996663cdcbc..108200e7a57 100644 --- a/tests/testflows/rbac/tests/privileges/show/show_columns.py +++ b/tests/testflows/rbac/tests/privileges/show/show_columns.py @@ -18,7 +18,7 @@ def describe_with_privilege_granted_directly(self, node=None): with user(node, f"{user_name}"): table_name = f"table_name_{getuid()}" - Suite(test=describe, setup=instrument_clickhouse_server_log)(grant_target_name=user_name, user_name=user_name, table_name=table_name) + Suite(test=describe)(grant_target_name=user_name, user_name=user_name, table_name=table_name) @TestSuite def describe_with_privilege_granted_via_role(self, node=None): @@ -37,7 +37,7 @@ def describe_with_privilege_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(test=describe, setup=instrument_clickhouse_server_log)(grant_target_name=role_name, user_name=user_name, table_name=table_name) + Suite(test=describe)(grant_target_name=role_name, user_name=user_name, table_name=table_name) @TestSuite @Requirements( @@ -54,11 +54,19 @@ def describe(self, grant_target_name, user_name, table_name, node=None): with table(node, table_name): with Scenario("DESCRIBE table without privilege"): - with When(f"I attempt to DESCRIBE {table_name}"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then(f"I attempt to DESCRIBE {table_name}"): node.query(f"DESCRIBE {table_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) with Scenario("DESCRIBE with privilege"): + with When(f"I grant SHOW COLUMNS on the table"): node.query(f"GRANT SHOW COLUMNS ON {table_name} TO {grant_target_name}") @@ -66,6 +74,7 @@ def describe(self, grant_target_name, user_name, table_name, node=None): node.query(f"DESCRIBE TABLE {table_name}", settings=[("user",user_name)]) with Scenario("DESCRIBE with revoked privilege"): + with When(f"I grant SHOW COLUMNS on the table"): node.query(f"GRANT SHOW COLUMNS ON {table_name} TO {grant_target_name}") @@ -76,6 +85,26 @@ def describe(self, grant_target_name, user_name, table_name, node=None): node.query(f"DESCRIBE {table_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) + with Scenario("DESCRIBE with revoked ALL privilege"): + + with When(f"I grant SHOW COLUMNS on the table"): + node.query(f"GRANT SHOW COLUMNS ON {table_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then(f"I attempt to DESCRIBE {table_name}"): + node.query(f"DESCRIBE {table_name}", settings=[("user",user_name)], + exitcode=exitcode, message=message) + + with Scenario("DESCRIBE with ALL privilege"): + + with When(f"I grant SHOW COLUMNS on the table"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then(f"I attempt to DESCRIBE {table_name}"): + node.query(f"DESCRIBE TABLE {table_name}", settings=[("user",user_name)]) + @TestSuite def show_create_with_privilege_granted_directly(self, node=None): """Check that user is able to execute SHOW CREATE on a table if and only if @@ -89,7 +118,7 @@ def show_create_with_privilege_granted_directly(self, node=None): with user(node, f"{user_name}"): table_name = f"table_name_{getuid()}" - Suite(test=show_create, setup=instrument_clickhouse_server_log)(grant_target_name=user_name, user_name=user_name, table_name=table_name) + Suite(test=show_create)(grant_target_name=user_name, user_name=user_name, table_name=table_name) @TestSuite def show_create_with_privilege_granted_via_role(self, node=None): @@ -108,7 +137,7 @@ def show_create_with_privilege_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(test=show_create, setup=instrument_clickhouse_server_log)(grant_target_name=role_name, user_name=user_name, table_name=table_name) + Suite(test=show_create)(grant_target_name=role_name, user_name=user_name, table_name=table_name) @TestSuite @Requirements( @@ -125,11 +154,19 @@ def show_create(self, grant_target_name, user_name, table_name, node=None): with table(node, table_name): with Scenario("SHOW CREATE without privilege"): - with When(f"I attempt to SHOW CREATE {table_name}"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then(f"I attempt to SHOW CREATE {table_name}"): node.query(f"SHOW CREATE TABLE {table_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) with Scenario("SHOW CREATE with privilege"): + with When(f"I grant SHOW COLUMNS on the table"): node.query(f"GRANT SHOW COLUMNS ON {table_name} TO {grant_target_name}") @@ -137,6 +174,7 @@ def show_create(self, grant_target_name, user_name, table_name, node=None): node.query(f"SHOW CREATE TABLE {table_name}", settings=[("user",user_name)]) with Scenario("SHOW CREATE with revoked privilege"): + with When(f"I grant SHOW COLUMNS on the table"): node.query(f"GRANT SHOW COLUMNS ON {table_name} TO {grant_target_name}") @@ -147,10 +185,20 @@ def show_create(self, grant_target_name, user_name, table_name, node=None): node.query(f"SHOW CREATE TABLE {table_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) + with Scenario("SHOW CREATE with ALL privilege"): + + with When(f"I grant SHOW COLUMNS on the table"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then(f"I attempt to SHOW CREATE {table_name}"): + node.query(f"SHOW CREATE TABLE {table_name}", settings=[("user",user_name)]) + @TestFeature @Name("show columns") @Requirements( - RQ_SRS_006_RBAC_ShowColumns_Privilege("1.0") + RQ_SRS_006_RBAC_ShowColumns_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SHOW COLUMNS. diff --git a/tests/testflows/rbac/tests/privileges/show/show_databases.py b/tests/testflows/rbac/tests/privileges/show/show_databases.py index 27d10ef2b73..39a46947afe 100644 --- a/tests/testflows/rbac/tests/privileges/show/show_databases.py +++ b/tests/testflows/rbac/tests/privileges/show/show_databases.py @@ -20,7 +20,7 @@ def dict_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): db_name = f"db_name_{getuid()}" - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name db_name", [ tuple(list(row)+[user_name,user_name,db_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -44,13 +44,14 @@ def dict_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name db_name", [ tuple(list(row)+[role_name,user_name,db_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SHOW","*.*"), ("SHOW DATABASES","db"), ("CREATE DATABASE","db"), @@ -65,9 +66,9 @@ def check_privilege(self, privilege, on, grant_target_name, user_name, db_name, on = on.replace("db", f"{db_name}") - Suite(test=show_db, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, db_name=db_name) - Suite(test=use, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, db_name=db_name) - Suite(test=show_create, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, db_name=db_name) + Suite(test=show_db)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, db_name=db_name) + Suite(test=use)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, db_name=db_name) + Suite(test=show_create)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, db_name=db_name) @TestSuite @Requirements( @@ -83,14 +84,23 @@ def show_db(self, privilege, on, grant_target_name, user_name, db_name, node=Non try: with Given("I have a database"): + node.query(f"CREATE DATABASE {db_name}") with Scenario("SHOW DATABASES without privilege"): - with When("I check the user doesn't see the database"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user doesn't see the database"): output = node.query("SHOW DATABASES", settings = [("user", f"{user_name}")]).output assert output == '', error() with Scenario("SHOW DATABASES with privilege"): + with When(f"I grant {privilege} on the database"): node.query(f"GRANT {privilege} ON {db_name}.* TO {grant_target_name}") @@ -98,6 +108,7 @@ def show_db(self, privilege, on, grant_target_name, user_name, db_name, node=Non output = node.query("SHOW DATABASES", settings = [("user", f"{user_name}")], message = f'{db_name}') with Scenario("SHOW DATABASES with revoked privilege"): + with When(f"I grant {privilege} on the database"): node.query(f"GRANT {privilege} ON {db_name}.* TO {grant_target_name}") @@ -130,11 +141,19 @@ def use(self, privilege, on, grant_target_name, user_name, db_name, node=None): node.query(f"CREATE DATABASE {db_name}") with Scenario("USE without privilege"): - with When(f"I attempt to USE {db_name}"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then(f"I attempt to USE {db_name}"): node.query(f"USE {db_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) with Scenario("USE with privilege"): + with When(f"I grant {privilege} on the database"): node.query(f"GRANT {privilege} ON {db_name}.* TO {grant_target_name}") @@ -142,6 +161,7 @@ def use(self, privilege, on, grant_target_name, user_name, db_name, node=None): node.query(f"USE {db_name}", settings=[("user",user_name)]) with Scenario("USE with revoked privilege"): + with When(f"I grant {privilege} on the database"): node.query(f"GRANT {privilege} ON {db_name}.* TO {grant_target_name}") @@ -174,11 +194,19 @@ def show_create(self, privilege, on, grant_target_name, user_name, db_name, node node.query(f"CREATE DATABASE {db_name}") with Scenario("SHOW CREATE without privilege"): - with When(f"I attempt to SHOW CREATE {db_name}"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then(f"I attempt to SHOW CREATE {db_name}"): node.query(f"SHOW CREATE DATABASE {db_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) with Scenario("SHOW CREATE with privilege"): + with When(f"I grant {privilege} on the database"): node.query(f"GRANT {privilege} ON {db_name}.* TO {grant_target_name}") @@ -186,6 +214,7 @@ def show_create(self, privilege, on, grant_target_name, user_name, db_name, node node.query(f"SHOW CREATE DATABASE {db_name}", settings=[("user",user_name)]) with Scenario("SHOW CREATE with revoked privilege"): + with When(f"I grant {privilege} on the database"): node.query(f"GRANT {privilege} ON {db_name}.* TO {grant_target_name}") @@ -203,7 +232,9 @@ def show_create(self, privilege, on, grant_target_name, user_name, db_name, node @TestFeature @Name("show databases") @Requirements( - RQ_SRS_006_RBAC_ShowDatabases_Privilege("1.0") + RQ_SRS_006_RBAC_ShowDatabases_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SHOW DATABASES. diff --git a/tests/testflows/rbac/tests/privileges/show/show_dictionaries.py b/tests/testflows/rbac/tests/privileges/show/show_dictionaries.py index ec5617af904..5b717b5f47c 100644 --- a/tests/testflows/rbac/tests/privileges/show/show_dictionaries.py +++ b/tests/testflows/rbac/tests/privileges/show/show_dictionaries.py @@ -20,7 +20,7 @@ def dict_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): dict_name = f"dict_name_{getuid()}" - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name dict_name", [ tuple(list(row)+[user_name,user_name,dict_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -44,13 +44,14 @@ def dict_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name dict_name", [ tuple(list(row)+[role_name,user_name,dict_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SHOW","*.*"), ("SHOW DICTIONARIES","dict"), ("CREATE DICTIONARY","dict"), @@ -65,9 +66,9 @@ def check_privilege(self, privilege, on, grant_target_name, user_name, dict_name on = on.replace("dict", f"{dict_name}") - Suite(test=show_dict, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, dict_name=dict_name) - Suite(test=exists, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, dict_name=dict_name) - Suite(test=show_create, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, dict_name=dict_name) + Suite(test=show_dict)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, dict_name=dict_name) + Suite(test=exists)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, dict_name=dict_name) + Suite(test=show_create)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, dict_name=dict_name) @TestSuite @Requirements( @@ -87,7 +88,14 @@ def show_dict(self, privilege, on, grant_target_name, user_name, dict_name, node node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)") with Scenario("SHOW DICTIONARIES without privilege"): - with When("I check the user doesn't see the dictionary"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user doesn't see the dictionary"): output = node.query("SHOW DICTIONARIES", settings = [("user", f"{user_name}")]).output assert output == '', error() @@ -131,7 +139,14 @@ def exists(self, privilege, on, grant_target_name, user_name, dict_name, node=No node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)") with Scenario("EXISTS without privilege"): - with When(f"I check if {dict_name} EXISTS"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then(f"I check if {dict_name} EXISTS"): node.query(f"EXISTS {dict_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -175,7 +190,14 @@ def show_create(self, privilege, on, grant_target_name, user_name, dict_name, no node.query(f"CREATE DICTIONARY {dict_name}(x Int32, y Int32) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE()) LIFETIME(0)") with Scenario("SHOW CREATE without privilege"): - with When(f"I attempt to SHOW CREATE {dict_name}"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then(f"I attempt to SHOW CREATE {dict_name}"): node.query(f"SHOW CREATE DICTIONARY {dict_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -205,6 +227,8 @@ def show_create(self, privilege, on, grant_target_name, user_name, dict_name, no @Name("show dictionaries") @Requirements( RQ_SRS_006_RBAC_ShowDictionaries_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SHOW DICTIONARIES. diff --git a/tests/testflows/rbac/tests/privileges/show/show_quotas.py b/tests/testflows/rbac/tests/privileges/show/show_quotas.py index d84b5192677..20476ae759b 100644 --- a/tests/testflows/rbac/tests/privileges/show/show_quotas.py +++ b/tests/testflows/rbac/tests/privileges/show/show_quotas.py @@ -29,7 +29,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -50,13 +50,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("SHOW ACCESS",), ("SHOW QUOTAS",), @@ -69,8 +70,8 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None): if node is None: node = self.context.node - Suite(test=show_quotas, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) - Suite(test=show_create, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_quotas)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_create)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) @TestSuite @Requirements( @@ -86,7 +87,13 @@ def show_quotas(self, privilege, grant_target_name, user_name, node=None): with Scenario("SHOW QUOTAS without privilege"): - with When("I check the user can't use SHOW QUOTAS"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW QUOTAS"): node.query(f"SHOW QUOTAS", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -127,7 +134,13 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): with quota(node, target_quota_name): - with When("I check the user can't use SHOW CREATE QUOTA"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW CREATE QUOTA"): node.query(f"SHOW CREATE QUOTA {target_quota_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -161,6 +174,8 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): @Name("show quotas") @Requirements( RQ_SRS_006_RBAC_ShowQuotas_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SHOW QUOTAS. diff --git a/tests/testflows/rbac/tests/privileges/show/show_roles.py b/tests/testflows/rbac/tests/privileges/show/show_roles.py index 3106e1c5df3..14d038102dd 100644 --- a/tests/testflows/rbac/tests/privileges/show/show_roles.py +++ b/tests/testflows/rbac/tests/privileges/show/show_roles.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("SHOW ACCESS",), ("SHOW ROLES",), @@ -57,8 +58,8 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None): if node is None: node = self.context.node - Suite(test=show_roles, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) - Suite(test=show_create, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_roles)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_create)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) @TestSuite @Requirements( @@ -74,7 +75,13 @@ def show_roles(self, privilege, grant_target_name, user_name, node=None): with Scenario("SHOW ROLES without privilege"): - with When("I check the user can't use SHOW ROLES"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW ROLES"): node.query(f"SHOW ROLES", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -115,7 +122,13 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): with role(node, target_role_name): - with When("I check the user can't use SHOW CREATE ROLE"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW CREATE ROLE"): node.query(f"SHOW CREATE ROLE {target_role_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -149,6 +162,8 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): @Name("show roles") @Requirements( RQ_SRS_006_RBAC_ShowRoles_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SHOW ROLES. diff --git a/tests/testflows/rbac/tests/privileges/show/show_row_policies.py b/tests/testflows/rbac/tests/privileges/show/show_row_policies.py index cfa25284cee..789c4c95223 100644 --- a/tests/testflows/rbac/tests/privileges/show/show_row_policies.py +++ b/tests/testflows/rbac/tests/privileges/show/show_row_policies.py @@ -29,7 +29,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -50,13 +50,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("SHOW ACCESS",), ("SHOW ROW POLICIES",), @@ -71,8 +72,8 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None): if node is None: node = self.context.node - Suite(test=show_row_policies, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) - Suite(test=show_create, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_row_policies)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_create)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) @TestSuite @Requirements( @@ -88,7 +89,13 @@ def show_row_policies(self, privilege, grant_target_name, user_name, node=None): with Scenario("SHOW ROW POLICIES without privilege"): - with When("I check the user can't use SHOW ROW POLICIES"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW ROW POLICIES"): node.query(f"SHOW ROW POLICIES", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -130,7 +137,13 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): with row_policy(node, target_row_policy_name, table_name): - with When("I check the user can't use SHOW CREATE ROW POLICY"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW CREATE ROW POLICY"): node.query(f"SHOW CREATE ROW POLICY {target_row_policy_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -166,6 +179,8 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): @Name("show row policies") @Requirements( RQ_SRS_006_RBAC_ShowRowPolicies_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SHOW ROW POLICYS. diff --git a/tests/testflows/rbac/tests/privileges/show/show_settings_profiles.py b/tests/testflows/rbac/tests/privileges/show/show_settings_profiles.py index 8c29a7f462e..18ca0ee7f6e 100644 --- a/tests/testflows/rbac/tests/privileges/show/show_settings_profiles.py +++ b/tests/testflows/rbac/tests/privileges/show/show_settings_profiles.py @@ -29,7 +29,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -50,13 +50,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("SHOW ACCESS",), ("SHOW SETTINGS PROFILES",), @@ -71,8 +72,8 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None): if node is None: node = self.context.node - Suite(test=show_settings_profiles, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) - Suite(test=show_create, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_settings_profiles)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_create)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) @TestSuite @Requirements( @@ -88,7 +89,13 @@ def show_settings_profiles(self, privilege, grant_target_name, user_name, node=N with Scenario("SHOW SETTINGS PROFILES without privilege"): - with When("I check the user can't use SHOW SETTINGS PROFILES"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW SETTINGS PROFILES"): node.query(f"SHOW SETTINGS PROFILES", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -129,7 +136,13 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): with settings_profile(node, target_settings_profile_name): - with When("I check the user can't use SHOW CREATE SETTINGS PROFILE"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW CREATE SETTINGS PROFILE"): node.query(f"SHOW CREATE SETTINGS PROFILE {target_settings_profile_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -163,6 +176,8 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): @Name("show settings profiles") @Requirements( RQ_SRS_006_RBAC_ShowSettingsProfiles_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SHOW SETTINGS PROFILES. diff --git a/tests/testflows/rbac/tests/privileges/show/show_tables.py b/tests/testflows/rbac/tests/privileges/show/show_tables.py index 913b64cef69..d445550c032 100755 --- a/tests/testflows/rbac/tests/privileges/show/show_tables.py +++ b/tests/testflows/rbac/tests/privileges/show/show_tables.py @@ -20,7 +20,7 @@ def table_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): table_name = f"table_name_{getuid()}" - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[user_name,user_name,table_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -44,13 +44,14 @@ def table_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[role_name,user_name,table_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SHOW", "*.*"), ("SHOW TABLES", "table"), ("SELECT", "table"), @@ -67,9 +68,9 @@ def check_privilege(self, privilege, on, grant_target_name, user_name, table_nam if node is None: node = self.context.node - Suite(test=show_tables, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) - Suite(test=exists, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) - Suite(test=check, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=show_tables)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=exists)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=check)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) @TestSuite @Requirements( @@ -88,11 +89,19 @@ def show_tables(self, privilege, on, grant_target_name, user_name, table_name, n with table(node, table_name): with Scenario("SHOW TABLES without privilege"): - with When("I check the user doesn't see the table"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user doesn't see the table"): output = node.query("SHOW TABLES", settings = [("user", f"{user_name}")]).output assert output == '', error() with Scenario("SHOW TABLES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -100,6 +109,7 @@ def show_tables(self, privilege, on, grant_target_name, user_name, table_name, n node.query("SHOW TABLES", settings = [("user", f"{user_name}")], message=f"{table_name}") with Scenario("SHOW TABLES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -127,12 +137,21 @@ def exists(self, privilege, on, grant_target_name, user_name, table_name, node=N on = f"{table_name}" with table(node, table_name): + with Scenario("EXISTS without privilege"): - with When(f"I check if {table_name} EXISTS"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then(f"I check if {table_name} EXISTS"): node.query(f"EXISTS {table_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) with Scenario("EXISTS with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -140,6 +159,7 @@ def exists(self, privilege, on, grant_target_name, user_name, table_name, node=N node.query(f"EXISTS {table_name}", settings=[("user",user_name)]) with Scenario("EXISTS with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -167,12 +187,21 @@ def check(self, privilege, on, grant_target_name, user_name, table_name, node=No on = f"{table_name}" with table(node, table_name): + with Scenario("CHECK without privilege"): - with When(f"I CHECK {table_name}"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then(f"I CHECK {table_name}"): node.query(f"CHECK TABLE {table_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) with Scenario("CHECK with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -180,6 +209,7 @@ def check(self, privilege, on, grant_target_name, user_name, table_name, node=No node.query(f"CHECK TABLE {table_name}", settings=[("user",user_name)]) with Scenario("CHECK with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -194,6 +224,8 @@ def check(self, privilege, on, grant_target_name, user_name, table_name, node=No @Name("show tables") @Requirements( RQ_SRS_006_RBAC_ShowTables_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SHOW TABLES. diff --git a/tests/testflows/rbac/tests/privileges/show/show_users.py b/tests/testflows/rbac/tests/privileges/show/show_users.py index 48e6ba51f48..aa5c97297b5 100644 --- a/tests/testflows/rbac/tests/privileges/show/show_users.py +++ b/tests/testflows/rbac/tests/privileges/show/show_users.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("ACCESS MANAGEMENT",), ("SHOW ACCESS",), ("SHOW USERS",), @@ -57,8 +58,8 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None): if node is None: node = self.context.node - Suite(test=show_users, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) - Suite(test=show_create, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_users)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=show_create)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) @TestSuite @Requirements( @@ -74,7 +75,13 @@ def show_users(self, privilege, grant_target_name, user_name, node=None): with Scenario("SHOW USERS without privilege"): - with When("I check the user can't use SHOW USERS"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW USERS"): node.query(f"SHOW USERS", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -115,7 +122,13 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): with user(node, target_user_name): - with When("I check the user can't use SHOW CREATE USER"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SHOW CREATE USER"): node.query(f"SHOW CREATE USER {target_user_name}", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -149,6 +162,8 @@ def show_create(self, privilege, grant_target_name, user_name, node=None): @Name("show users") @Requirements( RQ_SRS_006_RBAC_ShowUsers_Privilege("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SHOW USERS. diff --git a/tests/testflows/rbac/tests/privileges/sources.py b/tests/testflows/rbac/tests/privileges/sources.py index 8c1b61ee401..19d32cf500a 100644 --- a/tests/testflows/rbac/tests/privileges/sources.py +++ b/tests/testflows/rbac/tests/privileges/sources.py @@ -17,7 +17,7 @@ def file_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=file, flags=TE, + Suite(run=file, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in file.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def file_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=file, flags=TE, + Suite(run=file, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in file.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("SOURCES",), ("FILE",), ]) @@ -65,7 +66,13 @@ def file(self, privilege, grant_target_name, user_name, node=None): with Given("The user has table privilege"): node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}") - with When("I check the user can't use the File source"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use the File source"): node.query(f"CREATE TABLE {table_name} (x String) ENGINE=File()", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -102,7 +109,7 @@ def url_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=url, flags=TE, + Suite(run=url, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in url.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -123,13 +130,14 @@ def url_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=url, flags=TE, + Suite(run=url, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in url.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("SOURCES",), ("URL",), ]) @@ -150,7 +158,13 @@ def url(self, privilege, grant_target_name, user_name, node=None): with Given("The user has table privilege"): node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}") - with When("I check the user can't use the URL source"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use the URL source"): node.query(f"CREATE TABLE {table_name} (x String) ENGINE=URL()", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -187,7 +201,7 @@ def remote_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=remote, flags=TE, + Suite(run=remote, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in remote.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -208,13 +222,14 @@ def remote_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=remote, flags=TE, + Suite(run=remote, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in remote.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("SOURCES",), ("REMOTE",), ]) @@ -235,7 +250,13 @@ def remote(self, privilege, grant_target_name, user_name, node=None): with Given("The user has table privilege"): node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}") - with When("I check the user can't use the Remote source"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use the Remote source"): node.query(f"CREATE TABLE {table_name} (x String) ENGINE = Distributed()", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -272,7 +293,7 @@ def MySQL_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=MySQL, flags=TE, + Suite(run=MySQL, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in MySQL.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -293,13 +314,14 @@ def MySQL_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=MySQL, flags=TE, + Suite(run=MySQL, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in MySQL.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("SOURCES",), ("MYSQL",), ]) @@ -320,7 +342,13 @@ def MySQL(self, privilege, grant_target_name, user_name, node=None): with Given("The user has table privilege"): node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}") - with When("I check the user can't use the MySQL source"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use the MySQL source"): node.query(f"CREATE TABLE {table_name} (x String) ENGINE=MySQL()", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -357,7 +385,7 @@ def ODBC_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=ODBC, flags=TE, + Suite(run=ODBC, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in ODBC.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -378,13 +406,14 @@ def ODBC_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=ODBC, flags=TE, + Suite(run=ODBC, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in ODBC.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("SOURCES",), ("ODBC",), ]) @@ -405,7 +434,13 @@ def ODBC(self, privilege, grant_target_name, user_name, node=None): with Given("The user has table privilege"): node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}") - with When("I check the user can't use the ODBC source"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use the ODBC source"): node.query(f"CREATE TABLE {table_name} (x String) ENGINE=ODBC()", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -442,7 +477,7 @@ def JDBC_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=JDBC, flags=TE, + Suite(run=JDBC, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in JDBC.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -463,13 +498,14 @@ def JDBC_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=JDBC, flags=TE, + Suite(run=JDBC, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in JDBC.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("SOURCES",), ("JDBC",), ]) @@ -490,7 +526,13 @@ def JDBC(self, privilege, grant_target_name, user_name, node=None): with Given("The user has table privilege"): node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}") - with When("I check the user can't use the JDBC source"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use the JDBC source"): node.query(f"CREATE TABLE {table_name} (x String) ENGINE=JDBC()", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -527,7 +569,7 @@ def HDFS_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=HDFS, flags=TE, + Suite(run=HDFS, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in HDFS.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -548,13 +590,14 @@ def HDFS_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=HDFS, flags=TE, + Suite(run=HDFS, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in HDFS.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("SOURCES",), ("HDFS",), ]) @@ -575,7 +618,13 @@ def HDFS(self, privilege, grant_target_name, user_name, node=None): with Given("The user has table privilege"): node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}") - with When("I check the user can't use the HDFS source"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use the HDFS source"): node.query(f"CREATE TABLE {table_name} (x String) ENGINE=HDFS()", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -612,7 +661,7 @@ def S3_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=S3, flags=TE, + Suite(run=S3, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in S3.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -633,13 +682,14 @@ def S3_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=S3, flags=TE, + Suite(run=S3, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in S3.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("SOURCES",), ("S3",), ]) @@ -660,7 +710,13 @@ def S3(self, privilege, grant_target_name, user_name, node=None): with Given("The user has table privilege"): node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}") - with When("I check the user can't use the S3 source"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use the S3 source"): node.query(f"CREATE TABLE {table_name} (x String) ENGINE=S3()", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -689,6 +745,8 @@ def S3(self, privilege, grant_target_name, user_name, node=None): @Name("sources") @Requirements( RQ_SRS_006_RBAC_Privileges_Sources("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SOURCES. diff --git a/tests/testflows/rbac/tests/privileges/system/drop_cache.py b/tests/testflows/rbac/tests/privileges/system/drop_cache.py index 6439beb248d..8f1a6caeaac 100644 --- a/tests/testflows/rbac/tests/privileges/system/drop_cache.py +++ b/tests/testflows/rbac/tests/privileges/system/drop_cache.py @@ -17,7 +17,7 @@ def dns_cache_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=dns_cache, flags=TE, + Suite(run=dns_cache, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in dns_cache.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,7 +38,7 @@ def dns_cache_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=dns_cache, flags=TE, + Suite(run=dns_cache, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in dns_cache.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -48,6 +48,7 @@ def dns_cache_privileges_granted_via_role(self, node=None): RQ_SRS_006_RBAC_Privileges_System_DropCache_DNS("1.0"), ) @Examples("privilege",[ + ("ALL",), ("SYSTEM",), ("SYSTEM DROP CACHE",), ("SYSTEM DROP DNS CACHE",), @@ -65,11 +66,19 @@ def dns_cache(self, privilege, grant_target_name, user_name, node=None): node = self.context.node with Scenario("SYSTEM DROP DNS CACHE without privilege"): - with When("I check the user is unable to execute SYSTEM DROP DNS CACHE"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user is unable to execute SYSTEM DROP DNS CACHE"): node.query("SYSTEM DROP DNS CACHE", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM DROP DNS CACHE with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -77,6 +86,7 @@ def dns_cache(self, privilege, grant_target_name, user_name, node=None): node.query("SYSTEM DROP DNS CACHE", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM DROP DNS CACHE with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -99,7 +109,7 @@ def mark_cache_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=mark_cache, flags=TE, + Suite(run=mark_cache, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in mark_cache.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -120,7 +130,7 @@ def mark_cache_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=mark_cache, flags=TE, + Suite(run=mark_cache, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in mark_cache.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -130,6 +140,7 @@ def mark_cache_privileges_granted_via_role(self, node=None): RQ_SRS_006_RBAC_Privileges_System_DropCache_Mark("1.0"), ) @Examples("privilege",[ + ("ALL",), ("SYSTEM",), ("SYSTEM DROP CACHE",), ("SYSTEM DROP MARK CACHE",), @@ -147,11 +158,19 @@ def mark_cache(self, privilege, grant_target_name, user_name, node=None): node = self.context.node with Scenario("SYSTEM DROP MARK CACHE without privilege"): - with When("I check the user is unable to execute SYSTEM DROP MARK CACHE"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user is unable to execute SYSTEM DROP MARK CACHE"): node.query("SYSTEM DROP MARK CACHE", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM DROP MARK CACHE with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -159,6 +178,7 @@ def mark_cache(self, privilege, grant_target_name, user_name, node=None): node.query("SYSTEM DROP MARK CACHE", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM DROP MARK CACHE with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -181,7 +201,7 @@ def uncompressed_cache_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=uncompressed_cache, flags=TE, + Suite(run=uncompressed_cache, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in uncompressed_cache.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -202,7 +222,7 @@ def uncompressed_cache_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=uncompressed_cache, flags=TE, + Suite(run=uncompressed_cache, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in uncompressed_cache.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -212,6 +232,7 @@ def uncompressed_cache_privileges_granted_via_role(self, node=None): RQ_SRS_006_RBAC_Privileges_System_DropCache_Uncompressed("1.0"), ) @Examples("privilege",[ + ("ALL",), ("SYSTEM",), ("SYSTEM DROP CACHE",), ("SYSTEM DROP UNCOMPRESSED CACHE",), @@ -229,11 +250,19 @@ def uncompressed_cache(self, privilege, grant_target_name, user_name, node=None) node = self.context.node with Scenario("SYSTEM DROP UNCOMPRESSED CACHE without privilege"): - with When("I check the user is unable to execute SYSTEM DROP UNCOMPRESSED CACHE"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user is unable to execute SYSTEM DROP UNCOMPRESSED CACHE"): node.query("SYSTEM DROP UNCOMPRESSED CACHE", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM DROP UNCOMPRESSED CACHE with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -241,6 +270,7 @@ def uncompressed_cache(self, privilege, grant_target_name, user_name, node=None) node.query("SYSTEM DROP UNCOMPRESSED CACHE", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM DROP UNCOMPRESSED CACHE with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -255,6 +285,8 @@ def uncompressed_cache(self, privilege, grant_target_name, user_name, node=None) @Name("system drop cache") @Requirements( RQ_SRS_006_RBAC_Privileges_System_DropCache("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM DROP CACHE. diff --git a/tests/testflows/rbac/tests/privileges/system/fetches.py b/tests/testflows/rbac/tests/privileges/system/fetches.py index 14c046f4fbe..3aba1b71566 100644 --- a/tests/testflows/rbac/tests/privileges/system/fetches.py +++ b/tests/testflows/rbac/tests/privileges/system/fetches.py @@ -17,7 +17,7 @@ def replicated_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=check_replicated_privilege, flags=TE, + Suite(run=check_replicated_privilege, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in check_replicated_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def replicated_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_replicated_privilege, flags=TE, + Suite(run=check_replicated_privilege, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in check_replicated_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM FETCHES", "table"), ("SYSTEM STOP FETCHES", "table"), @@ -59,8 +60,8 @@ def check_replicated_privilege(self, privilege, on, grant_target_name, user_name if node is None: node = self.context.node - Suite(test=start_replication_queues, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) - Suite(test=stop_replication_queues, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=start_replication_queues)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=stop_replication_queues)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) @TestSuite def start_replication_queues(self, privilege, on, grant_target_name, user_name, node=None): @@ -77,11 +78,19 @@ def start_replication_queues(self, privilege, on, grant_target_name, user_name, with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"): with Scenario("SYSTEM START FETCHES without privilege"): - with When("I check the user can't start fetches"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't start fetches"): node.query(f"SYSTEM START FETCHES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM START FETCHES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -89,6 +98,7 @@ def start_replication_queues(self, privilege, on, grant_target_name, user_name, node.query(f"SYSTEM START FETCHES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM START FETCHES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -114,11 +124,19 @@ def stop_replication_queues(self, privilege, on, grant_target_name, user_name, n with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"): with Scenario("SYSTEM STOP FETCHES without privilege"): - with When("I check the user can't stop fetches"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't stop fetches"): node.query(f"SYSTEM STOP FETCHES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM STOP FETCHES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -126,6 +144,7 @@ def stop_replication_queues(self, privilege, on, grant_target_name, user_name, n node.query(f"SYSTEM STOP FETCHES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM STOP FETCHES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -140,6 +159,8 @@ def stop_replication_queues(self, privilege, on, grant_target_name, user_name, n @Name("system fetches") @Requirements( RQ_SRS_006_RBAC_Privileges_System_Fetches("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM FETCHES. diff --git a/tests/testflows/rbac/tests/privileges/system/flush.py b/tests/testflows/rbac/tests/privileges/system/flush.py index 8835b51db9e..8c540fa1286 100644 --- a/tests/testflows/rbac/tests/privileges/system/flush.py +++ b/tests/testflows/rbac/tests/privileges/system/flush.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=flush_logs, flags=TE, + Suite(run=flush_logs, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in flush_logs.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=flush_logs, flags=TE, + Suite(run=flush_logs, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in flush_logs.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM FLUSH", "*.*"), ("SYSTEM FLUSH LOGS", "*.*"), @@ -62,11 +63,19 @@ def flush_logs(self, privilege, on, grant_target_name, user_name, node=None): node = self.context.node with Scenario("SYSTEM FLUSH LOGS without privilege"): - with When("I check the user can't flush logs"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't flush logs"): node.query(f"SYSTEM FLUSH LOGS", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM FLUSH LOGS with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -74,6 +83,7 @@ def flush_logs(self, privilege, on, grant_target_name, user_name, node=None): node.query(f"SYSTEM FLUSH LOGS", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM FLUSH LOGS with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -97,7 +107,7 @@ def distributed_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): table_name = f"table_name_{getuid()}" - Suite(run=flush_distributed, flags=TE, + Suite(run=flush_distributed, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[user_name,user_name,table_name]) for row in flush_distributed.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -119,13 +129,14 @@ def distributed_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=flush_distributed, flags=TE, + Suite(run=flush_distributed, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[role_name,user_name,table_name]) for row in flush_distributed.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM FLUSH", "*.*"), ("SYSTEM FLUSH DISTRIBUTED", "table"), @@ -151,11 +162,19 @@ def flush_distributed(self, privilege, on, grant_target_name, user_name, table_n node.query(f"CREATE TABLE {table_name} (a UInt64) ENGINE = Distributed(sharded_cluster, default, {table0_name}, rand())") with Scenario("SYSTEM FLUSH DISTRIBUTED without privilege"): - with When("I check the user can't flush distributed"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't flush distributed"): node.query(f"SYSTEM FLUSH DISTRIBUTED {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM FLUSH DISTRIBUTED with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -163,6 +182,7 @@ def flush_distributed(self, privilege, on, grant_target_name, user_name, table_n node.query(f"SYSTEM FLUSH DISTRIBUTED {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM FLUSH DISTRIBUTED with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -182,6 +202,8 @@ def flush_distributed(self, privilege, on, grant_target_name, user_name, table_n @Name("system flush") @Requirements( RQ_SRS_006_RBAC_Privileges_System_Flush("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM FLUSH. diff --git a/tests/testflows/rbac/tests/privileges/system/merges.py b/tests/testflows/rbac/tests/privileges/system/merges.py index 0f347299c44..324b9c0b4ec 100644 --- a/tests/testflows/rbac/tests/privileges/system/merges.py +++ b/tests/testflows/rbac/tests/privileges/system/merges.py @@ -18,7 +18,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): table_name = f"table_name_{getuid()}" - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[user_name,user_name,table_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -40,13 +40,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[role_name,user_name,table_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM MERGES", "table"), ("SYSTEM STOP MERGES", "table"), @@ -61,8 +62,8 @@ def check_privilege(self, privilege, on, grant_target_name, user_name, table_nam if node is None: node = self.context.node - Suite(test=start_merges, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) - Suite(test=stop_merges, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=start_merges)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=stop_merges)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) @TestSuite def start_merges(self, privilege, on, grant_target_name, user_name, table_name, node=None): @@ -78,11 +79,19 @@ def start_merges(self, privilege, on, grant_target_name, user_name, table_name, with table(node, table_name): with Scenario("SYSTEM START MERGES without privilege"): - with When("I check the user can't start merges"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't start merges"): node.query(f"SYSTEM START MERGES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM START MERGES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -90,6 +99,7 @@ def start_merges(self, privilege, on, grant_target_name, user_name, table_name, node.query(f"SYSTEM START MERGES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM START MERGES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -114,11 +124,19 @@ def stop_merges(self, privilege, on, grant_target_name, user_name, table_name, n with table(node, table_name): with Scenario("SYSTEM STOP MERGES without privilege"): - with When("I check the user can't stop merges"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't stop merges"): node.query(f"SYSTEM STOP MERGES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM STOP MERGES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -126,6 +144,7 @@ def stop_merges(self, privilege, on, grant_target_name, user_name, table_name, n node.query(f"SYSTEM STOP MERGES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM STOP MERGES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -140,6 +159,8 @@ def stop_merges(self, privilege, on, grant_target_name, user_name, table_name, n @Name("system merges") @Requirements( RQ_SRS_006_RBAC_Privileges_System_Merges("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM MERGES. diff --git a/tests/testflows/rbac/tests/privileges/system/moves.py b/tests/testflows/rbac/tests/privileges/system/moves.py index 2081e6dfe22..2a75ff39aaf 100644 --- a/tests/testflows/rbac/tests/privileges/system/moves.py +++ b/tests/testflows/rbac/tests/privileges/system/moves.py @@ -18,7 +18,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): table_name = f"table_name_{getuid()}" - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[user_name,user_name,table_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -40,13 +40,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[role_name,user_name,table_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM MOVES", "table"), ("SYSTEM STOP MOVES", "table"), @@ -61,8 +62,8 @@ def check_privilege(self, privilege, on, grant_target_name, user_name, table_nam if node is None: node = self.context.node - Suite(test=start_moves, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) - Suite(test=stop_moves, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=start_moves)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=stop_moves)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) @TestSuite def start_moves(self, privilege, on, grant_target_name, user_name, table_name, node=None): @@ -78,11 +79,19 @@ def start_moves(self, privilege, on, grant_target_name, user_name, table_name, n with table(node, table_name): with Scenario("SYSTEM START MOVES without privilege"): - with When("I check the user can't start moves"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't start moves"): node.query(f"SYSTEM START MOVES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM START MOVES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -90,6 +99,7 @@ def start_moves(self, privilege, on, grant_target_name, user_name, table_name, n node.query(f"SYSTEM START MOVES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM START MOVES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -114,11 +124,19 @@ def stop_moves(self, privilege, on, grant_target_name, user_name, table_name, no with table(node, table_name): with Scenario("SYSTEM STOP MOVES without privilege"): - with When("I check the user can't stop moves"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't stop moves"): node.query(f"SYSTEM STOP MOVES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM STOP MOVES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -126,6 +144,7 @@ def stop_moves(self, privilege, on, grant_target_name, user_name, table_name, no node.query(f"SYSTEM STOP MOVES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM STOP MOVES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -140,6 +159,8 @@ def stop_moves(self, privilege, on, grant_target_name, user_name, table_name, no @Name("system moves") @Requirements( RQ_SRS_006_RBAC_Privileges_System_Moves("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM MOVES. diff --git a/tests/testflows/rbac/tests/privileges/system/reload.py b/tests/testflows/rbac/tests/privileges/system/reload.py index cfc752fb253..bb8f91a0dd4 100644 --- a/tests/testflows/rbac/tests/privileges/system/reload.py +++ b/tests/testflows/rbac/tests/privileges/system/reload.py @@ -38,7 +38,7 @@ def config_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=config, flags=TE, + Suite(run=config, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in config.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -59,7 +59,7 @@ def config_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=config, flags=TE, + Suite(run=config, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in config.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -69,6 +69,7 @@ def config_privileges_granted_via_role(self, node=None): RQ_SRS_006_RBAC_Privileges_System_Reload_Config("1.0"), ) @Examples("privilege",[ + ("ALL",), ("SYSTEM",), ("SYSTEM RELOAD",), ("SYSTEM RELOAD CONFIG",), @@ -83,11 +84,19 @@ def config(self, privilege, grant_target_name, user_name, node=None): node = self.context.node with Scenario("SYSTEM RELOAD CONFIG without privilege"): - with When("I check the user is unable to execute SYSTEM RELOAD CONFIG"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user is unable to execute SYSTEM RELOAD CONFIG"): node.query("SYSTEM RELOAD CONFIG", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM RELOAD CONFIG with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -95,6 +104,7 @@ def config(self, privilege, grant_target_name, user_name, node=None): node.query("SYSTEM RELOAD CONFIG", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM RELOAD CONFIG with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -117,7 +127,7 @@ def dictionary_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=dictionary, flags=TE, + Suite(run=dictionary, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in dictionary.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -138,7 +148,7 @@ def dictionary_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=dictionary, flags=TE, + Suite(run=dictionary, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in dictionary.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -148,6 +158,7 @@ def dictionary_privileges_granted_via_role(self, node=None): RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionary("1.0"), ) @Examples("privilege",[ + ("ALL",), ("SYSTEM",), ("SYSTEM RELOAD",), ("SYSTEM RELOAD DICTIONARIES",), @@ -163,16 +174,24 @@ def dictionary(self, privilege, grant_target_name, user_name, node=None): node = self.context.node with Scenario("SYSTEM RELOAD DICTIONARY without privilege"): + dict_name = f"dict_{getuid()}" table_name = f"table_{getuid()}" with dict_setup(node, table_name, dict_name): - with When("I check the user is unable to execute SYSTEM RELOAD DICTIONARY"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user is unable to execute SYSTEM RELOAD DICTIONARY"): node.query(f"SYSTEM RELOAD DICTIONARY default.{dict_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM RELOAD DICTIONARY with privilege"): + dict_name = f"dict_{getuid()}" table_name = f"table_{getuid()}" @@ -185,6 +204,7 @@ def dictionary(self, privilege, grant_target_name, user_name, node=None): node.query(f"SYSTEM RELOAD DICTIONARY default.{dict_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM RELOAD DICTIONARY with revoked privilege"): + dict_name = f"dict_{getuid()}" table_name = f"table_{getuid()}" @@ -212,7 +232,7 @@ def dictionaries_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=dictionaries, flags=TE, + Suite(run=dictionaries, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in dictionaries.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -233,7 +253,7 @@ def dictionaries_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=dictionaries, flags=TE, + Suite(run=dictionaries, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in dictionaries.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -243,6 +263,7 @@ def dictionaries_privileges_granted_via_role(self, node=None): RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionaries("1.0"), ) @Examples("privilege",[ + ("ALL",), ("SYSTEM",), ("SYSTEM RELOAD",), ("SYSTEM RELOAD DICTIONARIES",), @@ -258,11 +279,19 @@ def dictionaries(self, privilege, grant_target_name, user_name, node=None): node = self.context.node with Scenario("SYSTEM RELOAD DICTIONARIES without privilege"): - with When("I check the user is unable to execute SYSTEM RELOAD DICTIONARIES"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user is unable to execute SYSTEM RELOAD DICTIONARIES"): node.query("SYSTEM RELOAD DICTIONARIES", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM RELOAD DICTIONARIES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -270,6 +299,7 @@ def dictionaries(self, privilege, grant_target_name, user_name, node=None): node.query("SYSTEM RELOAD DICTIONARIES", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM RELOAD DICTIONARIES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -292,7 +322,7 @@ def embedded_dictionaries_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=embedded_dictionaries, flags=TE, + Suite(run=embedded_dictionaries, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in embedded_dictionaries.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -313,7 +343,7 @@ def embedded_dictionaries_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=embedded_dictionaries, flags=TE, + Suite(run=embedded_dictionaries, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in embedded_dictionaries.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -323,6 +353,7 @@ def embedded_dictionaries_privileges_granted_via_role(self, node=None): RQ_SRS_006_RBAC_Privileges_System_Reload_EmbeddedDictionaries("1.0"), ) @Examples("privilege",[ + ("ALL",), ("SYSTEM",), ("SYSTEM RELOAD",), ("SYSTEM RELOAD EMBEDDED DICTIONARIES",), @@ -337,11 +368,19 @@ def embedded_dictionaries(self, privilege, grant_target_name, user_name, node=No node = self.context.node with Scenario("SYSTEM RELOAD EMBEDDED DICTIONARIES without privilege"): - with When("I check the user is unable to execute SYSTEM RELOAD EMBEDDED DICTIONARIES"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user is unable to execute SYSTEM RELOAD EMBEDDED DICTIONARIES"): node.query("SYSTEM RELOAD EMBEDDED DICTIONARIES", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM RELOAD EMBEDDED DICTIONARIES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -349,6 +388,7 @@ def embedded_dictionaries(self, privilege, grant_target_name, user_name, node=No node.query("SYSTEM RELOAD EMBEDDED DICTIONARIES", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM RELOAD EMBEDDED DICTIONARIES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}") @@ -363,6 +403,8 @@ def embedded_dictionaries(self, privilege, grant_target_name, user_name, node=No @Name("system reload") @Requirements( RQ_SRS_006_RBAC_Privileges_System_Reload("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM RELOAD. diff --git a/tests/testflows/rbac/tests/privileges/system/replication_queues.py b/tests/testflows/rbac/tests/privileges/system/replication_queues.py index 3ac2e09418a..47f12b7c866 100644 --- a/tests/testflows/rbac/tests/privileges/system/replication_queues.py +++ b/tests/testflows/rbac/tests/privileges/system/replication_queues.py @@ -17,7 +17,7 @@ def replicated_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=check_replicated_privilege, flags=TE, + Suite(run=check_replicated_privilege, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in check_replicated_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def replicated_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_replicated_privilege, flags=TE, + Suite(run=check_replicated_privilege, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in check_replicated_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM REPLICATION QUEUES", "table"), ("SYSTEM STOP REPLICATION QUEUES", "table"), @@ -59,8 +60,8 @@ def check_replicated_privilege(self, privilege, on, grant_target_name, user_name if node is None: node = self.context.node - Suite(test=start_replication_queues, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) - Suite(test=stop_replication_queues, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=start_replication_queues)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=stop_replication_queues)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) @TestSuite def start_replication_queues(self, privilege, on, grant_target_name, user_name, node=None): @@ -77,11 +78,19 @@ def start_replication_queues(self, privilege, on, grant_target_name, user_name, with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"): with Scenario("SYSTEM START REPLICATION QUEUES without privilege"): - with When("I check the user can't start sends"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't start sends"): node.query(f"SYSTEM START REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM START REPLICATION QUEUES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -89,6 +98,7 @@ def start_replication_queues(self, privilege, on, grant_target_name, user_name, node.query(f"SYSTEM START REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM START REPLICATION QUEUES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -114,11 +124,19 @@ def stop_replication_queues(self, privilege, on, grant_target_name, user_name, n with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"): with Scenario("SYSTEM STOP REPLICATION QUEUES without privilege"): - with When("I check the user can't stop sends"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't stop sends"): node.query(f"SYSTEM STOP REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM STOP REPLICATION QUEUES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -126,6 +144,7 @@ def stop_replication_queues(self, privilege, on, grant_target_name, user_name, n node.query(f"SYSTEM STOP REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM STOP REPLICATION QUEUES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -140,6 +159,8 @@ def stop_replication_queues(self, privilege, on, grant_target_name, user_name, n @Name("system replication queues") @Requirements( RQ_SRS_006_RBAC_Privileges_System_ReplicationQueues("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM REPLICATION QUEUES. diff --git a/tests/testflows/rbac/tests/privileges/system/restart_replica.py b/tests/testflows/rbac/tests/privileges/system/restart_replica.py index 0e3e61d04bb..4e3d5f7b060 100644 --- a/tests/testflows/rbac/tests/privileges/system/restart_replica.py +++ b/tests/testflows/rbac/tests/privileges/system/restart_replica.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=restart_replica, flags=TE, + Suite(run=restart_replica, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in restart_replica.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=restart_replica, flags=TE, + Suite(run=restart_replica, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in restart_replica.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM RESTART REPLICA", "table"), ("RESTART REPLICA", "table"), @@ -63,11 +64,19 @@ def restart_replica(self, privilege, on, grant_target_name, user_name, node=None with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"): with Scenario("SYSTEM RESTART REPLICA without privilege"): - with When("I check the user can't restart replica"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't restart replica"): node.query(f"SYSTEM RESTART REPLICA {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM RESTART REPLICA with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -75,6 +84,7 @@ def restart_replica(self, privilege, on, grant_target_name, user_name, node=None node.query(f"SYSTEM RESTART REPLICA {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM RESTART REPLICA with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -89,6 +99,8 @@ def restart_replica(self, privilege, on, grant_target_name, user_name, node=None @Name("system restart replica") @Requirements( RQ_SRS_006_RBAC_Privileges_System_RestartReplica("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM RESTART REPLICA. diff --git a/tests/testflows/rbac/tests/privileges/system/sends.py b/tests/testflows/rbac/tests/privileges/system/sends.py index 24865088703..4acd173d922 100644 --- a/tests/testflows/rbac/tests/privileges/system/sends.py +++ b/tests/testflows/rbac/tests/privileges/system/sends.py @@ -17,7 +17,7 @@ def replicated_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=check_replicated_privilege, flags=TE, + Suite(run=check_replicated_privilege, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in check_replicated_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def replicated_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_replicated_privilege, flags=TE, + Suite(run=check_replicated_privilege, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in check_replicated_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM SENDS", "*.*"), ("SYSTEM START SENDS", "*.*"), @@ -67,8 +68,8 @@ def check_replicated_privilege(self, privilege, on, grant_target_name, user_name if node is None: node = self.context.node - Suite(test=start_replicated_sends, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) - Suite(test=stop_replicated_sends, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=start_replicated_sends)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=stop_replicated_sends)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name) @TestSuite def start_replicated_sends(self, privilege, on, grant_target_name, user_name, node=None): @@ -85,11 +86,19 @@ def start_replicated_sends(self, privilege, on, grant_target_name, user_name, no with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"): with Scenario("SYSTEM START REPLICATED SENDS without privilege"): - with When("I check the user can't start sends"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't start sends"): node.query(f"SYSTEM START REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM START REPLICATED SENDS with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -97,6 +106,7 @@ def start_replicated_sends(self, privilege, on, grant_target_name, user_name, no node.query(f"SYSTEM START REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM START REPLICATED SENDS with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -122,11 +132,19 @@ def stop_replicated_sends(self, privilege, on, grant_target_name, user_name, nod with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"): with Scenario("SYSTEM STOP REPLICATED SENDS without privilege"): - with When("I check the user can't stop sends"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't stop sends"): node.query(f"SYSTEM STOP REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM STOP REPLICATED SENDS with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -134,6 +152,7 @@ def stop_replicated_sends(self, privilege, on, grant_target_name, user_name, nod node.query(f"SYSTEM STOP REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM STOP REPLICATED SENDS with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -157,7 +176,7 @@ def distributed_privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): table_name = f"table_name_{getuid()}" - Suite(run=check_distributed_privilege, flags=TE, + Suite(run=check_distributed_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[user_name,user_name,table_name]) for row in check_distributed_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -179,13 +198,14 @@ def distributed_privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_distributed_privilege, flags=TE, + Suite(run=check_distributed_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[role_name,user_name,table_name]) for row in check_distributed_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM SENDS", "*.*"), ("SYSTEM START SENDS", "*.*"), @@ -208,8 +228,8 @@ def check_distributed_privilege(self, privilege, on, grant_target_name, user_nam if node is None: node = self.context.node - Suite(test=start_distributed_moves, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) - Suite(test=stop_distributed_moves, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=start_distributed_moves)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=stop_distributed_moves)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) @TestSuite def start_distributed_moves(self, privilege, on, grant_target_name, user_name, table_name, node=None): @@ -229,11 +249,19 @@ def start_distributed_moves(self, privilege, on, grant_target_name, user_name, t node.query(f"CREATE TABLE {table_name} (a UInt64) ENGINE = Distributed(sharded_cluster, default, {table0_name}, rand())") with Scenario("SYSTEM START DISTRIBUTED SENDS without privilege"): - with When("I check the user can't start merges"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't start merges"): node.query(f"SYSTEM START DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM START DISTRIBUTED SENDS with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -241,6 +269,7 @@ def start_distributed_moves(self, privilege, on, grant_target_name, user_name, t node.query(f"SYSTEM START DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM START DISTRIBUTED SENDS with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -273,11 +302,19 @@ def stop_distributed_moves(self, privilege, on, grant_target_name, user_name, ta node.query(f"CREATE TABLE {table_name} (a UInt64) ENGINE = Distributed(sharded_cluster, default, {table0_name}, rand())") with Scenario("SYSTEM STOP DISTRIBUTED SENDS without privilege"): - with When("I check the user can't stop merges"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't stop merges"): node.query(f"SYSTEM STOP DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM STOP DISTRIBUTED SENDS with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -285,6 +322,7 @@ def stop_distributed_moves(self, privilege, on, grant_target_name, user_name, ta node.query(f"SYSTEM STOP DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM STOP DISTRIBUTED SENDS with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -302,6 +340,8 @@ def stop_distributed_moves(self, privilege, on, grant_target_name, user_name, ta @Name("system sends") @Requirements( RQ_SRS_006_RBAC_Privileges_System_Sends("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM SENDS. diff --git a/tests/testflows/rbac/tests/privileges/system/shutdown.py b/tests/testflows/rbac/tests/privileges/system/shutdown.py index 290f6d8e5d1..26752ef4d01 100644 --- a/tests/testflows/rbac/tests/privileges/system/shutdown.py +++ b/tests/testflows/rbac/tests/privileges/system/shutdown.py @@ -19,7 +19,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @@ -40,13 +40,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in check_privilege.examples ], args=Args(name="privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege",[ + ("ALL",), ("SYSTEM",), ("SYSTEM SHUTDOWN",), ("SHUTDOWN",), @@ -59,8 +60,8 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None): if node is None: node = self.context.node - Suite(test=shutdown, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) - Suite(test=kill, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=shutdown)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) + Suite(test=kill)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name) @TestSuite def shutdown(self, privilege, grant_target_name, user_name, node=None): @@ -75,7 +76,13 @@ def shutdown(self, privilege, grant_target_name, user_name, node=None): with Scenario("SYSTEM SHUTDOWN without privilege"): - with When("I check the user can't use SYSTEM SHUTDOWN"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SYSTEM SHUTDOWN"): node.query(f"SYSTEM SHUTDOWN", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -136,7 +143,13 @@ def kill(self, privilege, grant_target_name, user_name, node=None): with Scenario("SYSTEM KILL without privilege"): - with When("I check the user can't use SYSTEM KILL"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't use SYSTEM KILL"): node.query(f"SYSTEM KILL", settings=[("user",user_name)], exitcode=exitcode, message=message) @@ -190,6 +203,8 @@ def kill(self, privilege, grant_target_name, user_name, node=None): @Name("system shutdown") @Requirements( RQ_SRS_006_RBAC_Privileges_System_Shutdown("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM SHUTDOWN. diff --git a/tests/testflows/rbac/tests/privileges/system/sync_replica.py b/tests/testflows/rbac/tests/privileges/system/sync_replica.py index 7df697fd6e5..14681ad31ae 100644 --- a/tests/testflows/rbac/tests/privileges/system/sync_replica.py +++ b/tests/testflows/rbac/tests/privileges/system/sync_replica.py @@ -17,7 +17,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): - Suite(run=sync_replica, flags=TE, + Suite(run=sync_replica, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[user_name,user_name]) for row in sync_replica.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -38,13 +38,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=sync_replica, flags=TE, + Suite(run=sync_replica, examples=Examples("privilege on grant_target_name user_name", [ tuple(list(row)+[role_name,user_name]) for row in sync_replica.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM SYNC REPLICA", "table"), ("SYNC REPLICA", "table"), @@ -63,11 +64,19 @@ def sync_replica(self, privilege, on, grant_target_name, user_name, node=None): with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"): with Scenario("SYSTEM SYNC REPLICA without privilege"): - with When("I check the user can't sync replica"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't sync replica"): node.query(f"SYSTEM SYNC REPLICA {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM SYNC REPLICA with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -75,6 +84,7 @@ def sync_replica(self, privilege, on, grant_target_name, user_name, node=None): node.query(f"SYSTEM SYNC REPLICA {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM SYNC REPLICA with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -89,6 +99,8 @@ def sync_replica(self, privilege, on, grant_target_name, user_name, node=None): @Name("system sync replica") @Requirements( RQ_SRS_006_RBAC_Privileges_System_SyncReplica("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM SYNC REPLICA. diff --git a/tests/testflows/rbac/tests/privileges/system/ttl_merges.py b/tests/testflows/rbac/tests/privileges/system/ttl_merges.py index 74f99026fe4..a59cc530a6d 100644 --- a/tests/testflows/rbac/tests/privileges/system/ttl_merges.py +++ b/tests/testflows/rbac/tests/privileges/system/ttl_merges.py @@ -18,7 +18,7 @@ def privileges_granted_directly(self, node=None): with user(node, f"{user_name}"): table_name = f"table_name_{getuid()}" - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[user_name,user_name,table_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @@ -40,13 +40,14 @@ def privileges_granted_via_role(self, node=None): with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") - Suite(run=check_privilege, flags=TE, + Suite(run=check_privilege, examples=Examples("privilege on grant_target_name user_name table_name", [ tuple(list(row)+[role_name,user_name,table_name]) for row in check_privilege.examples ], args=Args(name="check privilege={privilege}", format_name=True))) @TestOutline(Suite) @Examples("privilege on",[ + ("ALL", "*.*"), ("SYSTEM", "*.*"), ("SYSTEM TTL MERGES", "table"), ("SYSTEM STOP TTL MERGES", "table"), @@ -61,8 +62,8 @@ def check_privilege(self, privilege, on, grant_target_name, user_name, table_nam if node is None: node = self.context.node - Suite(test=start_ttl_merges, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) - Suite(test=stop_ttl_merges, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=start_ttl_merges)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) + Suite(test=stop_ttl_merges)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name) @TestSuite def start_ttl_merges(self, privilege, on, grant_target_name, user_name, table_name, node=None): @@ -78,11 +79,19 @@ def start_ttl_merges(self, privilege, on, grant_target_name, user_name, table_na with table(node, table_name): with Scenario("SYSTEM START TTL MERGES without privilege"): - with When("I check the user can't start merges"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't start merges"): node.query(f"SYSTEM START TTL MERGES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM START TTL MERGES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -90,6 +99,7 @@ def start_ttl_merges(self, privilege, on, grant_target_name, user_name, table_na node.query(f"SYSTEM START TTL MERGES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM START TTL MERGES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -114,11 +124,19 @@ def stop_ttl_merges(self, privilege, on, grant_target_name, user_name, table_nam with table(node, table_name): with Scenario("SYSTEM STOP TTL MERGES without privilege"): - with When("I check the user can't stop merges"): + + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I check the user can't stop merges"): node.query(f"SYSTEM STOP TTL MERGES {table_name}", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with Scenario("SYSTEM STOP TTL MERGES with privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -126,6 +144,7 @@ def stop_ttl_merges(self, privilege, on, grant_target_name, user_name, table_nam node.query(f"SYSTEM STOP TTL MERGES {table_name}", settings = [("user", f"{user_name}")]) with Scenario("SYSTEM STOP TTL MERGES with revoked privilege"): + with When(f"I grant {privilege} on the table"): node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}") @@ -140,6 +159,8 @@ def stop_ttl_merges(self, privilege, on, grant_target_name, user_name, table_nam @Name("system ttl merges") @Requirements( RQ_SRS_006_RBAC_Privileges_System_TTLMerges("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) def feature(self, node="clickhouse1"): """Check the RBAC functionality of SYSTEM TTL MERGES. diff --git a/tests/testflows/rbac/tests/privileges/truncate.py b/tests/testflows/rbac/tests/privileges/truncate.py index b7dfcbfd718..df81913f0a8 100644 --- a/tests/testflows/rbac/tests/privileges/truncate.py +++ b/tests/testflows/rbac/tests/privileges/truncate.py @@ -12,13 +12,13 @@ def privilege_granted_directly_or_via_role(self, table_type, node=None): if node is None: node = self.context.node - with Suite("user with direct privilege", setup=instrument_clickhouse_server_log): + with Suite("user with direct privilege"): with user(node, user_name): with When(f"I run checks that {user_name} is only able to execute TRUNCATE with required privileges"): privilege_check(grant_target_name=user_name, user_name=user_name, table_type=table_type, node=node) - with Suite("user with privilege via role", setup=instrument_clickhouse_server_log): + with Suite("user with privilege via role"): with user(node, user_name), role(node, role_name): with When("I grant the role to the user"): @@ -32,16 +32,22 @@ def privilege_check(grant_target_name, user_name, table_type, node=None): """ exitcode, message = errors.not_enough_privileges(name=f"{user_name}") - with Scenario("user without privilege", setup=instrument_clickhouse_server_log): + with Scenario("user without privilege"): table_name = f"merge_tree_{getuid()}" with table(node, table_name, table_type): - with When("I attempt to truncate a table without privilege"): + with When("I grant the user NONE privilege"): + node.query(f"GRANT NONE TO {grant_target_name}") + + with And("I grant the user USAGE privilege"): + node.query(f"GRANT USAGE ON *.* TO {grant_target_name}") + + with Then("I attempt to truncate a table without privilege"): node.query(f"TRUNCATE TABLE {table_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("user with privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with privilege"): table_name = f"merge_tree_{getuid()}" with table(node, table_name, table_type): @@ -52,7 +58,7 @@ def privilege_check(grant_target_name, user_name, table_type, node=None): with Then("I attempt to truncate a table"): node.query(f"TRUNCATE TABLE {table_name}", settings = [("user", user_name)]) - with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked privilege"): table_name = f"merge_tree_{getuid()}" with table(node, table_name, table_type): @@ -67,7 +73,22 @@ def privilege_check(grant_target_name, user_name, table_type, node=None): node.query(f"TRUNCATE TABLE {table_name}", settings = [("user", user_name)], exitcode=exitcode, message=message) - with Scenario("execute on cluster", setup=instrument_clickhouse_server_log): + with Scenario("user with revoked ALL privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name, table_type): + + with When("I grant the truncate privilege"): + node.query(f"GRANT TRUNCATE ON {table_name} TO {grant_target_name}") + + with And("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with Then("I attempt to truncate a table"): + node.query(f"TRUNCATE TABLE {table_name}", settings = [("user", user_name)], + exitcode=exitcode, message=message) + + with Scenario("execute on cluster"): table_name = f"merge_tree_{getuid()}" with table(node, table_name, table_type): @@ -78,9 +99,25 @@ def privilege_check(grant_target_name, user_name, table_type, node=None): with Then("I attempt to truncate a table"): node.query(f"TRUNCATE TABLE IF EXISTS {table_name} ON CLUSTER sharded_cluster", settings = [("user", user_name)]) + with Scenario("user with ALL privilege"): + table_name = f"merge_tree_{getuid()}" + + with table(node, table_name, table_type): + + with When("I revoke ALL privilege"): + node.query(f"REVOKE ALL ON *.* FROM {grant_target_name}") + + with And("I grant ALL privilege"): + node.query(f"GRANT ALL ON *.* TO {grant_target_name}") + + with Then("I attempt to truncate a table"): + node.query(f"TRUNCATE TABLE {table_name}", settings = [("user", user_name)]) + @TestFeature @Requirements( RQ_SRS_006_RBAC_Privileges_Truncate("1.0"), + RQ_SRS_006_RBAC_Privileges_All("1.0"), + RQ_SRS_006_RBAC_Privileges_None("1.0") ) @Examples("table_type", [ (key,) for key in table_types.keys() @@ -103,5 +140,5 @@ def feature(self, node="clickhouse1", stress=None, parallel=None): continue with Example(str(example)): - with Suite(test=privilege_granted_directly_or_via_role): + with Suite(test=privilege_granted_directly_or_via_role, setup=instrument_clickhouse_server_log): privilege_granted_directly_or_via_role(table_type=table_type) diff --git a/tests/testflows/rbac/tests/syntax/alter_quota.py b/tests/testflows/rbac/tests/syntax/alter_quota.py index 74a9c05bd27..6ccafc4dbcd 100755 --- a/tests/testflows/rbac/tests/syntax/alter_quota.py +++ b/tests/testflows/rbac/tests/syntax/alter_quota.py @@ -33,12 +33,12 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER user0") node.query(f"CREATE ROLE role0") - with Scenario("I alter quota with no options", flags=TE, requirements=[ + with Scenario("I alter quota with no options", requirements=[ RQ_SRS_006_RBAC_Quota_Alter("1.0")]): with When("I alter quota"): node.query("ALTER QUOTA quota0") - with Scenario("I alter quota that does not exist, throws an exception", flags=TE, requirements=[ + with Scenario("I alter quota that does not exist, throws an exception", requirements=[ RQ_SRS_006_RBAC_Quota_Alter("1.0")]): quota = "quota1" cleanup_quota(quota) @@ -47,11 +47,11 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER QUOTA {quota}", exitcode=exitcode, message=message) del quota - with Scenario("I alter quota with if exists, quota does exist", flags=TE, requirements=[ + with Scenario("I alter quota with if exists, quota does exist", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_IfExists("1.0")]): node.query("ALTER QUOTA IF EXISTS quota0") - with Scenario("I alter quota with if exists, quota does not exist", flags=TE, requirements=[ + with Scenario("I alter quota with if exists, quota does not exist", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_IfExists("1.0")]): quota = "quota1" cleanup_quota(quota) @@ -59,11 +59,11 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER QUOTA IF EXISTS {quota}") del quota - with Scenario("I alter quota using rename, target available", flags=TE, requirements=[ + with Scenario("I alter quota using rename, target available", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Rename("1.0")]): node.query("ALTER QUOTA quota0 RENAME TO quota0") - with Scenario("I alter quota using rename, target unavailable", flags=TE, requirements=[ + with Scenario("I alter quota using rename, target unavailable", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Rename("1.0")]): new_quota = "quota1" @@ -82,20 +82,20 @@ def feature(self, node="clickhouse1"): keys = ['none', 'user name', 'ip address', 'client key', 'client key or user name', 'client key or ip address'] for key in keys: - with Scenario(f"I alter quota keyed by {key}", flags=TE, requirements=[ + with Scenario(f"I alter quota keyed by {key}", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_KeyedBy("1.0"), RQ_SRS_006_RBAC_Quota_Alter_KeyedByOptions("1.0")]): with When("I alter quota with a key"): node.query(f"ALTER QUOTA quota0 KEYED BY '{key}'") - with Scenario("I alter quota for randomized interval", flags=TE, requirements=[ + with Scenario("I alter quota for randomized interval", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Interval_Randomized("1.0")]): with When("I alter quota on a randomized interval"): node.query("ALTER QUOTA quota0 FOR RANDOMIZED INTERVAL 1 DAY NO LIMITS") intervals = ['SECOND', 'MINUTE', 'HOUR', 'DAY', 'MONTH'] for i, interval in enumerate(intervals): - with Scenario(f"I alter quota for interval {interval}", flags=TE, requirements=[ + with Scenario(f"I alter quota for interval {interval}", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Interval("1.0")]): with When(f"I alter quota for {interval}"): node.query(f"ALTER QUOTA quota0 FOR INTERVAL 1 {interval} NO LIMITS") @@ -104,7 +104,7 @@ def feature(self, node="clickhouse1"): 'MAX RESULT BYTES', 'MAX READ ROWS', 'MAX READ BYTES', 'MAX EXECUTION TIME', 'NO LIMITS', 'TRACKING ONLY'] for i, constraint in enumerate(constraints): - with Scenario(f"I alter quota for {constraint.lower()}", flags=TE, requirements=[ + with Scenario(f"I alter quota for {constraint.lower()}", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Queries("1.0"), RQ_SRS_006_RBAC_Quota_Alter_Errors("1.0"), RQ_SRS_006_RBAC_Quota_Alter_ResultRows("1.0"), @@ -117,7 +117,7 @@ def feature(self, node="clickhouse1"): with When("I alter quota for a constraint"): node.query(f"ALTER QUOTA quota0 FOR INTERVAL 1 DAY {constraint}{' 1024' if constraint.startswith('MAX') else ''}") - with Scenario("I create quota for multiple constraints", flags=TE, requirements=[ + with Scenario("I create quota for multiple constraints", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Interval("1.0"), RQ_SRS_006_RBAC_Quota_Alter_Queries("1.0")]): node.query("ALTER QUOTA quota0 \ @@ -125,12 +125,12 @@ def feature(self, node="clickhouse1"): FOR INTERVAL 2 DAY MAX QUERIES 124, \ FOR INTERVAL 1 MONTH TRACKING ONLY") - with Scenario("I alter quota to assign to one role", flags=TE, requirements=[ + with Scenario("I alter quota to assign to one role", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Assignment("1.0")]): with When("I alter quota to a role"): node.query("ALTER QUOTA quota0 TO role0") - with Scenario("I alter quota to assign to role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter quota to assign to role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Assignment("1.0")]): role = "role1" with Given(f"I drop {role} if it exists"): @@ -140,7 +140,7 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER QUOTA quota0 TO {role}", exitcode=exitcode, message=message) del role - with Scenario("I alter quota to assign to all except role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter quota to assign to all except role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Assignment("1.0")]): role = "role1" with Given(f"I drop {role} if it exists"): @@ -150,32 +150,32 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER QUOTA quota0 TO ALL EXCEPT {role}", exitcode=exitcode, message=message) del role - with Scenario("I alter quota to assign to one role and one user", flags=TE, requirements=[ + with Scenario("I alter quota to assign to one role and one user", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Assignment("1.0")]): with When("I alter quota to a role and a user"): node.query("ALTER QUOTA quota0 TO role0, user0") - with Scenario("I alter quota assigned to none", flags=TE, requirements=[ + with Scenario("I alter quota assigned to none", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Assignment_None("1.0")]): with When("I alter quota to none"): node.query("ALTER QUOTA quota0 TO NONE") - with Scenario("I alter quota to assign to all", flags=TE, requirements=[ + with Scenario("I alter quota to assign to all", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Assignment_All("1.0")]): with When("I alter quota to all"): node.query("ALTER QUOTA quota0 TO ALL") - with Scenario("I alter quota to assign to all except one role", flags=TE, requirements=[ + with Scenario("I alter quota to assign to all except one role", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Assignment_Except("1.0")]): with When("I alter quota to all except one role"): node.query("ALTER QUOTA quota0 TO ALL EXCEPT role0") - with Scenario("I alter quota to assign to all except multiple roles", flags=TE, requirements=[ + with Scenario("I alter quota to assign to all except multiple roles", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Assignment_Except("1.0")]): with When("I alter quota to all except one multiple roles"): node.query("ALTER QUOTA quota0 TO ALL EXCEPT role0, user0") - with Scenario("I alter quota on cluster", flags=TE, requirements=[ + with Scenario("I alter quota on cluster", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Cluster("1.0")]): try: with Given("I have a quota on a cluster"): @@ -193,7 +193,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the quota"): node.query("DROP QUOTA IF EXISTS quota1 ON CLUSTER sharded_cluster") - with Scenario("I alter quota on nonexistent cluster, throws exception", flags=TE, requirements=[ + with Scenario("I alter quota on nonexistent cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_Quota_Alter_Cluster("1.0")]): with When("I run alter quota on a cluster"): exitcode, message = errors.cluster_not_found("fake_cluster") diff --git a/tests/testflows/rbac/tests/syntax/alter_role.py b/tests/testflows/rbac/tests/syntax/alter_role.py index b1e66fb5893..5068302fc84 100755 --- a/tests/testflows/rbac/tests/syntax/alter_role.py +++ b/tests/testflows/rbac/tests/syntax/alter_role.py @@ -38,13 +38,13 @@ def feature(self, node="clickhouse1"): with Given(f"I ensure that role {role} does not exist"): node.query(f"DROP ROLE IF EXISTS {role}") - with Scenario("I alter role with no options", flags=TE, requirements=[ + with Scenario("I alter role with no options", requirements=[ RQ_SRS_006_RBAC_Role_Alter("1.0")]): with setup("role0"): with When("I alter role"): node.query("ALTER ROLE role0") - with Scenario("I alter role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_Role_Alter("1.0")]): role = "role0" cleanup_role(role) @@ -53,13 +53,13 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER ROLE {role}", exitcode=exitcode, message=message) del role - with Scenario("I alter role if exists, role does exist", flags=TE, requirements=[ + with Scenario("I alter role if exists, role does exist", requirements=[ RQ_SRS_006_RBAC_Role_Alter_IfExists("1.0")]): with setup("role1"): with When("I alter role with if exists"): node.query("ALTER ROLE IF EXISTS role1") - with Scenario("I alter role if exists, role does not exist", flags=TE, requirements=[ + with Scenario("I alter role if exists, role does not exist", requirements=[ RQ_SRS_006_RBAC_Role_Alter_IfExists("1.0")]): role = "role0" cleanup_role(role) @@ -67,7 +67,7 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER ROLE IF EXISTS {role}") del role - with Scenario("I alter role on cluster", flags=TE, requirements=[ + with Scenario("I alter role on cluster", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Cluster("1.0")]): try: with Given("I have a role on a cluster"): @@ -82,13 +82,13 @@ def feature(self, node="clickhouse1"): with Finally("I drop the role"): node.query("DROP ROLE IF EXISTS role1,role2 ON CLUSTER sharded_cluster") - with Scenario("I alter role on nonexistent cluster, throws exception", flags=TE, requirements=[ + with Scenario("I alter role on nonexistent cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Cluster("1.0")]): with When("I run alter role on a cluster"): exitcode, message = errors.cluster_not_found("fake_cluster") node.query("ALTER ROLE role1 ON CLUSTER fake_cluster", exitcode=exitcode, message=message) - with Scenario("I alter role to rename, new name is available", flags=TE, requirements=[ + with Scenario("I alter role to rename, new name is available", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Rename("1.0")]): with setup("role2"): new_role = "role3" @@ -102,7 +102,7 @@ def feature(self, node="clickhouse1"): node.query(f"DROP ROLE IF EXISTS {new_role}") del new_role - with Scenario("I alter role to rename, new name is not available, throws exception", flags=TE, requirements=[ + with Scenario("I alter role to rename, new name is not available, throws exception", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Rename("1.0")]): with setup("role2a"): new_role = "role3a" @@ -117,13 +117,13 @@ def feature(self, node="clickhouse1"): node.query(f"DROP ROLE IF EXISTS {new_role}") del new_role - with Scenario("I alter role settings profile", flags=TE, requirements=[ + with Scenario("I alter role settings profile", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role4"): with When("I alter role with settings profile"): node.query("ALTER ROLE role4 SETTINGS PROFILE default, max_memory_usage=10000000 READONLY") - with Scenario("I alter role settings profile, profile does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter role settings profile, profile does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role4a"): with Given("I ensure profile profile0 does not exist"): @@ -132,20 +132,20 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.settings_profile_not_found_in_disk("profile0") node.query("ALTER ROLE role4a SETTINGS PROFILE profile0", exitcode=exitcode, message=message) - with Scenario("I alter role settings profile multiple", flags=TE, requirements=[ + with Scenario("I alter role settings profile multiple", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role4b", profile="profile0"): with When("I alter role with multiple profiles"): node.query("ALTER ROLE role4b SETTINGS PROFILE default, PROFILE profile0, \ max_memory_usage=10000000 READONLY") - with Scenario("I alter role settings without profile", flags=TE, requirements=[ + with Scenario("I alter role settings without profile", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role5"): with When("I alter role with settings and no profile"): node.query("ALTER ROLE role5 SETTINGS max_memory_usage=10000000 READONLY") - with Scenario("I alter role settings, variable does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter role settings, variable does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role5a"): with When("I alter role using settings and nonexistent value"): @@ -153,33 +153,33 @@ def feature(self, node="clickhouse1"): node.query("ALTER ROLE role5a SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message) - with Scenario("I alter role settings without profile multiple", flags=TE, requirements=[ + with Scenario("I alter role settings without profile multiple", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role6"): with When("I alter role with multiple settings and no profile"): node.query("ALTER ROLE role6 SETTINGS max_memory_usage=10000000 READONLY, \ max_rows_to_read MIN 20 MAX 25") - with Scenario("I alter role settings with multiple profiles multiple variables", flags=TE, requirements=[ + with Scenario("I alter role settings with multiple profiles multiple variables", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role7", profile="profile1"): with When("I alter role with multiple settings and profiles"): node.query("ALTER ROLE role7 SETTINGS PROFILE default, PROFILE profile1, \ max_memory_usage=10000000 READONLY, max_rows_to_read MIN 20 MAX 25") - with Scenario("I alter role settings readonly", flags=TE, requirements=[ + with Scenario("I alter role settings readonly", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role8"): with When("I alter role with readonly"): node.query("ALTER ROLE role8 SETTINGS max_memory_usage READONLY") - with Scenario("I alter role settings writable", flags=TE, requirements=[ + with Scenario("I alter role settings writable", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role9"): with When("I alter role with writable"): node.query("ALTER ROLE role9 SETTINGS max_memory_usage WRITABLE") - with Scenario("I alter role settings min, with and without = sign", flags=TE, requirements=[ + with Scenario("I alter role settings min, with and without = sign", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role10"): with When("I set min, no equals"): @@ -187,7 +187,7 @@ def feature(self, node="clickhouse1"): with When("I set min, yes equals"): node.query("ALTER ROLE role10 SETTINGS max_memory_usage MIN = 200") - with Scenario("I alter role settings max, with and without = sign", flags=TE, requirements=[ + with Scenario("I alter role settings max, with and without = sign", requirements=[ RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]): with setup("role11"): with When("I set max, no equals"): diff --git a/tests/testflows/rbac/tests/syntax/alter_row_policy.py b/tests/testflows/rbac/tests/syntax/alter_row_policy.py index 7fbed4a63c4..6422a81fec2 100755 --- a/tests/testflows/rbac/tests/syntax/alter_row_policy.py +++ b/tests/testflows/rbac/tests/syntax/alter_row_policy.py @@ -42,21 +42,21 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROLE role0") node.query(f"CREATE ROLE role1") - with Scenario("I alter row policy with no options", flags=TE, requirements=[ + with Scenario("I alter row policy with no options", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy0"): with When("I alter row policy"): node.query("ALTER ROW POLICY policy0 ON default.foo") - with Scenario("I alter row policy using short syntax with no options", flags=TE, requirements=[ + with Scenario("I alter row policy using short syntax with no options", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy1"): with When("I alter row policy short form"): node.query("ALTER POLICY policy1 ON default.foo") - with Scenario("I alter row policy, does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter row policy, does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): policy = "policy2" @@ -66,14 +66,14 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER ROW POLICY {policy} ON default.foo", exitcode=exitcode, message=message) del policy - with Scenario("I alter row policy if exists", flags=TE, requirements=[ + with Scenario("I alter row policy if exists", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_IfExists("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy2"): with When("I alter row policy using if exists"): node.query("ALTER ROW POLICY IF EXISTS policy2 ON default.foo") - with Scenario("I alter row policy if exists, policy does not exist", flags=TE, requirements=[ + with Scenario("I alter row policy if exists, policy does not exist", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_IfExists("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): policy = "policy2" @@ -82,14 +82,14 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER ROW POLICY IF EXISTS {policy} ON default.foo") del policy - with Scenario("I alter row policy to rename, target available", flags=TE, requirements=[ + with Scenario("I alter row policy to rename, target available", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Rename("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy3"): with When("I alter row policy with rename"): node.query("ALTER ROW POLICY policy3 ON default.foo RENAME TO policy3") - with Scenario("I alter row policy to rename, target unavailable", flags=TE, requirements=[ + with Scenario("I alter row policy to rename, target unavailable", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Rename("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy3"): @@ -106,49 +106,49 @@ def feature(self, node="clickhouse1"): node.query(f"DROP ROW POLICY IF EXISTS {new_policy} ON default.foo") del new_policy - with Scenario("I alter row policy to permissive", flags=TE, requirements=[ + with Scenario("I alter row policy to permissive", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Permissive("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy4"): with When("I alter row policy as permissive"): node.query("ALTER ROW POLICY policy4 ON default.foo AS PERMISSIVE") - with Scenario("I alter row policy to restrictive", flags=TE, requirements=[ + with Scenario("I alter row policy to restrictive", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Restrictive("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy5"): with When("I alter row policy as restrictive"): node.query("ALTER ROW POLICY policy5 ON default.foo AS RESTRICTIVE") - with Scenario("I alter row policy for select", flags=TE, requirements=[ + with Scenario("I alter row policy for select", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_ForSelect("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy6"): with When("I alter row policy using for select"): node.query("ALTER ROW POLICY policy6 ON default.foo FOR SELECT USING x > 10") - with Scenario("I alter row policy using condition", flags=TE, requirements=[ + with Scenario("I alter row policy using condition", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Condition("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy6"): with When("I alter row policy wtih condition"): node.query("ALTER ROW POLICY policy6 ON default.foo USING x > 10") - with Scenario("I alter row policy using condition none", flags=TE, requirements=[ + with Scenario("I alter row policy using condition none", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Condition_None("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy7"): with When("I alter row policy using no condition"): node.query("ALTER ROW POLICY policy7 ON default.foo USING NONE") - with Scenario("I alter row policy to one role", flags=TE, requirements=[ + with Scenario("I alter row policy to one role", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy8"): with When("I alter row policy to a role"): node.query("ALTER ROW POLICY policy8 ON default.foo TO role0") - with Scenario("I alter row policy to assign to role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter row policy to assign to role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment("1.0")]): role = "role2" with cleanup("policy8a"): @@ -159,7 +159,7 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER ROW POLICY policy8a ON default.foo TO {role}", exitcode=exitcode, message=message) del role - with Scenario("I alter row policy to assign to all excpet role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter row policy to assign to all excpet role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment("1.0")]): role = "role2" with cleanup("policy8a"): @@ -170,35 +170,35 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER ROW POLICY policy8a ON default.foo TO ALL EXCEPT {role}", exitcode=exitcode, message=message) del role - with Scenario("I alter row policy assigned to multiple roles", flags=TE, requirements=[ + with Scenario("I alter row policy assigned to multiple roles", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy9"): with When("I alter row policy to multiple roles"): node.query("ALTER ROW POLICY policy9 ON default.foo TO role0, role1") - with Scenario("I alter row policy assigned to all", flags=TE, requirements=[ + with Scenario("I alter row policy assigned to all", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_All("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy10"): with When("I alter row policy to all"): node.query("ALTER ROW POLICY policy10 ON default.foo TO ALL") - with Scenario("I alter row policy assigned to all except one role", flags=TE, requirements=[ + with Scenario("I alter row policy assigned to all except one role", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_AllExcept("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy11"): with When("I alter row policy to all except"): node.query("ALTER ROW POLICY policy11 ON default.foo TO ALL EXCEPT role0") - with Scenario("I alter row policy assigned to all except multiple roles", flags=TE, requirements=[ + with Scenario("I alter row policy assigned to all except multiple roles", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_AllExcept("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy12"): with When("I alter row policy to all except multiple roles"): node.query("ALTER ROW POLICY policy12 ON default.foo TO ALL EXCEPT role0, role1") - with Scenario("I alter row policy assigned to none", flags=TE, requirements=[ + with Scenario("I alter row policy assigned to none", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_None("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with cleanup("policy12"): @@ -208,7 +208,7 @@ def feature(self, node="clickhouse1"): # Official syntax: ON CLUSTER cluster_name ON database.table # Working syntax: both orderings of ON CLUSTER and TABLE clauses work - with Scenario("I alter row policy on cluster", flags=TE, requirements=[ + with Scenario("I alter row policy on cluster", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): try: @@ -220,14 +220,14 @@ def feature(self, node="clickhouse1"): with Finally("I drop the row policy"): node.query("DROP ROW POLICY IF EXISTS policy13 ON CLUSTER sharded_cluster ON default.foo") - with Scenario("I alter row policy on fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I alter row policy on fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): with When("I run alter row policy command"): exitcode, message = errors.cluster_not_found("fake_cluster") node.query("ALTER ROW POLICY policy13 ON CLUSTER fake_cluster ON default.foo", exitcode=exitcode, message=message) - with Scenario("I alter row policy on cluster after table", flags=TE, requirements=[ + with Scenario("I alter row policy on cluster after table", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster("1.0"), RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]): try: diff --git a/tests/testflows/rbac/tests/syntax/alter_settings_profile.py b/tests/testflows/rbac/tests/syntax/alter_settings_profile.py index 4222b27954d..4533f6aea65 100755 --- a/tests/testflows/rbac/tests/syntax/alter_settings_profile.py +++ b/tests/testflows/rbac/tests/syntax/alter_settings_profile.py @@ -31,15 +31,15 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER user0") node.query(f"CREATE ROLE role0") - with Scenario("I alter settings profile with no options", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter("1.0")]): + with Scenario("I alter settings profile with no options", requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter("1.0")]): with When("I alter settings profile"): node.query("ALTER SETTINGS PROFILE profile0") - with Scenario("I alter settings profile short form", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter("1.0")]): + with Scenario("I alter settings profile short form", requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter("1.0")]): with When("I short form alter settings profile"): node.query("ALTER PROFILE profile0") - with Scenario("I alter settings profile that does not exist, throws exception", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter("1.0")]): + with Scenario("I alter settings profile that does not exist, throws exception", requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter("1.0")]): profile = "profile1" cleanup_profile(profile) @@ -48,11 +48,11 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER SETTINGS PROFILE {profile}", exitcode=exitcode, message=message) del profile - with Scenario("I alter settings profile if exists", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_IfExists("1.0")]): + with Scenario("I alter settings profile if exists", requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_IfExists("1.0")]): with When("I alter settings profile using if exists"): node.query("ALTER SETTINGS PROFILE IF EXISTS profile0") - with Scenario("I alter settings profile if exists, profile does not exist", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_IfExists("1.0")]): + with Scenario("I alter settings profile if exists, profile does not exist", requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_IfExists("1.0")]): profile = "profile1" cleanup_profile(profile) @@ -61,11 +61,11 @@ def feature(self, node="clickhouse1"): del profile - with Scenario("I alter settings profile to rename, target available", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_Rename("1.0")]): + with Scenario("I alter settings profile to rename, target available", requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_Rename("1.0")]): with When("I alter settings profile by renaming it"): node.query("ALTER SETTINGS PROFILE profile0 RENAME TO profile0") - with Scenario("I alter settings profile to rename, target unavailable", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_Rename("1.0")]): + with Scenario("I alter settings profile to rename, target unavailable", requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_Rename("1.0")]): new_profile = "profile1" try: @@ -81,52 +81,52 @@ def feature(self, node="clickhouse1"): del new_profile - with Scenario("I alter settings profile with a setting value", flags=TE, requirements=[ + with Scenario("I alter settings profile with a setting value", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables("1.0"), RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value("1.0")]): with When("I alter settings profile using settings"): node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage = 100000001") - with Scenario("I alter settings profile with a setting value, does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter settings profile with a setting value, does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables("1.0"), RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value("1.0")]): with When("I alter settings profile using settings and nonexistent value"): exitcode, message = errors.unknown_setting("fake_setting") node.query("ALTER SETTINGS PROFILE profile0 SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message) - with Scenario("I alter settings profile with a min setting value", flags=TE, requirements=[ + with Scenario("I alter settings profile with a min setting value", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]): with When("I alter settings profile using 2 minimum formats"): node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MIN 100000001") node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MIN = 100000001") - with Scenario("I alter settings profile with a max setting value", flags=TE, requirements=[ + with Scenario("I alter settings profile with a max setting value", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]): with When("I alter settings profile using 2 maximum formats"): node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MAX 100000001") node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MAX = 100000001") - with Scenario("I alter settings profile with min and max setting values", flags=TE, requirements=[ + with Scenario("I alter settings profile with min and max setting values", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]): with When("I alter settings profile with both min and max"): node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MIN 100000001 MAX 200000001") - with Scenario("I alter settings profile with a readonly setting", flags=TE, requirements=[ + with Scenario("I alter settings profile with a readonly setting", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]): with When("I alter settings profile with with readonly"): node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage READONLY") - with Scenario("I alter settings profile with a writable setting", flags=TE, requirements=[ + with Scenario("I alter settings profile with a writable setting", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]): with When("I alter settings profile with writable"): node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage WRITABLE") - with Scenario("I alter settings profile with inherited settings", flags=TE, requirements=[ + with Scenario("I alter settings profile with inherited settings", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_Inherit("1.0")]): with When("I alter settings profile with inherit"): node.query("ALTER SETTINGS PROFILE profile0 SETTINGS INHERIT 'default'") - with Scenario("I alter settings profile with inherit, parent profile does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter settings profile with inherit, parent profile does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_Inherit("1.0")]): profile = "profile3" with Given(f"I ensure that profile {profile} does not exist"): @@ -136,7 +136,7 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER PROFILE profile0 SETTINGS INHERIT {profile}", exitcode=exitcode, message=message) del profile - with Scenario("I alter settings profile with multiple settings", flags=TE, requirements=[ + with Scenario("I alter settings profile with multiple settings", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables("1.0"), RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value("1.0")]): with When("I alter settings profile with multiple settings"): @@ -144,7 +144,7 @@ def feature(self, node="clickhouse1"): " SETTINGS max_memory_usage = 100000001" " SETTINGS max_memory_usage_for_user = 100000001") - with Scenario("I alter settings profile with multiple settings short form", flags=TE, requirements=[ + with Scenario("I alter settings profile with multiple settings short form", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables("1.0"), RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value("1.0")]): with When("I alter settings profile with short form multiple settings"): @@ -152,12 +152,12 @@ def feature(self, node="clickhouse1"): " SETTINGS max_memory_usage = 100000001," " max_memory_usage_for_user = 100000001") - with Scenario("I alter settings profile assigned to one role", flags=TE, requirements=[ + with Scenario("I alter settings profile assigned to one role", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment("1.0")]): with When("I alter settings profile with assignment to role"): node.query("ALTER SETTINGS PROFILE profile0 TO role0") - with Scenario("I alter settings profile to assign to role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter settings profile to assign to role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment("1.0")]): role = "role1" with Given(f"I drop {role} if it exists"): @@ -167,7 +167,7 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER SETTINGS PROFILE profile0 TO {role}", exitcode=exitcode, message=message) del role - with Scenario("I alter settings profile to assign to all except role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter settings profile to assign to all except role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment("1.0")]): role = "role1" with Given(f"I drop {role} if it exists"): @@ -177,32 +177,32 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER SETTINGS PROFILE profile0 TO ALL EXCEPT {role}", exitcode=exitcode, message=message) del role - with Scenario("I alter settings profile assigned to multiple roles", flags=TE, requirements=[ + with Scenario("I alter settings profile assigned to multiple roles", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment("1.0")]): with When("I alter settings profile with assignment to multiple roles"): node.query("ALTER SETTINGS PROFILE profile0 TO role0, user0") - with Scenario("I alter settings profile assigned to all", flags=TE, requirements=[ + with Scenario("I alter settings profile assigned to all", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_All("1.0")]): with When("I alter settings profile with assignment to all"): node.query("ALTER SETTINGS PROFILE profile0 TO ALL") - with Scenario("I alter settings profile assigned to all except one role", flags=TE, requirements=[ + with Scenario("I alter settings profile assigned to all except one role", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_AllExcept("1.0")]): with When("I alter settings profile with assignment to all except a role"): node.query("ALTER SETTINGS PROFILE profile0 TO ALL EXCEPT role0") - with Scenario("I alter settings profile assigned to all except multiple roles", flags=TE, requirements=[ + with Scenario("I alter settings profile assigned to all except multiple roles", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_AllExcept("1.0")]): with When("I alter settings profile with assignmentto all except multiple roles"): node.query("ALTER SETTINGS PROFILE profile0 TO ALL EXCEPT role0, user0") - with Scenario("I alter settings profile assigned to none", flags=TE, requirements=[ + with Scenario("I alter settings profile assigned to none", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_None("1.0")]): with When("I alter settings profile with assignment to none"): node.query("ALTER SETTINGS PROFILE profile0 TO NONE") - with Scenario("I alter settings profile on cluster", flags=TE, requirements=[ + with Scenario("I alter settings profile on cluster", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_OnCluster("1.0")]): try: with Given("I have a settings profile on cluster"): @@ -219,7 +219,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the settings profile"): node.query("DROP SETTINGS PROFILE IF EXISTS profile1 ON CLUSTER sharded_cluster") - with Scenario("I alter settings profile on fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I alter settings profile on fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_OnCluster("1.0")]): with When("I run alter settings profile command"): exitcode, message = errors.cluster_not_found("fake_cluster") diff --git a/tests/testflows/rbac/tests/syntax/alter_user.py b/tests/testflows/rbac/tests/syntax/alter_user.py index 8a7ce8724eb..cf8a13008c9 100755 --- a/tests/testflows/rbac/tests/syntax/alter_user.py +++ b/tests/testflows/rbac/tests/syntax/alter_user.py @@ -30,28 +30,28 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER OR REPLACE {user}") yield finally: - with Finally("I drop the user", flags=TE): + with Finally("I drop the user"): node.query(f"DROP USER IF EXISTS {user}") - with Scenario("I alter user, base command", flags=TE, requirements=[ + with Scenario("I alter user, base command", requirements=[ RQ_SRS_006_RBAC_User_Alter("1.0")]): with setup("user0"): with When("I alter user"): node.query("ALTER USER user0") - with Scenario("I alter user that does not exist without if exists, throws exception", flags=TE, requirements=[ + with Scenario("I alter user that does not exist without if exists, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Alter("1.0")]): with When("I run alter user command, expecting error 192"): exitcode, message = errors.user_not_found_in_disk(name="user0") node.query(f"ALTER USER user0",exitcode=exitcode, message=message) - with Scenario("I alter user with if exists", flags=TE, requirements=[ + with Scenario("I alter user with if exists", requirements=[ RQ_SRS_006_RBAC_User_Alter_IfExists("1.0")]): with setup("user0"): with When(f"I alter user with if exists"): node.query(f"ALTER USER IF EXISTS user0") - with Scenario("I alter user that does not exist with if exists", flags=TE, requirements=[ + with Scenario("I alter user that does not exist with if exists", requirements=[ RQ_SRS_006_RBAC_User_Alter_IfExists("1.0")]): user = "user0" with Given("I don't have a user"): @@ -60,7 +60,7 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER USER IF EXISTS {user}") del user - with Scenario("I alter user on a cluster", flags=TE, requirements=[ + with Scenario("I alter user on a cluster", requirements=[ RQ_SRS_006_RBAC_User_Alter_Cluster("1.0")]): with Given("I have a user on a cluster"): node.query("CREATE USER OR REPLACE user0 ON CLUSTER sharded_cluster") @@ -69,19 +69,19 @@ def feature(self, node="clickhouse1"): with Finally("I drop user from cluster"): node.query("DROP USER IF EXISTS user0 ON CLUSTER sharded_cluster") - with Scenario("I alter user on a fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I alter user on a fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Alter_Cluster("1.0")]): with When("I alter user on a fake cluster"): exitcode, message = errors.cluster_not_found("fake_cluster") node.query("ALTER USER user0 ON CLUSTER fake_cluster", exitcode=exitcode, message=message) - with Scenario("I alter user to rename, target available", flags=TE, requirements=[ + with Scenario("I alter user to rename, target available", requirements=[ RQ_SRS_006_RBAC_User_Alter_Rename("1.0")]): with setup("user15"): with When("I alter user name"): node.query("ALTER USER user15 RENAME TO user15") - with Scenario("I alter user to rename, target unavailable", flags=TE, requirements=[ + with Scenario("I alter user to rename, target unavailable", requirements=[ RQ_SRS_006_RBAC_User_Alter_Rename("1.0")]): with setup("user15"): new_user = "user16" @@ -96,20 +96,20 @@ def feature(self, node="clickhouse1"): node.query(f"DROP USER IF EXISTS {new_user}") del new_user - with Scenario("I alter user password plaintext password", flags=TE, requirements=[ + with Scenario("I alter user password plaintext password", requirements=[ RQ_SRS_006_RBAC_User_Alter_Password_PlainText("1.0")]): with setup("user1"): with When("I alter user with plaintext password"): node.query("ALTER USER user1 IDENTIFIED WITH PLAINTEXT_PASSWORD BY 'mypassword'", step=When) - with Scenario("I alter user password to sha256", flags=TE, requirements=[ + with Scenario("I alter user password to sha256", requirements=[ RQ_SRS_006_RBAC_User_Alter_Password_Sha256Password("1.0")]): with setup("user2"): with When("I alter user with sha256_password"): password = hashlib.sha256("mypassword".encode("utf-8")).hexdigest() node.query(f"ALTER USER user2 IDENTIFIED WITH SHA256_PASSWORD BY '{password}'",step=When) - with Scenario("I alter user password to double_sha1_password", flags=TE, requirements=[ + with Scenario("I alter user password to double_sha1_password", requirements=[ RQ_SRS_006_RBAC_User_Alter_Password_DoubleSha1Password("1.0")]): with setup("user3"): with When("I alter user with double_sha1_password"): @@ -118,56 +118,56 @@ def feature(self, node="clickhouse1"): password = hash(hash("mypassword")) node.query(f"ALTER USER user3 IDENTIFIED WITH DOUBLE_SHA1_PASSWORD BY '{password}'", step=When) - with Scenario("I alter user host local", flags=TE, requirements=[ + with Scenario("I alter user host local", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_Local("1.0")]): with setup("user4"): with When("I alter user with host local"): node.query("ALTER USER user4 HOST LOCAL") - with Scenario("I alter user host name", flags=TE, requirements=[ + with Scenario("I alter user host name", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_Name("1.0")]): with setup("user5"): with When("I alter user with host name"): node.query("ALTER USER user5 HOST NAME 'localhost', NAME 'clickhouse.com'") - with Scenario("I alter user host regexp", flags=TE, requirements=[ + with Scenario("I alter user host regexp", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_Regexp("1.0")]): with setup("user6"): with When("I alter user with host regexp"): node.query("ALTER USER user6 HOST REGEXP 'lo..*host', 'lo*host'") - with Scenario("I alter user host ip", flags=TE, requirements=[ + with Scenario("I alter user host ip", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_IP("1.0")]): with setup("user7"): with When("I alter user with host ip"): node.query("ALTER USER user7 HOST IP '127.0.0.1', IP '127.0.0.2'") - with Scenario("I alter user host like", flags=TE, requirements=[ + with Scenario("I alter user host like", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_Like("1.0")]): with setup("user8"): with When("I alter user with host like"): node.query("ALTER USER user8 HOST LIKE '%.clickhouse.com'") - with Scenario("I alter user host any", flags=TE, requirements=[ + with Scenario("I alter user host any", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_Any("1.0")]): with setup("user9"): with When("I alter user with host any"): node.query("ALTER USER user9 HOST ANY") - with Scenario("I alter user host many hosts", flags=TE, requirements=[ + with Scenario("I alter user host many hosts", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_Like("1.0")]): with setup("user11"): with When("I alter user with multiple hosts"): node.query("ALTER USER user11 HOST LIKE '%.clickhouse.com', \ IP '127.0.0.2', NAME 'localhost', REGEXP 'lo*host'") - with Scenario("I alter user default role set to none", flags=TE, requirements=[ + with Scenario("I alter user default role set to none", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_None("1.0")]): with setup("user12"): with When("I alter user with default role none"): node.query("ALTER USER user12 DEFAULT ROLE NONE") - with Scenario("I alter user default role set to all", flags=TE, requirements=[ + with Scenario("I alter user default role set to all", requirements=[ RQ_SRS_006_RBAC_User_Alter_DefaultRole_All("1.0")]): with setup("user13"): with When("I alter user with all roles set to default"): @@ -183,7 +183,7 @@ def feature(self, node="clickhouse1"): with Finally(f"I drop the role {role}", flags=TE): node.query(f"DROP ROLE IF EXISTS {role}") - with Scenario("I alter user default role", flags=TE, requirements=[ + with Scenario("I alter user default role", requirements=[ RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]): with setup("user14"), setup_role("role2"): with Given("I have a user with a role"): @@ -191,7 +191,7 @@ def feature(self, node="clickhouse1"): with When("I alter user default role"): node.query("ALTER USER user14 DEFAULT ROLE role2") - with Scenario("I alter user default role, setting default role", flags=TE, requirements=[ + with Scenario("I alter user default role, setting default role", requirements=[ RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]): with setup("user14a"), setup_role("default"): with Given("I grant default role to the user"): @@ -199,7 +199,7 @@ def feature(self, node="clickhouse1"): with When("I alter user default role"): node.query("ALTER USER user14a DEFAULT ROLE default") - with Scenario("I alter user default role, role doesn't exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter user default role, role doesn't exist, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]): with setup("user12"): role = "role0" @@ -210,7 +210,7 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER USER user12 DEFAULT ROLE {role}",exitcode=exitcode, message=message) del role - with Scenario("I alter user default role, all except role doesn't exist, throws exception", flags=TE, requirements=[ + with Scenario("I alter user default role, all except role doesn't exist, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]): with setup("user12"): role = "role0" @@ -221,7 +221,7 @@ def feature(self, node="clickhouse1"): node.query(f"ALTER USER user12 DEFAULT ROLE ALL EXCEPT {role}",exitcode=exitcode, message=message) del role - with Scenario("I alter user default role multiple", flags=TE, requirements=[ + with Scenario("I alter user default role multiple", requirements=[ RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]): with setup("user15"), setup_role("second"), setup_role("third"): with Given("I have a user with multiple roles"): @@ -229,7 +229,7 @@ def feature(self, node="clickhouse1"): with When("I alter user default role to second, third"): node.query("ALTER USER user15 DEFAULT ROLE second, third") - with Scenario("I alter user default role set to all except", flags=TE, requirements=[ + with Scenario("I alter user default role set to all except", requirements=[ RQ_SRS_006_RBAC_User_Alter_DefaultRole_AllExcept("1.0")]): with setup("user16"), setup_role("second"): with Given("I have a user with a role"): @@ -237,7 +237,7 @@ def feature(self, node="clickhouse1"): with When("I alter user default role"): node.query("ALTER USER user16 DEFAULT ROLE ALL EXCEPT second") - with Scenario("I alter user default role multiple all except", flags=TE, requirements=[ + with Scenario("I alter user default role multiple all except", requirements=[ RQ_SRS_006_RBAC_User_Alter_DefaultRole_AllExcept("1.0")]): with setup("user17"), setup_role("second"), setup_role("third"): with Given("I have a user with multiple roles"): @@ -245,7 +245,7 @@ def feature(self, node="clickhouse1"): with When("I alter user default role to all except second"): node.query("ALTER USER user17 DEFAULT ROLE ALL EXCEPT second") - with Scenario("I alter user settings profile", flags=TE, requirements=[ + with Scenario("I alter user settings profile", requirements=[ RQ_SRS_006_RBAC_User_Alter_Settings("1.0"), \ RQ_SRS_006_RBAC_User_Alter_Settings_Profile("1.0")]): with setup("user18"): @@ -258,7 +258,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the profile"): node.query(f"DROP SETTINGS PROFILE profile10") - with Scenario("I alter user settings profile, fake profile, throws exception", flags=TE, requirements=[ + with Scenario("I alter user settings profile, fake profile, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Alter_Settings("1.0"), RQ_SRS_006_RBAC_User_Alter_Settings_Profile("1.0")]): with setup("user18a"): @@ -270,14 +270,14 @@ def feature(self, node="clickhouse1"): node.query("ALTER USER user18a SETTINGS PROFILE profile0", exitcode=exitcode, message=message) del profile - with Scenario("I alter user settings with a fake setting, throws exception", flags=TE, requirements=[ + with Scenario("I alter user settings with a fake setting, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Alter_Settings("1.0")]): with setup("user18b"): with When("I alter settings profile using settings and nonexistent value"): exitcode, message = errors.unknown_setting("fake_setting") node.query("ALTER USER user18b SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message) - with Scenario("I alter user settings without profile (no equals)", flags=TE, requirements=[ + with Scenario("I alter user settings without profile (no equals)", requirements=[ RQ_SRS_006_RBAC_User_Alter_Settings("1.0"), RQ_SRS_006_RBAC_User_Alter_Settings_Min("1.0"), RQ_SRS_006_RBAC_User_Alter_Settings_Max("1.0")]): @@ -286,7 +286,7 @@ def feature(self, node="clickhouse1"): node.query("ALTER USER user19 SETTINGS max_memory_usage=10000000 MIN 100000 MAX 1000000000 READONLY") #equals sign (=) syntax verify - with Scenario("I alter user settings without profile (yes equals)", flags=TE, requirements=[ + with Scenario("I alter user settings without profile (yes equals)", requirements=[ RQ_SRS_006_RBAC_User_Alter_Settings("1.0"), RQ_SRS_006_RBAC_User_Alter_Settings_Min("1.0"), RQ_SRS_006_RBAC_User_Alter_Settings_Max("1.0")]): @@ -295,7 +295,7 @@ def feature(self, node="clickhouse1"): node.query("ALTER USER user20 SETTINGS max_memory_usage=10000000 MIN=100000 MAX=1000000000 READONLY") #Add requirement to host: add/drop - with Scenario("I alter user to add host", flags=TE, requirements=[ + with Scenario("I alter user to add host", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_AddDrop("1.0")]): with setup("user21"): with When("I alter user by adding local host"): @@ -309,7 +309,7 @@ def feature(self, node="clickhouse1"): with And("I alter user by adding host name"): node.query("ALTER USER user21 ADD HOST NAME 'localhost'") - with Scenario("I alter user to remove host", flags=TE, requirements=[ + with Scenario("I alter user to remove host", requirements=[ RQ_SRS_006_RBAC_User_Alter_Host_AddDrop("1.0")]): with setup("user22"): with When("I alter user by removing local host"): diff --git a/tests/testflows/rbac/tests/syntax/create_quota.py b/tests/testflows/rbac/tests/syntax/create_quota.py index 4945583a542..33dbbf9c153 100755 --- a/tests/testflows/rbac/tests/syntax/create_quota.py +++ b/tests/testflows/rbac/tests/syntax/create_quota.py @@ -41,13 +41,13 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER user0") node.query(f"CREATE ROLE role0") - with Scenario("I create quota with no options", flags=TE, requirements=[ + with Scenario("I create quota with no options", requirements=[ RQ_SRS_006_RBAC_Quota_Create("1.0")]): with cleanup("quota0"): with When("I create a quota with no options"): node.query("CREATE QUOTA quota0") - with Scenario("I create quota that already exists, throws exception", flags=TE, requirements=[ + with Scenario("I create quota that already exists, throws exception", requirements=[ RQ_SRS_006_RBAC_Quota_Create("1.0")]): quota = "quota0" with cleanup(quota): @@ -57,7 +57,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE QUOTA {quota}", exitcode=exitcode, message=message) del quota - with Scenario("I create quota if not exists, quota does not exist", flags=TE, requirements=[ + with Scenario("I create quota if not exists, quota does not exist", requirements=[ RQ_SRS_006_RBAC_Quota_Create_IfNotExists("1.0")]): quota = "quota1" with cleanup(quota): @@ -65,7 +65,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE QUOTA IF NOT EXISTS {quota}") del quota - with Scenario("I create quota if not exists, quota does exist", flags=TE, requirements=[ + with Scenario("I create quota if not exists, quota does exist", requirements=[ RQ_SRS_006_RBAC_Quota_Create_IfNotExists("1.0")]): quota = "quota1" with cleanup(quota): @@ -74,7 +74,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE QUOTA IF NOT EXISTS {quota}") del quota - with Scenario("I create quota or replace, quota does not exist", flags=TE, requirements=[ + with Scenario("I create quota or replace, quota does not exist", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Replace("1.0")]): quota = "quota2" with cleanup(quota): @@ -82,7 +82,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE QUOTA OR REPLACE {quota}") del quota - with Scenario("I create quota or replace, quota does exist", flags=TE, requirements=[ + with Scenario("I create quota or replace, quota does exist", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Replace("1.0")]): quota = "quota2" with cleanup(quota): @@ -93,7 +93,7 @@ def feature(self, node="clickhouse1"): keys = ['none', 'user name', 'ip address', 'client key', 'client key or user name', 'client key or ip address'] for i, key in enumerate(keys): - with Scenario(f"I create quota keyed by {key}", flags=TE, requirements=[ + with Scenario(f"I create quota keyed by {key}", requirements=[ RQ_SRS_006_RBAC_Quota_Create_KeyedBy("1.0"), RQ_SRS_006_RBAC_Quota_Create_KeyedByOptions("1.0")]): name = f'quota{3 + i}' @@ -101,7 +101,7 @@ def feature(self, node="clickhouse1"): with When(f"I create a quota with {key}"): node.query(f"CREATE QUOTA {name} KEYED BY '{key}'") - with Scenario("I create quota for randomized interval", flags=TE, requirements=[ + with Scenario("I create quota for randomized interval", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Interval_Randomized("1.0")]): with cleanup("quota9"): with When("I create a quota for randomized interval"): @@ -109,7 +109,7 @@ def feature(self, node="clickhouse1"): intervals = ['SECOND', 'MINUTE', 'HOUR', 'DAY', 'MONTH'] for i, interval in enumerate(intervals): - with Scenario(f"I create quota for interval {interval}", flags=TE, requirements=[ + with Scenario(f"I create quota for interval {interval}", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Interval("1.0")]): name = f'quota{10 + i}' with cleanup(name): @@ -120,7 +120,7 @@ def feature(self, node="clickhouse1"): 'MAX RESULT BYTES', 'MAX READ ROWS', 'MAX READ BYTES', 'MAX EXECUTION TIME', 'NO LIMITS', 'TRACKING ONLY'] for i, constraint in enumerate(constraints): - with Scenario(f"I create quota for {constraint.lower()}", flags=TE, requirements=[ + with Scenario(f"I create quota for {constraint.lower()}", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Queries("1.0"), RQ_SRS_006_RBAC_Quota_Create_Errors("1.0"), RQ_SRS_006_RBAC_Quota_Create_ResultRows("1.0"), @@ -135,7 +135,7 @@ def feature(self, node="clickhouse1"): with When(f"I create quota for {constraint.lower()}"): node.query(f"CREATE QUOTA {name} FOR INTERVAL 1 DAY {constraint}{' 1024' if constraint.startswith('MAX') else ''}") - with Scenario("I create quota for multiple constraints", flags=TE, requirements=[ + with Scenario("I create quota for multiple constraints", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Interval("1.0"), RQ_SRS_006_RBAC_Quota_Create_Queries("1.0")]): with cleanup("quota23"): @@ -145,13 +145,13 @@ def feature(self, node="clickhouse1"): FOR INTERVAL 2 DAY MAX QUERIES 124, \ FOR INTERVAL 1 HOUR TRACKING ONLY') - with Scenario("I create quota assigned to one role", flags=TE, requirements=[ + with Scenario("I create quota assigned to one role", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Assignment("1.0")]): with cleanup("quota24"): with When("I create quota for role"): node.query("CREATE QUOTA quota24 TO role0") - with Scenario("I create quota to assign to role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I create quota to assign to role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Assignment("1.0")]): role = "role1" with Given(f"I drop {role} if it exists"): @@ -161,7 +161,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE QUOTA quota0 TO {role}", exitcode=exitcode, message=message) del role - with Scenario("I create quota to assign to all except role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I create quota to assign to all except role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Assignment("1.0")]): role = "role1" with Given(f"I drop {role} if it exists"): @@ -171,36 +171,36 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE QUOTA quota0 TO ALL EXCEPT {role}", exitcode=exitcode, message=message) del role - with Scenario("I create quota assigned to no role", flags=TE, requirements=[ + with Scenario("I create quota assigned to no role", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Assignment_None("1.0")]): with When("I create quota for no role"): node.query("CREATE QUOTA quota24 TO NONE") - with Scenario("I create quota assigned to multiple roles", flags=TE, requirements=[ + with Scenario("I create quota assigned to multiple roles", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Assignment("1.0")]): with cleanup("quota25"): with When("I create quota for multiple roles"): node.query("CREATE QUOTA quota25 TO role0, user0") - with Scenario("I create quota assigned to all", flags=TE,requirements=[ + with Scenario("I create quota assigned to all", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Assignment_All("1.0")]): with cleanup("quota26"): with When("I create quota for all"): node.query("CREATE QUOTA quota26 TO ALL") - with Scenario("I create quota assigned to all except one role", flags=TE, requirements=[ + with Scenario("I create quota assigned to all except one role", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Assignment_Except("1.0")]): with cleanup("quota27"): with When("I create quota for all except one role"): node.query("CREATE QUOTA quota27 TO ALL EXCEPT role0") - with Scenario("I create quota assigned to all except multiple roles", flags=TE, requirements=[ + with Scenario("I create quota assigned to all except multiple roles", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Assignment_Except("1.0")]): with cleanup("quota28"): with When("I create quota for all except multiple roles"): node.query("CREATE QUOTA quota28 TO ALL EXCEPT role0, user0") - with Scenario("I create quota on cluster", flags=TE, requirements=[ + with Scenario("I create quota on cluster", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Cluster("1.0")]): try: with When("I run create quota command on cluster"): @@ -215,7 +215,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the quota from cluster"): node.query("DROP QUOTA IF EXISTS quota29 ON CLUSTER sharded_cluster") - with Scenario("I create quota on nonexistent cluster, throws exception", flags=TE, requirements=[ + with Scenario("I create quota on nonexistent cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_Quota_Create_Cluster("1.0")]): with When("I run create quota on a cluster"): exitcode, message = errors.cluster_not_found("fake_cluster") diff --git a/tests/testflows/rbac/tests/syntax/create_role.py b/tests/testflows/rbac/tests/syntax/create_role.py index 86db48691bd..1cb10077570 100755 --- a/tests/testflows/rbac/tests/syntax/create_role.py +++ b/tests/testflows/rbac/tests/syntax/create_role.py @@ -32,13 +32,13 @@ def feature(self, node="clickhouse1"): with Given(f"I ensure I do have role {role}"): node.query(f"CREATE ROLE OR REPLACE {role}") - with Scenario("I create role with no options", flags=TE, requirements=[ + with Scenario("I create role with no options", requirements=[ RQ_SRS_006_RBAC_Role_Create("1.0")]): with cleanup("role0"): with When("I create role"): node.query("CREATE ROLE role0") - with Scenario("I create role that already exists, throws exception", flags=TE, requirements=[ + with Scenario("I create role that already exists, throws exception", requirements=[ RQ_SRS_006_RBAC_Role_Create("1.0")]): role = "role0" with cleanup(role): @@ -49,7 +49,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROLE {role}", exitcode=exitcode, message=message) del role - with Scenario("I create role if not exists, role does not exist", flags=TE, requirements=[ + with Scenario("I create role if not exists, role does not exist", requirements=[ RQ_SRS_006_RBAC_Role_Create_IfNotExists("1.0")]): role = "role1" with cleanup(role): @@ -57,7 +57,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROLE IF NOT EXISTS {role}") del role - with Scenario("I create role if not exists, role does exist", flags=TE, requirements=[ + with Scenario("I create role if not exists, role does exist", requirements=[ RQ_SRS_006_RBAC_Role_Create_IfNotExists("1.0")]): role = "role1" with cleanup(role): @@ -66,7 +66,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROLE IF NOT EXISTS {role}") del role - with Scenario("I create role or replace, role does not exist", flags=TE, requirements=[ + with Scenario("I create role or replace, role does not exist", requirements=[ RQ_SRS_006_RBAC_Role_Create_Replace("1.0")]): role = "role2" with cleanup(role): @@ -74,7 +74,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROLE OR REPLACE {role}") del role - with Scenario("I create role or replace, role does exist", flags=TE, requirements=[ + with Scenario("I create role or replace, role does exist", requirements=[ RQ_SRS_006_RBAC_Role_Create_Replace("1.0")]): role = "role2" with cleanup(role): @@ -83,7 +83,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROLE OR REPLACE {role}") del role - with Scenario("I create role on cluster", flags=TE, requirements=[ + with Scenario("I create role on cluster", requirements=[ RQ_SRS_006_RBAC_Role_Create("1.0")]): try: with When("I have a role on a cluster"): @@ -96,19 +96,19 @@ def feature(self, node="clickhouse1"): with Finally("I drop the role"): node.query("DROP ROLE IF EXISTS role1,role2 ON CLUSTER sharded_cluster") - with Scenario("I create role on nonexistent cluster, throws exception", flags=TE, requirements=[ + with Scenario("I create role on nonexistent cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_Role_Create("1.0")]): with When("I run create role on a cluster"): exitcode, message = errors.cluster_not_found("fake_cluster") node.query("CREATE ROLE role1 ON CLUSTER fake_cluster", exitcode=exitcode, message=message) - with Scenario("I create role with settings profile", flags=TE, requirements=[ + with Scenario("I create role with settings profile", requirements=[ RQ_SRS_006_RBAC_Role_Create_Settings("1.0")]): with cleanup("role3"): with When("I create role with settings profile"): node.query("CREATE ROLE role3 SETTINGS PROFILE default, max_memory_usage=10000000 WRITABLE") - with Scenario("I create role settings profile, fake profile, throws exception", flags=TE, requirements=[ + with Scenario("I create role settings profile, fake profile, throws exception", requirements=[ RQ_SRS_006_RBAC_Role_Create_Settings("1.0")]): with cleanup("role4a"): with Given("I ensure profile profile0 does not exist"): @@ -117,7 +117,7 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.settings_profile_not_found_in_disk("profile0") node.query("CREATE ROLE role4a SETTINGS PROFILE profile0", exitcode=exitcode, message=message) - with Scenario("I create role with settings without profile", flags=TE, requirements=[ + with Scenario("I create role with settings without profile", requirements=[ RQ_SRS_006_RBAC_Role_Create_Settings("1.0")]): with cleanup("role4"): with When("I create role with settings without profile"): diff --git a/tests/testflows/rbac/tests/syntax/create_row_policy.py b/tests/testflows/rbac/tests/syntax/create_row_policy.py index 4f35f47ff4b..8bf83579dd5 100755 --- a/tests/testflows/rbac/tests/syntax/create_row_policy.py +++ b/tests/testflows/rbac/tests/syntax/create_row_policy.py @@ -41,21 +41,21 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROLE role0") node.query(f"CREATE ROLE role1") - with Scenario("I create row policy with no options", flags=TE, requirements=[ + with Scenario("I create row policy with no options", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy0"): with When("I create row policy"): node.query("CREATE ROW POLICY policy0 ON default.foo") - with Scenario("I create row policy using short syntax with no options", flags=TE, requirements=[ + with Scenario("I create row policy using short syntax with no options", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy1"): with When("I create row policy short form"): node.query("CREATE POLICY policy1 ON default.foo") - with Scenario("I create row policy that already exists, throws exception", flags=TE, requirements=[ + with Scenario("I create row policy that already exists, throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): policy = "policy0" @@ -66,14 +66,14 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROW POLICY {policy} ON default.foo", exitcode=exitcode, message=message) del policy - with Scenario("I create row policy if not exists, policy does not exist", flags=TE, requirements=[ + with Scenario("I create row policy if not exists, policy does not exist", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_IfNotExists("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy2"): with When("I create row policy with if not exists"): node.query("CREATE ROW POLICY IF NOT EXISTS policy2 ON default.foo") - with Scenario("I create row policy if not exists, policy does exist", flags=TE, requirements=[ + with Scenario("I create row policy if not exists, policy does exist", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_IfNotExists("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): policy = "policy2" @@ -83,14 +83,14 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROW POLICY IF NOT EXISTS {policy} ON default.foo") del policy - with Scenario("I create row policy or replace, policy does not exist", flags=TE, requirements=[ + with Scenario("I create row policy or replace, policy does not exist", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Replace("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy3"): with When("I create row policy with or replace"): node.query("CREATE ROW POLICY OR REPLACE policy3 ON default.foo") - with Scenario("I create row policy or replace, policy does exist", flags=TE, requirements=[ + with Scenario("I create row policy or replace, policy does exist", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Replace("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): policy = "policy3" @@ -100,21 +100,21 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROW POLICY OR REPLACE {policy} ON default.foo") del policy - with Scenario("I create row policy as permissive", flags=TE, requirements=[ + with Scenario("I create row policy as permissive", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Access_Permissive("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy4"): with When("I create row policy as permissive"): node.query("CREATE ROW POLICY policy4 ON default.foo AS PERMISSIVE") - with Scenario("I create row policy as restrictive", flags=TE, requirements=[ + with Scenario("I create row policy as restrictive", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Access_Restrictive("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy5"): with When("I create row policy as restrictive"): node.query("CREATE ROW POLICY policy5 ON default.foo AS RESTRICTIVE") - with Scenario("I create row policy for select", flags=TE, requirements=[ + with Scenario("I create row policy for select", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_ForSelect("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_Condition("1.0")]): @@ -122,21 +122,21 @@ def feature(self, node="clickhouse1"): with When("I create row policy with for select"): node.query("CREATE ROW POLICY policy6 ON default.foo FOR SELECT USING x > 10") - with Scenario("I create row policy using condition", flags=TE, requirements=[ + with Scenario("I create row policy using condition", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Condition("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy6"): with When("I create row policy with condition"): node.query("CREATE ROW POLICY policy6 ON default.foo USING x > 10") - with Scenario("I create row policy assigned to one role", flags=TE, requirements=[ + with Scenario("I create row policy assigned to one role", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Assignment("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy7"): with When("I create row policy for one role"): node.query("CREATE ROW POLICY policy7 ON default.foo TO role0") - with Scenario("I create row policy to assign to role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I create row policy to assign to role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Assignment("1.0")]): role = "role2" with cleanup("policy8a"): @@ -147,7 +147,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROW POLICY policy8a ON default.foo TO {role}", exitcode=exitcode, message=message) del role - with Scenario("I create row policy to assign to all excpet role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I create row policy to assign to all excpet role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Assignment("1.0")]): role = "role2" with cleanup("policy8a"): @@ -158,42 +158,42 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE ROW POLICY policy8a ON default.foo TO ALL EXCEPT {role}", exitcode=exitcode, message=message) del role - with Scenario("I create row policy assigned to multiple roles", flags=TE, requirements=[ + with Scenario("I create row policy assigned to multiple roles", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Assignment("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy8b"): with When("I create row policy for multiple roles"): node.query("CREATE ROW POLICY policy8b ON default.foo TO role0, role1") - with Scenario("I create row policy assigned to all", flags=TE, requirements=[ + with Scenario("I create row policy assigned to all", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_All("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy9"): with When("I create row policy for all"): node.query("CREATE ROW POLICY policy9 ON default.foo TO ALL") - with Scenario("I create row policy assigned to all except one role", flags=TE, requirements=[ + with Scenario("I create row policy assigned to all except one role", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_AllExcept("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy10"): with When("I create row policy for all except one"): node.query("CREATE ROW POLICY policy10 ON default.foo TO ALL EXCEPT role0") - with Scenario("I create row policy assigned to all except multiple roles", flags=TE, requirements=[ + with Scenario("I create row policy assigned to all except multiple roles", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_AllExcept("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy11"): with When("I create row policy for all except multiple roles"): node.query("CREATE ROW POLICY policy11 ON default.foo TO ALL EXCEPT role0, role1") - with Scenario("I create row policy assigned to none", flags=TE, requirements=[ + with Scenario("I create row policy assigned to none", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_None("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with cleanup("policy11"): with When("I create row policy for none"): node.query("CREATE ROW POLICY policy11 ON default.foo TO NONE") - with Scenario("I create row policy on cluster", flags=TE, requirements=[ + with Scenario("I create row policy on cluster", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): try: @@ -203,14 +203,14 @@ def feature(self, node="clickhouse1"): with Finally("I drop the row policy from cluster"): node.query("DROP ROW POLICY IF EXISTS policy12 ON default.foo ON CLUSTER sharded_cluster") - with Scenario("I create row policy on fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I create row policy on fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): with When("I run create row policy command"): exitcode, message = errors.cluster_not_found("fake_cluster") node.query("CREATE ROW POLICY policy13 ON CLUSTER fake_cluster ON default.foo", exitcode=exitcode, message=message) - with Scenario("I create row policy on cluster after table", flags=TE, requirements=[ + with Scenario("I create row policy on cluster after table", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster("1.0"), RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]): try: diff --git a/tests/testflows/rbac/tests/syntax/create_settings_profile.py b/tests/testflows/rbac/tests/syntax/create_settings_profile.py index 6d720af21bc..8976ce6843a 100755 --- a/tests/testflows/rbac/tests/syntax/create_settings_profile.py +++ b/tests/testflows/rbac/tests/syntax/create_settings_profile.py @@ -39,13 +39,13 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER user0") node.query(f"CREATE ROLE role0") - with Scenario("I create settings profile with no options", flags=TE, requirements=[ + with Scenario("I create settings profile with no options", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create("1.0")]): with cleanup("profile0"): with When("I create settings profile"): node.query("CREATE SETTINGS PROFILE profile0") - with Scenario("I create settings profile that already exists, throws exception", flags=TE, requirements=[ + with Scenario("I create settings profile that already exists, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create("1.0")]): profile = "profile0" with cleanup(profile): @@ -55,13 +55,13 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE SETTINGS PROFILE {profile}", exitcode=exitcode, message=message) del profile - with Scenario("I create settings profile if not exists, profile does not exist", flags=TE, requirements=[ + with Scenario("I create settings profile if not exists, profile does not exist", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_IfNotExists("1.0")]): with cleanup("profile1"): with When("I create settings profile with if not exists"): node.query("CREATE SETTINGS PROFILE IF NOT EXISTS profile1") - with Scenario("I create settings profile if not exists, profile does exist", flags=TE, requirements=[ + with Scenario("I create settings profile if not exists, profile does exist", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_IfNotExists("1.0")]): profile = "profile1" with cleanup(profile): @@ -70,78 +70,78 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE SETTINGS PROFILE IF NOT EXISTS {profile}") del profile - with Scenario("I create settings profile or replace, profile does not exist", flags=TE, requirements=[ + with Scenario("I create settings profile or replace, profile does not exist", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Replace("1.0")]): with cleanup("profile2"): with When("I create settings policy with or replace"): node.query("CREATE SETTINGS PROFILE OR REPLACE profile2") - with Scenario("I create settings profile or replace, profile does exist", flags=TE, requirements=[ + with Scenario("I create settings profile or replace, profile does exist", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Replace("1.0")]): with cleanup("profile2"): create_profile("profile2") with When("I create settings policy with or replace"): node.query("CREATE SETTINGS PROFILE OR REPLACE profile2") - with Scenario("I create settings profile short form", flags=TE, requirements=[ + with Scenario("I create settings profile short form", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create("1.0")]): with cleanup("profile3"): with When("I create settings profile short form"): node.query("CREATE PROFILE profile3") - with Scenario("I create settings profile with a setting value", flags=TE, requirements=[ + with Scenario("I create settings profile with a setting value", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Variables("1.0"), RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Value("1.0")]): with cleanup("profile4"): with When("I create settings profile with settings"): node.query("CREATE SETTINGS PROFILE profile4 SETTINGS max_memory_usage = 100000001") - with Scenario("I create settings profile with a setting value, does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I create settings profile with a setting value, does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Variables("1.0"), RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Value("1.0")]): with When("I create settings profile using settings and nonexistent value"): exitcode, message = errors.unknown_setting("fake_setting") node.query("CREATE SETTINGS PROFILE profile0 SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message) - with Scenario("I create settings profile with a min setting value", flags=TE, requirements=[ + with Scenario("I create settings profile with a min setting value", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]): with cleanup("profile5"), cleanup("profile6"): with When("I create settings profile with min setting with and without equals"): node.query("CREATE SETTINGS PROFILE profile5 SETTINGS max_memory_usage MIN 100000001") node.query("CREATE SETTINGS PROFILE profile6 SETTINGS max_memory_usage MIN = 100000001") - with Scenario("I create settings profile with a max setting value", flags=TE, requirements=[ + with Scenario("I create settings profile with a max setting value", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]): with cleanup("profile7"), cleanup("profile8"): with When("I create settings profile with max setting with and without equals"): node.query("CREATE SETTINGS PROFILE profile7 SETTINGS max_memory_usage MAX 100000001") node.query("CREATE SETTINGS PROFILE profile8 SETTINGS max_memory_usage MAX = 100000001") - with Scenario("I create settings profile with min and max setting values", flags=TE, requirements=[ + with Scenario("I create settings profile with min and max setting values", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]): with cleanup("profile9"): with When("I create settings profile with min and max setting"): node.query("CREATE SETTINGS PROFILE profile9 SETTINGS max_memory_usage MIN 100000001 MAX 200000001") - with Scenario("I create settings profile with a readonly setting", flags=TE, requirements=[ + with Scenario("I create settings profile with a readonly setting", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]): with cleanup("profile10"): with When("I create settings profile with readonly"): node.query("CREATE SETTINGS PROFILE profile10 SETTINGS max_memory_usage READONLY") - with Scenario("I create settings profile with a writable setting", flags=TE, requirements=[ + with Scenario("I create settings profile with a writable setting", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]): with cleanup("profile21"): with When("I create settings profile with writable"): node.query("CREATE SETTINGS PROFILE profile21 SETTINGS max_memory_usage WRITABLE") - with Scenario("I create settings profile with inherited settings", flags=TE, requirements=[ + with Scenario("I create settings profile with inherited settings", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Inherit("1.0")]): with cleanup("profile11"): with When("I create settings profile with inherit"): node.query("CREATE SETTINGS PROFILE profile11 SETTINGS INHERIT 'default'") - with Scenario("I create settings profile with inherit/from profile, fake profile, throws exception", flags=TE, requirements=[ + with Scenario("I create settings profile with inherit/from profile, fake profile, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Inherit("1.0")]): profile = "profile3" with Given(f"I ensure that profile {profile} does not exist"): @@ -153,13 +153,13 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE PROFILE profile0 SETTINGS {source} {profile}", exitcode=exitcode, message=message) del profile - with Scenario("I create settings profile with inherited settings other form", flags=TE, requirements=[ + with Scenario("I create settings profile with inherited settings other form", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Inherit("1.0")]): with cleanup("profile12"): with When("I create settings profile with inherit short form"): node.query("CREATE PROFILE profile12 SETTINGS PROFILE 'default'") - with Scenario("I create settings profile with multiple settings", flags=TE, requirements=[ + with Scenario("I create settings profile with multiple settings", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]): with cleanup("profile13"): with When("I create settings profile with multiple settings"): @@ -167,7 +167,7 @@ def feature(self, node="clickhouse1"): " SETTINGS max_memory_usage = 100000001" " SETTINGS max_memory_usage_for_user = 100000001") - with Scenario("I create settings profile with multiple settings short form", flags=TE, requirements=[ + with Scenario("I create settings profile with multiple settings short form", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]): with cleanup("profile14"): with When("I create settings profile with multiple settings short form"): @@ -175,13 +175,13 @@ def feature(self, node="clickhouse1"): " SETTINGS max_memory_usage = 100000001," " max_memory_usage_for_user = 100000001") - with Scenario("I create settings profile assigned to one role", flags=TE, requirements=[ + with Scenario("I create settings profile assigned to one role", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment("1.0")]): with cleanup("profile15"): with When("I create settings profile for a role"): node.query("CREATE SETTINGS PROFILE profile15 TO role0") - with Scenario("I create settings profile to assign to role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I create settings profile to assign to role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment("1.0")]): role = "role1" with Given(f"I drop {role} if it exists"): @@ -191,7 +191,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE SETTINGS PROFILE profile0 TO {role}", exitcode=exitcode, message=message) del role - with Scenario("I create settings profile to assign to all except role that does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I create settings profile to assign to all except role that does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment("1.0")]): role = "role1" with Given(f"I drop {role} if it exists"): @@ -201,37 +201,37 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE SETTINGS PROFILE profile0 TO ALL EXCEPT {role}", exitcode=exitcode, message=message) del role - with Scenario("I create settings profile assigned to multiple roles", flags=TE, requirements=[ + with Scenario("I create settings profile assigned to multiple roles", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment("1.0")]): with cleanup("profile16"): with When("I create settings profile for multiple roles"): node.query("CREATE SETTINGS PROFILE profile16 TO role0, user0") - with Scenario("I create settings profile assigned to all", flags=TE, requirements=[ + with Scenario("I create settings profile assigned to all", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_All("1.0")]): with cleanup("profile17"): with When("I create settings profile for all"): node.query("CREATE SETTINGS PROFILE profile17 TO ALL") - with Scenario("I create settings profile assigned to all except one role", flags=TE,requirements=[ + with Scenario("I create settings profile assigned to all except one role",requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_AllExcept("1.0")]): with cleanup("profile18"): with When("I create settings profile for all except one role"): node.query("CREATE SETTINGS PROFILE profile18 TO ALL EXCEPT role0") - with Scenario("I create settings profile assigned to all except multiple roles", flags=TE, requirements=[ + with Scenario("I create settings profile assigned to all except multiple roles", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_AllExcept("1.0")]): with cleanup("profile19"): with When("I create settings profile for all except multiple roles"): node.query("CREATE SETTINGS PROFILE profile19 TO ALL EXCEPT role0, user0") - with Scenario("I create settings profile assigned to none", flags=TE, requirements=[ + with Scenario("I create settings profile assigned to none", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_None("1.0")]): with cleanup("profile22"): with When("I create settings profile for none"): node.query("CREATE SETTINGS PROFILE profile22 TO NONE") - with Scenario("I create settings profile on cluster", flags=TE, requirements=[ + with Scenario("I create settings profile on cluster", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_OnCluster("1.0")]): try: with When("I run create settings profile command"): @@ -243,7 +243,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the settings profile"): node.query("DROP SETTINGS PROFILE IF EXISTS profile20 ON CLUSTER sharded_cluster") - with Scenario("I create settings profile on fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I create settings profile on fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Create_OnCluster("1.0")]): with When("I run create settings profile command"): exitcode, message = errors.cluster_not_found("fake_cluster") diff --git a/tests/testflows/rbac/tests/syntax/create_user.py b/tests/testflows/rbac/tests/syntax/create_user.py index d410dd1ab6e..326446e4620 100755 --- a/tests/testflows/rbac/tests/syntax/create_user.py +++ b/tests/testflows/rbac/tests/syntax/create_user.py @@ -25,7 +25,7 @@ def feature(self, node="clickhouse1"): @contextmanager def cleanup(user): try: - with Given("I ensure the user does not already exist", flags=TE): + with Given("I ensure the user does not already exist"): node.query(f"DROP USER IF EXISTS {user}") yield finally: @@ -36,14 +36,14 @@ def feature(self, node="clickhouse1"): with Given(f"I ensure I do have user {user}"): node.query(f"CREATE USER OR REPLACE {user}") - with Scenario("I create user with no options", flags=TE, requirements=[ + with Scenario("I create user with no options", requirements=[ RQ_SRS_006_RBAC_User_Create("1.0"), RQ_SRS_006_RBAC_User_Create_Host_Default("1.0")]): with cleanup("user0"): with When("I create a user with no options"): node.query("CREATE USER user0") - with Scenario("I create user that already exists, throws exception", flags=TE, requirements=[ + with Scenario("I create user that already exists, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Create("1.0"), RQ_SRS_006_RBAC_User_Create_Host_Default("1.0")]): user = "user0" @@ -54,7 +54,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER {user}", exitcode=exitcode, message=message) del user - with Scenario("I create user with if not exists, user does not exist", flags=TE, requirements=[ + with Scenario("I create user with if not exists, user does not exist", requirements=[ RQ_SRS_006_RBAC_User_Create_IfNotExists("1.0")]): user = "user0" with cleanup(user): @@ -63,7 +63,7 @@ def feature(self, node="clickhouse1"): del user #Bug exists, mark as xfail - with Scenario("I create user with if not exists, user does exist", flags=TE, requirements=[ + with Scenario("I create user with if not exists, user does exist", requirements=[ RQ_SRS_006_RBAC_User_Create_IfNotExists("1.0")]): user = "user0" with cleanup(user): @@ -72,7 +72,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER IF NOT EXISTS {user}") del user - with Scenario("I create user or replace, user does not exist", flags=TE, requirements=[ + with Scenario("I create user or replace, user does not exist", requirements=[ RQ_SRS_006_RBAC_User_Create_Replace("1.0")]): user = "user0" with cleanup(user): @@ -80,7 +80,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER OR REPLACE {user}") del user - with Scenario("I create user or replace, user does exist", flags=TE, requirements=[ + with Scenario("I create user or replace, user does exist", requirements=[ RQ_SRS_006_RBAC_User_Create_Replace("1.0")]): user = "user0" with cleanup(user): @@ -89,33 +89,33 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER OR REPLACE {user}") del user - with Scenario("I create user with no password", flags=TE, requirements=[ + with Scenario("I create user with no password", requirements=[ RQ_SRS_006_RBAC_User_Create_Password_NoPassword("1.0")]): with cleanup("user1"): with When("I create a user with no password"): node.query("CREATE USER user1 IDENTIFIED WITH NO_PASSWORD") - with Scenario("I create user with plaintext password", flags=TE, requirements=[ + with Scenario("I create user with plaintext password", requirements=[ RQ_SRS_006_RBAC_User_Create_Password_PlainText("1.0")]): with cleanup("user1"): with When("I create a user with plaintext password"): node.query("CREATE USER user1 IDENTIFIED WITH PLAINTEXT_PASSWORD BY 'mypassword'") - with Scenario("I create user with sha256 password", flags=TE, requirements=[ + with Scenario("I create user with sha256 password", requirements=[ RQ_SRS_006_RBAC_User_Create_Password_Sha256Password("1.0")]): with cleanup("user2"): with When("I create a user with sha256 password"): password = hashlib.sha256("mypassword".encode("utf-8")).hexdigest() node.query(f"CREATE USER user2 IDENTIFIED WITH SHA256_PASSWORD BY '{password}'") - with Scenario("I create user with sha256 password using IDENTIFIED BY", flags=TE, requirements=[ + with Scenario("I create user with sha256 password using IDENTIFIED BY", requirements=[ RQ_SRS_006_RBAC_User_Create_Password_Sha256Password("1.0")]): with cleanup("user2"): with When("I create a user with sha256 password using short form"): password = hashlib.sha256("mypassword".encode("utf-8")).hexdigest() node.query(f"CREATE USER user2 IDENTIFIED BY '{password}'") - with Scenario("I create user with sha256_hash password", flags=TE, requirements=[ + with Scenario("I create user with sha256_hash password", requirements=[ RQ_SRS_006_RBAC_User_Create_Password_Sha256Hash("1.0")]): with cleanup("user3"): with When("I create a user with sha256_hash"): @@ -124,13 +124,13 @@ def feature(self, node="clickhouse1"): password = hash(hash("mypassword")) node.query(f"CREATE USER user3 IDENTIFIED WITH SHA256_HASH BY '{password}'") - with Scenario("I create user with double sha1 password", flags=TE, requirements=[ + with Scenario("I create user with double sha1 password", requirements=[ RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Password("1.0")]): with cleanup("user3"): with When("I create a user with double_sha1_password"): node.query(f"CREATE USER user3 IDENTIFIED WITH DOUBLE_SHA1_PASSWORD BY 'mypassword'") - with Scenario("I create user with double sha1 hash", flags=TE, requirements=[ + with Scenario("I create user with double sha1 hash", requirements=[ RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Hash("1.0")]): with cleanup("user3"): with When("I create a user with double_sha1_hash"): @@ -139,55 +139,55 @@ def feature(self, node="clickhouse1"): password = hash(hash("mypassword")) node.query(f"CREATE USER user3 IDENTIFIED WITH DOUBLE_SHA1_HASH BY '{password}'") - with Scenario("I create user with host name", flags=TE, requirements=[ + with Scenario("I create user with host name", requirements=[ RQ_SRS_006_RBAC_User_Create_Host_Name("1.0")]): with cleanup("user4"): with When("I create a user with host name"): node.query("CREATE USER user4 HOST NAME 'localhost', NAME 'clickhouse.com'") - with Scenario("I create user with host regexp", flags=TE, requirements=[ + with Scenario("I create user with host regexp", requirements=[ RQ_SRS_006_RBAC_User_Create_Host_Regexp("1.0")]): with cleanup("user5"): with When("I create a user with host regexp"): node.query("CREATE USER user5 HOST REGEXP 'lo.?*host', REGEXP 'lo*host'") - with Scenario("I create user with host ip", flags=TE, requirements=[ + with Scenario("I create user with host ip", requirements=[ RQ_SRS_006_RBAC_User_Create_Host_IP("1.0")]): with cleanup("user6"): with When("I create a user with host ip"): node.query("CREATE USER user6 HOST IP '127.0.0.1', IP '127.0.0.2'") - with Scenario("I create user with host like", flags=TE, requirements=[ + with Scenario("I create user with host like", requirements=[ RQ_SRS_006_RBAC_User_Create_Host_Like("1.0")]): with cleanup("user7"): with When("I create a user with host like"): node.query("CREATE USER user7 HOST LIKE 'local%'") - with Scenario("I create user with host none", flags=TE, requirements=[ + with Scenario("I create user with host none", requirements=[ RQ_SRS_006_RBAC_User_Create_Host_None("1.0")]): with cleanup("user7"): with When("I create a user with host none"): node.query("CREATE USER user7 HOST NONE") - with Scenario("I create user with host local", flags=TE, requirements=[ + with Scenario("I create user with host local", requirements=[ RQ_SRS_006_RBAC_User_Create_Host_Local("1.0")]): with cleanup("user7"): with When("I create a user with host local"): node.query("CREATE USER user7 HOST LOCAL") - with Scenario("I create user with host any", flags=TE, requirements=[ + with Scenario("I create user with host any", requirements=[ RQ_SRS_006_RBAC_User_Create_Host_Any("1.0")]): with cleanup("user7"): with When("I create a user with host any"): node.query("CREATE USER user7 HOST ANY") - with Scenario("I create user with default role set to none", flags=TE, requirements=[ + with Scenario("I create user with default role set to none", requirements=[ RQ_SRS_006_RBAC_User_Create_DefaultRole_None("1.0")]): with cleanup("user8"): with When("I create a user with no default role"): node.query("CREATE USER user8 DEFAULT ROLE NONE") - with Scenario("I create user with default role", flags=TE, requirements=[ + with Scenario("I create user with default role", requirements=[ RQ_SRS_006_RBAC_User_Create_DefaultRole("1.0")]): with Given("I have a role"): node.query("CREATE ROLE default") @@ -197,7 +197,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the role"): node.query("DROP ROLE default") - with Scenario("I create user default role, role doesn't exist, throws exception", flags=TE, requirements=[ + with Scenario("I create user default role, role doesn't exist, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Create_DefaultRole("1.0")]): with cleanup("user12"): role = "role0" @@ -208,7 +208,7 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER user12 DEFAULT ROLE {role}",exitcode=exitcode, message=message) del role - with Scenario("I create user default role, all except role doesn't exist, throws exception", flags=TE, requirements=[ + with Scenario("I create user default role, all except role doesn't exist, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Create_DefaultRole("1.0")]): with cleanup("user12"): role = "role0" @@ -219,19 +219,19 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER user12 DEFAULT ROLE ALL EXCEPT {role}",exitcode=exitcode, message=message) del role - with Scenario("I create user with all roles set to default", flags=TE, requirements=[ + with Scenario("I create user with all roles set to default", requirements=[ RQ_SRS_006_RBAC_User_Create_DefaultRole_All("1.0")]): with cleanup("user10"): with When("I create a user with all roles as default"): node.query("CREATE USER user10 DEFAULT ROLE ALL") - with Scenario("I create user with settings profile", flags=TE, requirements=[ + with Scenario("I create user with settings profile", requirements=[ RQ_SRS_006_RBAC_User_Create_Settings("1.0")]): with cleanup("user11"): with When("I create a user with a settings profile"): node.query("CREATE USER user11 SETTINGS PROFILE default, max_memory_usage=10000000 READONLY") - with Scenario("I create user settings profile, fake profile, throws exception", flags=TE, requirements=[ + with Scenario("I create user settings profile, fake profile, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Create_Settings("1.0")]): with cleanup("user18a"): profile = "profile0" @@ -242,20 +242,20 @@ def feature(self, node="clickhouse1"): node.query("CREATE USER user18a SETTINGS PROFILE profile0", exitcode=exitcode, message=message) del profile - with Scenario("I create user settings with a fake setting, throws exception", flags=TE, requirements=[ + with Scenario("I create user settings with a fake setting, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Create_Settings("1.0")]): with cleanup("user18b"): with When("I create settings profile using settings and nonexistent value"): exitcode, message = errors.unknown_setting("fake_setting") node.query("CREATE USER user18b SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message) - with Scenario("I create user with settings without profile", flags=TE, requirements=[ + with Scenario("I create user with settings without profile", requirements=[ RQ_SRS_006_RBAC_User_Create_Settings("1.0")]): with cleanup("user12"): with When("I create a user with settings and no profile"): node.query("CREATE USER user12 SETTINGS max_memory_usage=10000000 READONLY") - with Scenario("I create user on cluster", flags=TE, requirements=[ + with Scenario("I create user on cluster", requirements=[ RQ_SRS_006_RBAC_User_Create_OnCluster("1.0")]): try: with When("I create user on cluster"): @@ -264,7 +264,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the user"): node.query("DROP USER user13 ON CLUSTER sharded_cluster") - with Scenario("I create user on fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I create user on fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Create_OnCluster("1.0")]): with When("I create user on fake cluster"): exitcode, message = errors.cluster_not_found("fake_cluster") diff --git a/tests/testflows/rbac/tests/syntax/drop_quota.py b/tests/testflows/rbac/tests/syntax/drop_quota.py index 099951e3f19..879964e46fb 100755 --- a/tests/testflows/rbac/tests/syntax/drop_quota.py +++ b/tests/testflows/rbac/tests/syntax/drop_quota.py @@ -23,20 +23,20 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE QUOTA {quota}") yield finally: - with Finally("I drop the quota"): + with Finally("I drop the quota", flags=TE): node.query(f"DROP QUOTA IF EXISTS {quota}") def cleanup_quota(quota): with Given(f"I ensure that quota {quota} does not exist"): node.query(f"DROP QUOTA IF EXISTS {quota}") - with Scenario("I drop quota with no options", flags=TE, requirements=[ + with Scenario("I drop quota with no options", requirements=[ RQ_SRS_006_RBAC_Quota_Drop("1.0")]): with cleanup("quota0"): with When("I run drop quota command"): node.query("DROP QUOTA quota0") - with Scenario("I drop quota, does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I drop quota, does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_Quota_Drop("1.0")]): quota = "quota0" cleanup_quota(quota) @@ -45,31 +45,31 @@ def feature(self, node="clickhouse1"): node.query(f"DROP QUOTA {quota}", exitcode=exitcode, message=message) del quota - with Scenario("I drop quota if exists, quota exists", flags=TE, requirements=[ + with Scenario("I drop quota if exists, quota exists", requirements=[ RQ_SRS_006_RBAC_Quota_Drop_IfExists("1.0")]): with cleanup("quota1"): with When("I run drop quota command"): node.query("DROP QUOTA IF EXISTS quota1") - with Scenario("I drop quota if exists, quota does not exist", flags=TE, requirements=[ + with Scenario("I drop quota if exists, quota does not exist", requirements=[ RQ_SRS_006_RBAC_Quota_Drop_IfExists("1.0")]): cleanup_quota("quota2") with When("I run drop quota command, quota does not exist"): node.query("DROP QUOTA IF EXISTS quota2") - with Scenario("I drop default quota, throws error", flags=TE, requirements=[ + with Scenario("I drop default quota, throws error", requirements=[ RQ_SRS_006_RBAC_Quota_Drop("1.0")]): with When("I drop default quota"): exitcode, message = errors.cannot_remove_quota_default() node.query("DROP QUOTA default", exitcode=exitcode, message=message) - with Scenario("I drop multiple quotas", flags=TE, requirements=[ + with Scenario("I drop multiple quotas", requirements=[ RQ_SRS_006_RBAC_Quota_Drop("1.0")]): with cleanup("quota2"), cleanup("quota3"): with When("I run drop quota command"): node.query("DROP QUOTA quota2, quota3") - with Scenario("I drop quota on cluster", flags=TE, requirements=[ + with Scenario("I drop quota on cluster", requirements=[ RQ_SRS_006_RBAC_Quota_Drop_Cluster("1.0")]): try: with Given("I have a quota"): @@ -80,7 +80,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the quota in case it still exists"): node.query("DROP QUOTA IF EXISTS quota4 ON CLUSTER sharded_cluster") - with Scenario("I drop quota on fake cluster", flags=TE, requirements=[ + with Scenario("I drop quota on fake cluster", requirements=[ RQ_SRS_006_RBAC_Quota_Drop_Cluster("1.0")]): with When("I run drop quota command"): exitcode, message = errors.cluster_not_found("fake_cluster") diff --git a/tests/testflows/rbac/tests/syntax/drop_role.py b/tests/testflows/rbac/tests/syntax/drop_role.py index 0e6d0134649..87810dc0184 100755 --- a/tests/testflows/rbac/tests/syntax/drop_role.py +++ b/tests/testflows/rbac/tests/syntax/drop_role.py @@ -31,13 +31,13 @@ def feature(self, node="clickhouse1"): node.query(f"DROP ROLE IF EXISTS {role}") - with Scenario("I drop role with no options", flags=TE, requirements=[ + with Scenario("I drop role with no options", requirements=[ RQ_SRS_006_RBAC_Role_Drop("1.0")]): with setup("role0"): with When("I drop role"): node.query("DROP ROLE role0") - with Scenario("I drop role that doesn't exist, throws exception", flags=TE, requirements=[ + with Scenario("I drop role that doesn't exist, throws exception", requirements=[ RQ_SRS_006_RBAC_Role_Drop("1.0")]): role = "role0" cleanup_role(role) @@ -46,38 +46,38 @@ def feature(self, node="clickhouse1"): node.query(f"DROP ROLE {role}", exitcode=exitcode, message=message) del role - with Scenario("I drop multiple roles", flags=TE, requirements=[ + with Scenario("I drop multiple roles", requirements=[ RQ_SRS_006_RBAC_Role_Drop("1.0")]): with setup("role1"), setup("role2"): with When("I drop multiple roles"): node.query("DROP ROLE role1, role2") - with Scenario("I drop role that does not exist, using if exists", flags=TE, requirements=[ + with Scenario("I drop role that does not exist, using if exists", requirements=[ RQ_SRS_006_RBAC_Role_Drop_IfExists("1.0")]): with When("I drop role if exists"): node.query("DROP ROLE IF EXISTS role3") - with Scenario("I drop multiple roles where one does not exist", flags=TE, requirements=[ + with Scenario("I drop multiple roles where one does not exist", requirements=[ RQ_SRS_006_RBAC_Role_Drop_IfExists("1.0")]): with setup("role5"): with When("I drop multiple roles where one doesnt exist"): node.query("DROP ROLE IF EXISTS role3, role5") - with Scenario("I drop multiple roles where both do not exist", flags = TE, requirements=[ + with Scenario("I drop multiple roles where both do not exist", requirements=[ RQ_SRS_006_RBAC_Role_Drop_IfExists("1.0")]): with Given("I ensure role does not exist"): node.query("DROP ROLE IF EXISTS role6") with When("I drop the nonexistant roles"): node.query("DROP USER IF EXISTS role5, role6") - with Scenario("I drop role on cluster", flags=TE, requirements=[ + with Scenario("I drop role on cluster", requirements=[ RQ_SRS_006_RBAC_Role_Drop_Cluster("1.0")]): with Given("I have a role on cluster"): node.query("CREATE ROLE OR REPLACE role0 ON CLUSTER sharded_cluster") with When("I drop the role from the cluster"): node.query("DROP ROLE IF EXISTS role0 ON CLUSTER sharded_cluster") - with Scenario("I drop role on fake cluster", flags=TE, requirements=[ + with Scenario("I drop role on fake cluster", requirements=[ RQ_SRS_006_RBAC_Role_Drop_Cluster("1.0")]): with When("I run drop role command"): exitcode, message = errors.cluster_not_found("fake_cluster") diff --git a/tests/testflows/rbac/tests/syntax/drop_row_policy.py b/tests/testflows/rbac/tests/syntax/drop_row_policy.py index 2f04450a16a..357f5084bb3 100755 --- a/tests/testflows/rbac/tests/syntax/drop_row_policy.py +++ b/tests/testflows/rbac/tests/syntax/drop_row_policy.py @@ -39,21 +39,21 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE TABLE default.foo (x UInt64, y String) Engine=Memory") node.query(f"CREATE TABLE default.foo2 (x UInt64, y String) Engine=Memory") - with Scenario("I drop row policy with no options", flags=TE, requirements=[ + with Scenario("I drop row policy with no options", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): with cleanup(["policy1"]): with When("I drop row policy"): node.query("DROP ROW POLICY policy1 ON default.foo") - with Scenario("I drop row policy using short syntax with no options", flags=TE, requirements=[ + with Scenario("I drop row policy using short syntax with no options", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): with cleanup(["policy2"]): with When("I drop row policy short form"): node.query("DROP POLICY policy2 ON default.foo") - with Scenario("I drop row policy, does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I drop row policy, does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): policy = "policy1" @@ -63,42 +63,42 @@ def feature(self, node="clickhouse1"): node.query(f"DROP ROW POLICY {policy} ON default.foo", exitcode=exitcode, message=message) del policy - with Scenario("I drop row policy if exists, policy does exist", flags=TE, requirements=[ + with Scenario("I drop row policy if exists, policy does exist", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop_IfExists("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): with cleanup(["policy3"]): with When("I drop row policy if exists"): node.query("DROP ROW POLICY IF EXISTS policy3 ON default.foo") - with Scenario("I drop row policy if exists, policy doesn't exist", flags=TE, requirements=[ + with Scenario("I drop row policy if exists, policy doesn't exist", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop_IfExists("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): cleanup_policy("policy3") with When("I drop row policy if exists"): node.query("DROP ROW POLICY IF EXISTS policy3 ON default.foo") - with Scenario("I drop multiple row policies", flags=TE, requirements=[ + with Scenario("I drop multiple row policies", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): with cleanup(["policy3", "policy4"]): with When("I drop multiple row policies"): node.query("DROP ROW POLICY policy3, policy4 ON default.foo") - with Scenario("I drop row policy on multiple tables", flags=TE, requirements=[ + with Scenario("I drop row policy on multiple tables", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): with cleanup(["policy3"], ["default.foo","default.foo2"]): with When("I drop row policy on multiple tables"): node.query("DROP ROW POLICY policy3 ON default.foo, default.foo2") - with Scenario("I drop multiple row policies on multiple tables", flags=TE, requirements=[ + with Scenario("I drop multiple row policies on multiple tables", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): with cleanup(["policy3", "policy4"], ["default.foo","default.foo2"]): with When("I drop the row policies from the tables"): node.query("DROP ROW POLICY policy3 ON default.foo, policy4 ON default.foo2") - with Scenario("I drop row policy on cluster", flags=TE, requirements=[ + with Scenario("I drop row policy on cluster", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): try: @@ -110,7 +110,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the row policy in case it still exists"): node.query("DROP ROW POLICY IF EXISTS policy13 ON default.foo ON CLUSTER sharded_cluster") - with Scenario("I drop row policy on cluster after table", flags=TE, requirements=[ + with Scenario("I drop row policy on cluster after table", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): try: @@ -122,7 +122,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the row policy in case it still exists"): node.query("DROP ROW POLICY IF EXISTS policy12 ON default.foo ON CLUSTER sharded_cluster") - with Scenario("I drop row policy on fake cluster throws exception", flags=TE, requirements=[ + with Scenario("I drop row policy on fake cluster throws exception", requirements=[ RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster("1.0"), RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]): with When("I run drop row policy command"): diff --git a/tests/testflows/rbac/tests/syntax/drop_settings_profile.py b/tests/testflows/rbac/tests/syntax/drop_settings_profile.py index cb17815127f..514c3042679 100755 --- a/tests/testflows/rbac/tests/syntax/drop_settings_profile.py +++ b/tests/testflows/rbac/tests/syntax/drop_settings_profile.py @@ -30,13 +30,13 @@ def feature(self, node="clickhouse1"): with Given(f"I ensure that profile {profile} does not exist"): node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}") - with Scenario("I drop settings profile with no options", flags=TE, requirements=[ + with Scenario("I drop settings profile with no options", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Drop("1.0")]): with cleanup("profile0"): with When("I drop settings profile"): node.query("DROP SETTINGS PROFILE profile0") - with Scenario("I drop settings profile, does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I drop settings profile, does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Drop("1.0")]): profile = "profile0" cleanup_profile(profile) @@ -45,19 +45,19 @@ def feature(self, node="clickhouse1"): node.query("DROP SETTINGS PROFILE profile0", exitcode=exitcode, message=message) del profile - with Scenario("I drop settings profile short form", flags=TE, requirements=[ + with Scenario("I drop settings profile short form", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Drop("1.0")]): with cleanup("profile1"): with When("I drop settings profile short form"): node.query("DROP PROFILE profile1") - with Scenario("I drop settings profile if exists, profile does exist", flags=TE, requirements=[ + with Scenario("I drop settings profile if exists, profile does exist", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Drop_IfExists("1.0")]): with cleanup("profile2"): with When("I drop settings profile if exists"): node.query("DROP SETTINGS PROFILE IF EXISTS profile2") - with Scenario("I drop settings profile if exists, profile does not exist", flags=TE, requirements=[ + with Scenario("I drop settings profile if exists, profile does not exist", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Drop_IfExists("1.0")]): cleanup_profile("profile2") with When("I drop settings profile if exists"): @@ -69,13 +69,13 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.cannot_remove_settings_profile_default() node.query("DROP SETTINGS PROFILE default", exitcode=exitcode, message=message) - with Scenario("I drop multiple settings profiles", flags=TE, requirements=[ + with Scenario("I drop multiple settings profiles", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Drop("1.0")]): with cleanup("profile3"), cleanup("profile4"): with When("I drop multiple settings profiles"): node.query("DROP SETTINGS PROFILE profile3, profile4") - with Scenario("I drop settings profile on cluster", flags=TE, requirements=[ + with Scenario("I drop settings profile on cluster", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Drop_OnCluster("1.0")]): try: with Given("I have a settings profile"): @@ -86,7 +86,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the profile in case it still exists"): node.query("DROP SETTINGS PROFILE IF EXISTS profile5 ON CLUSTER sharded_cluster") - with Scenario("I drop settings profile on fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I drop settings profile on fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_Drop_OnCluster("1.0")]): with When("I run drop settings profile command"): exitcode, message = errors.cluster_not_found("fake_cluster") diff --git a/tests/testflows/rbac/tests/syntax/drop_user.py b/tests/testflows/rbac/tests/syntax/drop_user.py index 13f0093080a..9bd2433d487 100755 --- a/tests/testflows/rbac/tests/syntax/drop_user.py +++ b/tests/testflows/rbac/tests/syntax/drop_user.py @@ -30,13 +30,13 @@ def feature(self, node="clickhouse1"): with Given(f"I ensure that user {user} does not exist"): node.query(f"DROP USER IF EXISTS {user}") - with Scenario("I drop user with no options", flags=TE, requirements=[ + with Scenario("I drop user with no options", requirements=[ RQ_SRS_006_RBAC_User_Drop("1.0")]): with setup("user0"): with When("I drop user"): node.query("DROP USER user0") - with Scenario("I drop user, does not exist, throws exception", flags=TE, requirements=[ + with Scenario("I drop user, does not exist, throws exception", requirements=[ RQ_SRS_006_RBAC_User_Drop("1.0")]): user = "user0" cleanup_user(user) @@ -45,31 +45,31 @@ def feature(self, node="clickhouse1"): node.query(f"DROP USER {user}", exitcode=exitcode, message=message) del user - with Scenario("I drop multiple users", flags=TE, requirements=[ + with Scenario("I drop multiple users", requirements=[ RQ_SRS_006_RBAC_User_Drop("1.0")]): with setup("user1"), setup("user2"): with When("I drop multiple users"): node.query("DROP USER user1, user2") - with Scenario("I drop user if exists, user does exist", flags=TE, requirements=[ + with Scenario("I drop user if exists, user does exist", requirements=[ RQ_SRS_006_RBAC_User_Drop_IfExists("1.0")]): with setup("user3"): with When("I drop user that exists"): node.query("DROP USER IF EXISTS user3") - with Scenario("I drop user if exists, user does not exist", flags=TE, requirements=[ + with Scenario("I drop user if exists, user does not exist", requirements=[ RQ_SRS_006_RBAC_User_Drop_IfExists("1.0")]): cleanup_user("user3") with When("I drop nonexistant user"): node.query("DROP USER IF EXISTS user3") - with Scenario("I drop default user, throws error", flags=TE, requirements=[ + with Scenario("I drop default user, throws error", requirements=[ RQ_SRS_006_RBAC_User_Drop("1.0")]): with When("I drop user"): exitcode, message = errors.cannot_remove_user_default() node.query("DROP USER default", exitcode=exitcode, message=message) - with Scenario("I drop multiple users where one does not exist", flags=TE, requirements=[ + with Scenario("I drop multiple users where one does not exist", requirements=[ RQ_SRS_006_RBAC_User_Drop_IfExists("1.0")]): with setup("user3"): with When("I drop multiple users where one does not exist"): @@ -80,7 +80,7 @@ def feature(self, node="clickhouse1"): with When("I drop the nonexistant users"): node.query("DROP USER IF EXISTS user5, user6") - with Scenario("I drop user from specific cluster", flags=TE, requirements=[ + with Scenario("I drop user from specific cluster", requirements=[ RQ_SRS_006_RBAC_User_Drop_OnCluster("1.0")]): try: with Given("I have a user on cluster"): @@ -91,7 +91,7 @@ def feature(self, node="clickhouse1"): with Finally("I make sure the user is dropped"): node.query("DROP USER IF EXISTS user4 ON CLUSTER sharded_cluster") - with Scenario("I drop user from fake cluster", flags=TE, requirements=[ + with Scenario("I drop user from fake cluster", requirements=[ RQ_SRS_006_RBAC_User_Drop_OnCluster("1.0")]): with When("I drop a user from the fake cluster"): exitcode, message = errors.cluster_not_found("fake_cluster") diff --git a/tests/testflows/rbac/tests/syntax/feature.py b/tests/testflows/rbac/tests/syntax/feature.py index aac786ff85c..b7c23f8d7ee 100755 --- a/tests/testflows/rbac/tests/syntax/feature.py +++ b/tests/testflows/rbac/tests/syntax/feature.py @@ -3,32 +3,32 @@ from testflows.core import * @TestFeature @Name("syntax") def feature(self): - Feature(run=load("rbac.tests.syntax.create_user", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.alter_user", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.drop_user", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.show_create_user", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.create_role", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.alter_role", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.drop_role", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.show_create_role", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.grant_role", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.grant_privilege","feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.show_grants", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.revoke_role", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.revoke_privilege","feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.create_row_policy", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.alter_row_policy", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.drop_row_policy", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.show_create_row_policy", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.show_row_policies", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.create_quota", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.alter_quota", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.drop_quota", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.show_create_quota", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.show_quotas", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.create_settings_profile", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.alter_settings_profile", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.drop_settings_profile", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.show_create_settings_profile", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.set_default_role", "feature"), flags=TE) - Feature(run=load("rbac.tests.syntax.set_role","feature"), flags=TE) \ No newline at end of file + Feature(run=load("rbac.tests.syntax.create_user", "feature")) + Feature(run=load("rbac.tests.syntax.alter_user", "feature")) + Feature(run=load("rbac.tests.syntax.drop_user", "feature")) + Feature(run=load("rbac.tests.syntax.show_create_user", "feature")) + Feature(run=load("rbac.tests.syntax.create_role", "feature")) + Feature(run=load("rbac.tests.syntax.alter_role", "feature")) + Feature(run=load("rbac.tests.syntax.drop_role", "feature")) + Feature(run=load("rbac.tests.syntax.show_create_role", "feature")) + Feature(run=load("rbac.tests.syntax.grant_role", "feature")) + Feature(run=load("rbac.tests.syntax.grant_privilege","feature")) + Feature(run=load("rbac.tests.syntax.show_grants", "feature")) + Feature(run=load("rbac.tests.syntax.revoke_role", "feature")) + Feature(run=load("rbac.tests.syntax.revoke_privilege","feature")) + Feature(run=load("rbac.tests.syntax.create_row_policy", "feature")) + Feature(run=load("rbac.tests.syntax.alter_row_policy", "feature")) + Feature(run=load("rbac.tests.syntax.drop_row_policy", "feature")) + Feature(run=load("rbac.tests.syntax.show_create_row_policy", "feature")) + Feature(run=load("rbac.tests.syntax.show_row_policies", "feature")) + Feature(run=load("rbac.tests.syntax.create_quota", "feature")) + Feature(run=load("rbac.tests.syntax.alter_quota", "feature")) + Feature(run=load("rbac.tests.syntax.drop_quota", "feature")) + Feature(run=load("rbac.tests.syntax.show_create_quota", "feature")) + Feature(run=load("rbac.tests.syntax.show_quotas", "feature")) + Feature(run=load("rbac.tests.syntax.create_settings_profile", "feature")) + Feature(run=load("rbac.tests.syntax.alter_settings_profile", "feature")) + Feature(run=load("rbac.tests.syntax.drop_settings_profile", "feature")) + Feature(run=load("rbac.tests.syntax.show_create_settings_profile", "feature")) + Feature(run=load("rbac.tests.syntax.set_default_role", "feature")) + Feature(run=load("rbac.tests.syntax.set_role","feature")) \ No newline at end of file diff --git a/tests/testflows/rbac/tests/syntax/grant_privilege.py b/tests/testflows/rbac/tests/syntax/grant_privilege.py index 2108b101c44..817a70498f4 100755 --- a/tests/testflows/rbac/tests/syntax/grant_privilege.py +++ b/tests/testflows/rbac/tests/syntax/grant_privilege.py @@ -82,7 +82,7 @@ def feature(self, node="clickhouse1"): Scenario(run=grant_privileges) # with nonexistant object name, GRANT assumes type role - with Scenario("I grant privilege to role that does not exist", flags=TE, requirements=[ + with Scenario("I grant privilege to role that does not exist", requirements=[ RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]): with Given("I ensure that role does not exist"): node.query("DROP ROLE IF EXISTS role0") @@ -90,35 +90,35 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.role_not_found_in_disk(name="role0") node.query("GRANT NONE TO role0", exitcode=exitcode, message=message) - with Scenario("I grant privilege ON CLUSTER", flags=TE, requirements=[ + with Scenario("I grant privilege ON CLUSTER", requirements=[ RQ_SRS_006_RBAC_Grant_Privilege_OnCluster("1.0"), RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]): with setup(node): with When("I grant privilege ON CLUSTER"): node.query("GRANT ON CLUSTER sharded_cluster NONE TO user0") - with Scenario("I grant privilege on fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I grant privilege on fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_Grant_Privilege_OnCluster("1.0")]): with setup(node): with When("I grant privilege ON CLUSTER"): exitcode, message = errors.cluster_not_found("fake_cluster") node.query("GRANT ON CLUSTER fake_cluster NONE TO user0", exitcode=exitcode, message=message) - with Scenario("I grant privilege to multiple users and roles", flags=TE, requirements=[ + with Scenario("I grant privilege to multiple users and roles", requirements=[ RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"), RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]): with setup(node): with When("I grant privilege to several users"): node.query("GRANT NONE TO user0, user1, role1") - with Scenario("I grant privilege to current user", flags=TE, requirements=[ + with Scenario("I grant privilege to current user", requirements=[ RQ_SRS_006_RBAC_Grant_Privilege_ToCurrentUser("1.0"), RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]): with setup(node): with When("I grant privilege to current user"): node.query("GRANT NONE TO CURRENT_USER", settings = [("user","user0")]) - with Scenario("I grant privilege NONE to default user, throws exception", flags=TE, requirements=[ + with Scenario("I grant privilege NONE to default user, throws exception", requirements=[ RQ_SRS_006_RBAC_Grant_Privilege_ToCurrentUser("1.0"), RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]): with setup(node): @@ -126,7 +126,7 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.cannot_update_default() node.query("GRANT NONE TO CURRENT_USER", exitcode=exitcode, message=message) - with Scenario("I grant privilege with grant option", flags=TE, requirements=[ + with Scenario("I grant privilege with grant option", requirements=[ RQ_SRS_006_RBAC_Grant_Privilege_GrantOption("1.0"), RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]): with setup(node): diff --git a/tests/testflows/rbac/tests/syntax/grant_role.py b/tests/testflows/rbac/tests/syntax/grant_role.py index 26c9fb619e9..af69e5f3751 100755 --- a/tests/testflows/rbac/tests/syntax/grant_role.py +++ b/tests/testflows/rbac/tests/syntax/grant_role.py @@ -33,7 +33,7 @@ def feature(self, node="clickhouse1"): for j in range(roles): node.query(f"DROP ROLE IF EXISTS role{j}") - with Scenario("I grant a role to a user",flags=TE, requirements=[ + with Scenario("I grant a role to a user", requirements=[ RQ_SRS_006_RBAC_Grant_Role("1.0")]): with setup(1,1): with When("I grant a role"): @@ -61,19 +61,19 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.role_not_found_in_disk(name="role0") node.query("GRANT role0 TO user0", exitcode=exitcode, message=message) - with Scenario("I grant a role to multiple users", flags=TE, requirements=[ + with Scenario("I grant a role to multiple users", requirements=[ RQ_SRS_006_RBAC_Grant_Role("1.0")]): with setup(2,1): with When("I grant role to a multiple users"): node.query("GRANT role0 TO user0, user1") - with Scenario("I grant multiple roles to multiple users", flags=TE, requirements=[ + with Scenario("I grant multiple roles to multiple users", requirements=[ RQ_SRS_006_RBAC_Grant_Role("1.0")]): with setup(2,2): with When("I grant multiple roles to multiple users"): node.query("GRANT role0, role1 TO user0, user1") - with Scenario("I grant role to current user", flags=TE, requirements=[ + with Scenario("I grant role to current user", requirements=[ RQ_SRS_006_RBAC_Grant_Role_CurrentUser("1.0")]): with setup(1,1): with Given("I have a user with access management privilege"): @@ -81,20 +81,20 @@ def feature(self, node="clickhouse1"): with When("I grant role to current user"): node.query("GRANT role0 TO CURRENT_USER", settings = [("user","user0")]) - with Scenario("I grant role to default user, throws exception", flags=TE, requirements=[ + with Scenario("I grant role to default user, throws exception", requirements=[ RQ_SRS_006_RBAC_Grant_Role_CurrentUser("1.0")]): with setup(1,1): with When("I grant role to default user"): exitcode, message = errors.cannot_update_default() node.query("GRANT role0 TO CURRENT_USER", exitcode=exitcode, message=message) - with Scenario("I grant role to user with admin option", flags=TE, requirements=[ + with Scenario("I grant role to user with admin option", requirements=[ RQ_SRS_006_RBAC_Grant_Role_AdminOption("1.0")]): with setup(1,1): with When("I grant role to a user with admin option"): node.query("GRANT role0 TO user0 WITH ADMIN OPTION") - with Scenario("I grant role to user on cluster", flags=TE, requirements=[ + with Scenario("I grant role to user on cluster", requirements=[ RQ_SRS_006_RBAC_Grant_Role_OnCluster("1.0")]): try: with Given("I have a user and a role on a cluster"): @@ -107,7 +107,7 @@ def feature(self, node="clickhouse1"): node.query("DROP USER IF EXISTS user0 ON CLUSTER sharded_cluster") node.query("DROP ROLE IF EXISTS role0 ON CLUSTER sharded_cluster") - with Scenario("I grant role to user on fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I grant role to user on fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_Grant_Role_OnCluster("1.0")]): with setup(1,1): with When("I grant the role to the user"): diff --git a/tests/testflows/rbac/tests/syntax/revoke_privilege.py b/tests/testflows/rbac/tests/syntax/revoke_privilege.py index a0fb714c823..3e23f2ddfc9 100755 --- a/tests/testflows/rbac/tests/syntax/revoke_privilege.py +++ b/tests/testflows/rbac/tests/syntax/revoke_privilege.py @@ -43,7 +43,9 @@ def revoke_privileges(self, privilege, on, allow_column, allow_introspection, no revoke_privilege(privilege=privilege, on=on, allow_column=allow_column, allow_introspection=allow_introspection, node=node) @TestOutline(Scenario) -@Requirements([RQ_SRS_006_RBAC_Revoke_Privilege_Any("1.0") , RQ_SRS_006_RBAC_Revoke_Privilege_PrivelegeColumns("1.0")]) +@Requirements( + RQ_SRS_006_RBAC_Revoke_Privilege_PrivilegeColumns("1.0"), +) def revoke_privilege(self, privilege, on, allow_column, allow_introspection, node="clickhouse1"): node = self.context.cluster.node(node) for on_ in on: @@ -78,14 +80,14 @@ def feature(self, node="clickhouse1"): Scenario(run=revoke_privileges) - with Scenario("I revoke privilege ON CLUSTER", flags=TE, requirements=[ + with Scenario("I revoke privilege ON CLUSTER", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_Cluster("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): with setup(node): with When("I revoke privilege ON CLUSTER"): node.query("REVOKE ON CLUSTER sharded_cluster NONE FROM user0") - with Scenario("I revoke privilege ON fake CLUSTER, throws exception", flags=TE, requirements=[ + with Scenario("I revoke privilege ON fake CLUSTER, throws exception", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_Cluster("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): with setup(node): @@ -94,21 +96,21 @@ def feature(self, node="clickhouse1"): node.query("REVOKE ON CLUSTER fake_cluster NONE FROM user0", exitcode=exitcode, message=message) - with Scenario("I revoke privilege from multiple users and roles", flags=TE, requirements=[ + with Scenario("I revoke privilege from multiple users and roles", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): with setup(node): with When("I revoke privilege from multiple users"): node.query("REVOKE NONE FROM user0, user1, role1") - with Scenario("I revoke privilege from current user", flags=TE, requirements=[ + with Scenario("I revoke privilege from current user", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): with setup(node): with When("I revoke privilege from current user"): node.query("REVOKE NONE FROM CURRENT_USER", settings = [("user","user0")]) - with Scenario("I revoke privilege from all users", flags=TE, requirements=[ + with Scenario("I revoke privilege from all users", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): with setup(node): @@ -116,7 +118,7 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.cannot_update_default() node.query("REVOKE NONE FROM ALL", exitcode=exitcode,message=message) - with Scenario("I revoke privilege from default user", flags=TE, requirements=[ + with Scenario("I revoke privilege from default user", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): with setup(node): @@ -125,7 +127,7 @@ def feature(self, node="clickhouse1"): node.query("REVOKE NONE FROM default", exitcode=exitcode,message=message) #By default, ClickHouse treats unnamed object as role - with Scenario("I revoke privilege from nonexistent role, throws exception", flags=TE, requirements=[ + with Scenario("I revoke privilege from nonexistent role, throws exception", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): role = "role5" @@ -135,7 +137,7 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.role_not_found_in_disk(role) node.query(f"REVOKE NONE FROM {role}", exitcode=exitcode,message=message) - with Scenario("I revoke privilege from ALL EXCEPT nonexistent role, throws exception", flags=TE, requirements=[ + with Scenario("I revoke privilege from ALL EXCEPT nonexistent role, throws exception", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): role = "role5" @@ -145,14 +147,14 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.role_not_found_in_disk(role) node.query(f"REVOKE NONE FROM ALL EXCEPT {role}", exitcode=exitcode,message=message) - with Scenario("I revoke privilege from all except some users and roles", flags=TE, requirements=[ + with Scenario("I revoke privilege from all except some users and roles", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): with setup(node): with When("I revoke privilege all except some users"): node.query("REVOKE NONE FROM ALL EXCEPT default, user0, role1") - with Scenario("I revoke privilege from all except current user", flags=TE, requirements=[ + with Scenario("I revoke privilege from all except current user", requirements=[ RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"), RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]): with setup(node): diff --git a/tests/testflows/rbac/tests/syntax/revoke_role.py b/tests/testflows/rbac/tests/syntax/revoke_role.py index 9d87257b054..4acdf127cec 100755 --- a/tests/testflows/rbac/tests/syntax/revoke_role.py +++ b/tests/testflows/rbac/tests/syntax/revoke_role.py @@ -37,7 +37,7 @@ def feature(self, node="clickhouse1"): for i in range(roles): node.query(f"DROP ROLE IF EXISTS role{i}") - with Scenario("I revoke a role from a user",flags=TE, requirements=[ + with Scenario("I revoke a role from a user", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0")]): with setup(): with When("I revoke a role"): @@ -73,19 +73,19 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.role_not_found_in_disk(name="role0") node.query("REVOKE role0 FROM user0", exitcode=exitcode, message=message) - with Scenario("I revoke a role from multiple users", flags=TE, requirements=[ + with Scenario("I revoke a role from multiple users", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0")]): with setup(): with When("I revoke a role from multiple users"): node.query("REVOKE role0 FROM user0, user1") - with Scenario("I revoke multiple roles from multiple users", flags=TE, requirements=[ + with Scenario("I revoke multiple roles from multiple users", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0")]): with setup(): node.query("REVOKE role0, role1 FROM user0, user1") #user is default, expect exception - with Scenario("I revoke a role from default user", flags=TE, requirements=[ + with Scenario("I revoke a role from default user", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0"), RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]): with setup(): @@ -94,7 +94,7 @@ def feature(self, node="clickhouse1"): node.query("REVOKE role0 FROM CURRENT_USER", exitcode=exitcode, message=message) #user is user0 - with Scenario("I revoke a role from current user", flags=TE, requirements=[ + with Scenario("I revoke a role from current user", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0"), RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]): with setup(): @@ -102,7 +102,7 @@ def feature(self, node="clickhouse1"): node.query("REVOKE role0 FROM CURRENT_USER", settings = [("user","user0")]) #user is default, expect exception - with Scenario("I revoke a role from all", flags=TE, requirements=[ + with Scenario("I revoke a role from all", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0"), RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]): with setup(): @@ -111,7 +111,7 @@ def feature(self, node="clickhouse1"): node.query("REVOKE role0 FROM ALL", exitcode=exitcode, message=message) #user is default, expect exception - with Scenario("I revoke multiple roles from all", flags=TE, requirements=[ + with Scenario("I revoke multiple roles from all", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0"), RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]): with setup(): @@ -119,14 +119,14 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.cannot_update_default() node.query("REVOKE role0, role1 FROM ALL", exitcode=exitcode, message=message) - with Scenario("I revoke a role from all but current user", flags=TE, requirements=[ + with Scenario("I revoke a role from all but current user", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0"), RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]): with setup(): with When("I revoke a role from all except current"): node.query("REVOKE role0 FROM ALL EXCEPT CURRENT_USER") - with Scenario("I revoke a role from all but default user", flags=TE, requirements=[ + with Scenario("I revoke a role from all but default user", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0"), RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]): with setup(): @@ -134,26 +134,26 @@ def feature(self, node="clickhouse1"): node.query("REVOKE role0 FROM ALL EXCEPT default", settings = [("user","user0")]) - with Scenario("I revoke multiple roles from all but default user", flags=TE, requirements=[ + with Scenario("I revoke multiple roles from all but default user", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0"), RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]): with setup(): with When("I revoke multiple roles from all except default"): node.query("REVOKE role0, role1 FROM ALL EXCEPT default", settings = [("user","user0")]) - with Scenario("I revoke a role from a role", flags=TE, requirements=[ + with Scenario("I revoke a role from a role", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0")]): with setup(): with When("I revoke a role from a role"): node.query("REVOKE role0 FROM role1") - with Scenario("I revoke a role from a role and a user", flags=TE, requirements=[ + with Scenario("I revoke a role from a role and a user", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0")]): with setup(): with When("I revoke a role from multiple roles"): node.query("REVOKE role0 FROM role1, user0") - with Scenario("I revoke a role from a user on cluster", flags=TE, requirements=[ + with Scenario("I revoke a role from a user on cluster", requirements=[ RQ_SRS_006_RBAC_Revoke_Role_Cluster("1.0")]): with Given("I have a role and a user on a cluster"): node.query("CREATE USER OR REPLACE user0 ON CLUSTER sharded_cluster") @@ -164,13 +164,13 @@ def feature(self, node="clickhouse1"): node.query("DROP USER IF EXISTS user0 ON CLUSTER sharded_cluster") node.query("DROP ROLE IF EXISTS role0 ON CLUSTER sharded_cluster") - with Scenario("I revoke a role on fake cluster, throws exception", flags=TE, requirements=[ + with Scenario("I revoke a role on fake cluster, throws exception", requirements=[ RQ_SRS_006_RBAC_Revoke_Role_Cluster("1.0")]): with When("I revoke a role from user on a cluster"): exitcode, message = errors.cluster_not_found("fake_cluster") node.query("REVOKE ON CLUSTER fake_cluster role0 FROM user0", exitcode=exitcode, message=message) - with Scenario("I revoke multiple roles from multiple users on cluster", flags=TE, requirements=[ + with Scenario("I revoke multiple roles from multiple users on cluster", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0"), RQ_SRS_006_RBAC_Revoke_Role_Cluster("1.0")]): with Given("I have multiple roles and multiple users on a cluster"): @@ -184,13 +184,13 @@ def feature(self, node="clickhouse1"): node.query(f"DROP USER IF EXISTS user{i} ON CLUSTER sharded_cluster") node.query(f"DROP ROLE IF EXISTS role{i} ON CLUSTER sharded_cluster") - with Scenario("I revoke admin option for role from a user", flags=TE, requirements=[ + with Scenario("I revoke admin option for role from a user", requirements=[ RQ_SRS_006_RBAC_Revoke_AdminOption("1.0")]): with setup(): with When("I revoke admin option for role from a user"): node.query("REVOKE ADMIN OPTION FOR role0 FROM user0") - with Scenario("I revoke admin option for multiple roles from multiple users", flags=TE, requirements=[ + with Scenario("I revoke admin option for multiple roles from multiple users", requirements=[ RQ_SRS_006_RBAC_Revoke_Role("1.0"), RQ_SRS_006_RBAC_Revoke_AdminOption("1.0")]): with setup(): diff --git a/tests/testflows/rbac/tests/syntax/set_default_role.py b/tests/testflows/rbac/tests/syntax/set_default_role.py index a7801e04b23..ed50810eba7 100755 --- a/tests/testflows/rbac/tests/syntax/set_default_role.py +++ b/tests/testflows/rbac/tests/syntax/set_default_role.py @@ -71,43 +71,43 @@ def feature(self, node="clickhouse1"): node.query(f"CREATE USER user{i}") node.query(f"GRANT role0, role1 TO user0, user1") - with Scenario("I set default role for a user to none", flags = TE, requirements=[ + with Scenario("I set default role for a user to none", requirements=[ RQ_SRS_006_RBAC_SetDefaultRole_None("1.0")]): with When("I set no roles default for user"): node.query("SET DEFAULT ROLE NONE TO user0") - with Scenario("I set one default role for a user", flags = TE, requirements=[ + with Scenario("I set one default role for a user", requirements=[ RQ_SRS_006_RBAC_SetDefaultRole("1.0")]): with When("I set a default role for user "): node.query("SET DEFAULT ROLE role0 TO user0") - with Scenario("I set one default role for user default, throws exception", flags = TE, requirements=[ + with Scenario("I set one default role for user default, throws exception", requirements=[ RQ_SRS_006_RBAC_SetDefaultRole("1.0")]): with When("I set a default role for default"): exitcode, message = errors.cannot_update_default() node.query("SET DEFAULT ROLE role0 TO default", exitcode=exitcode, message=message) - with Scenario("I set multiple default roles for a user", flags = TE, requirements=[ + with Scenario("I set multiple default roles for a user", requirements=[ RQ_SRS_006_RBAC_SetDefaultRole("1.0")]): with When("I set multiple default roles to user"): node.query("SET DEFAULT ROLE role0, role1 TO user0") - with Scenario("I set multiple default roles for multiple users", flags = TE, requirements=[ + with Scenario("I set multiple default roles for multiple users", requirements=[ RQ_SRS_006_RBAC_SetDefaultRole("1.0")]): with When("I set multiple default roles to multiple users"): node.query("SET DEFAULT ROLE role0, role1 TO user0, user1") - with Scenario("I set all roles as default for a user", flags = TE, requirements=[ + with Scenario("I set all roles as default for a user", requirements=[ RQ_SRS_006_RBAC_SetDefaultRole_All("1.0")]): with When("I set all roles default to user"): node.query("SET DEFAULT ROLE ALL TO user0") - with Scenario("I set all roles except one for a user", flags = TE, requirements=[ + with Scenario("I set all roles except one for a user", requirements=[ RQ_SRS_006_RBAC_SetDefaultRole_AllExcept("1.0")]): with When("I set all except one role default to user"): node.query("SET DEFAULT ROLE ALL EXCEPT role0 TO user0") - with Scenario("I set default role for current user", flags = TE, requirements=[ + with Scenario("I set default role for current user", requirements=[ RQ_SRS_006_RBAC_SetDefaultRole_CurrentUser("1.0")]): with When("I set default role to current user"): node.query("GRANT ACCESS MANAGEMENT ON *.* TO user0") diff --git a/tests/testflows/rbac/tests/syntax/set_role.py b/tests/testflows/rbac/tests/syntax/set_role.py index 97a121797ac..3d3d4d00fac 100755 --- a/tests/testflows/rbac/tests/syntax/set_role.py +++ b/tests/testflows/rbac/tests/syntax/set_role.py @@ -29,17 +29,17 @@ def feature(self, node="clickhouse1"): for i in range(roles): node.query(f"DROP ROLE IF EXISTS role{i}") - with Scenario("I set default role for current user", flags = TE, requirements=[ + with Scenario("I set default role for current user", requirements=[ RQ_SRS_006_RBAC_SetRole_Default("1.0")]): with When("I set default role for current user"): node.query("SET ROLE DEFAULT") - with Scenario("I set no role for current user", flags = TE, requirements=[ + with Scenario("I set no role for current user", requirements=[ RQ_SRS_006_RBAC_SetRole_None("1.0")]): with When("I set no role for current user"): node.query("SET ROLE NONE") - with Scenario("I set nonexistent role, throws exception", flags = TE, requirements=[ + with Scenario("I set nonexistent role, throws exception", requirements=[ RQ_SRS_006_RBAC_SetRole_None("1.0")]): with Given("I ensure that role role5 does not exist"): node.query("DROP ROLE IF EXISTS role5") @@ -47,7 +47,7 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.role_not_found_in_disk("role5") node.query("SET ROLE role5", exitcode=exitcode, message=message) - with Scenario("I set nonexistent role, throws exception", flags = TE, requirements=[ + with Scenario("I set nonexistent role, throws exception", requirements=[ RQ_SRS_006_RBAC_SetRole_None("1.0")]): with Given("I ensure that role role5 does not exist"): node.query("DROP ROLE IF EXISTS role5") @@ -55,7 +55,7 @@ def feature(self, node="clickhouse1"): exitcode, message = errors.role_not_found_in_disk("role5") node.query("SET ROLE ALL EXCEPT role5", exitcode=exitcode, message=message) - with Scenario("I set one role for current user", flags = TE, requirements=[ + with Scenario("I set one role for current user", requirements=[ RQ_SRS_006_RBAC_SetRole("1.0")]): with setup(1): with Given("I have a user"): @@ -67,7 +67,7 @@ def feature(self, node="clickhouse1"): with Finally("I drop the user"): node.query("DROP USER user0") - with Scenario("I set multiple roles for current user", flags = TE, requirements=[ + with Scenario("I set multiple roles for current user", requirements=[ RQ_SRS_006_RBAC_SetRole("1.0")]): with setup(2): with Given("I have a user"): @@ -79,12 +79,12 @@ def feature(self, node="clickhouse1"): with Finally("I drop the user"): node.query("DROP USER user0") - with Scenario("I set all roles for current user", flags = TE, requirements=[ + with Scenario("I set all roles for current user", requirements=[ RQ_SRS_006_RBAC_SetRole_All("1.0")]): with When("I set all roles for current user"): node.query("SET ROLE ALL") - with Scenario("I set all roles except one for current user", flags = TE, requirements=[ + with Scenario("I set all roles except one for current user", requirements=[ RQ_SRS_006_RBAC_SetRole_AllExcept("1.0")]): with setup(1): with When("I run set role command"): diff --git a/tests/testflows/rbac/tests/syntax/show_create_quota.py b/tests/testflows/rbac/tests/syntax/show_create_quota.py index 0954a24d2db..f29b3f5bcc6 100755 --- a/tests/testflows/rbac/tests/syntax/show_create_quota.py +++ b/tests/testflows/rbac/tests/syntax/show_create_quota.py @@ -25,19 +25,19 @@ def feature(self, node="clickhouse1"): with Finally("I drop the quota"): node.query(f"DROP QUOTA IF EXISTS {quota}") - with Scenario("I show create quota", flags=TE, requirements=[ + with Scenario("I show create quota", requirements=[ RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Name("1.0")]): with cleanup("quota0"): with When("I run show create quota command"): node.query("SHOW CREATE QUOTA quota0") - with Scenario("I show create quota current", flags=TE, requirements=[ + with Scenario("I show create quota current", requirements=[ RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Current("1.0")]): with cleanup("quota1"): with When("I run show create quota command"): node.query("SHOW CREATE QUOTA CURRENT") - with Scenario("I show create quota current short form", flags=TE, requirements=[ + with Scenario("I show create quota current short form", requirements=[ RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Current("1.0")]): with cleanup("quota2"): with When("I run show create quota command"): diff --git a/tests/testflows/rbac/tests/syntax/show_create_role.py b/tests/testflows/rbac/tests/syntax/show_create_role.py index 11ce7371ba2..0b2adba96e2 100755 --- a/tests/testflows/rbac/tests/syntax/show_create_role.py +++ b/tests/testflows/rbac/tests/syntax/show_create_role.py @@ -26,13 +26,13 @@ def feature(self, node="clickhouse1"): with Finally("I drop the role"): node.query(f"DROP ROLE IF EXISTS {role}") - with Scenario("I show create role", flags=TE, requirements=[ + with Scenario("I show create role", requirements=[ RQ_SRS_006_RBAC_Role_ShowCreate("1.0")]): with setup("role0"): with When("I run show create role command"): node.query("SHOW CREATE ROLE role0") - with Scenario("I show create role, role doesn't exist, exception", flags=TE, requirements=[ + with Scenario("I show create role, role doesn't exist, exception", requirements=[ RQ_SRS_006_RBAC_Role_ShowCreate("1.0")]): with When("I run show create role to catch an exception"): exitcode, message = errors.role_not_found_in_disk(name="role0") diff --git a/tests/testflows/rbac/tests/syntax/show_create_row_policy.py b/tests/testflows/rbac/tests/syntax/show_create_row_policy.py index 5d8b104540c..cf43c0f2b41 100755 --- a/tests/testflows/rbac/tests/syntax/show_create_row_policy.py +++ b/tests/testflows/rbac/tests/syntax/show_create_row_policy.py @@ -29,19 +29,19 @@ def feature(self, node="clickhouse1"): with Given("I have a table"): node.query(f"CREATE TABLE default.foo (x UInt64, y String) Engine=Memory") - with Scenario("I show create row policy", flags=TE, requirements=[ + with Scenario("I show create row policy", requirements=[ RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy("1.0")]): with cleanup("policy0"): with When("I run show create row policy command"): node.query("SHOW CREATE ROW POLICY policy0 ON default.foo") - with Scenario("I show create row policy on a table", flags=TE, requirements=[ + with Scenario("I show create row policy on a table", requirements=[ RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_On("1.0")]): with cleanup("policy0"): with When("I run show create row policy command"): node.query("SHOW CREATE ROW POLICY policy0 ON default.foo") - with Scenario("I show create row policy using short syntax on a table", flags=TE, requirements=[ + with Scenario("I show create row policy using short syntax on a table", requirements=[ RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_On("1.0")]): with cleanup("policy1",on="foo"): with When("I run show create row policy command"): diff --git a/tests/testflows/rbac/tests/syntax/show_create_settings_profile.py b/tests/testflows/rbac/tests/syntax/show_create_settings_profile.py index 6f715463539..4af4e37951a 100755 --- a/tests/testflows/rbac/tests/syntax/show_create_settings_profile.py +++ b/tests/testflows/rbac/tests/syntax/show_create_settings_profile.py @@ -25,13 +25,13 @@ def feature(self, node="clickhouse1"): with Finally("I drop the settings profile"): node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}") - with Scenario("I show create settings profile", flags=TE, requirements=[ + with Scenario("I show create settings profile", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_ShowCreateSettingsProfile("1.0")]): with cleanup("profile0"): with When("I run show create settings profile command"): node.query("SHOW CREATE SETTINGS PROFILE profile0") - with Scenario("I show create settings profile short form", flags=TE, requirements=[ + with Scenario("I show create settings profile short form", requirements=[ RQ_SRS_006_RBAC_SettingsProfile_ShowCreateSettingsProfile("1.0")]): with cleanup("profile1"): with When("I run show create settings profile command"): diff --git a/tests/testflows/rbac/tests/syntax/show_create_user.py b/tests/testflows/rbac/tests/syntax/show_create_user.py index 804b7e06959..963e0d5d193 100755 --- a/tests/testflows/rbac/tests/syntax/show_create_user.py +++ b/tests/testflows/rbac/tests/syntax/show_create_user.py @@ -25,13 +25,13 @@ def feature(self, node="clickhouse1"): with Finally("I drop the user"): node.query(f"DROP USER IF EXISTS {user}") - with Scenario("I run show create on user with no options", flags=TE, requirements=[ + with Scenario("I run show create on user with no options", requirements=[ RQ_SRS_006_RBAC_User_ShowCreateUser_For("1.0")]): with setup("user0"): with When("I run show create user command"): node.query("SHOW CREATE USER user0") - with Scenario("I run show create on current user", flags=TE, requirements=[ + with Scenario("I run show create on current user", requirements=[ RQ_SRS_006_RBAC_User_ShowCreateUser("1.0")]): with When("I show create the current user"): node.query("SHOW CREATE USER CURRENT_USER") \ No newline at end of file diff --git a/tests/testflows/rbac/tests/syntax/show_grants.py b/tests/testflows/rbac/tests/syntax/show_grants.py index f6c797a6d76..18165ba98a5 100755 --- a/tests/testflows/rbac/tests/syntax/show_grants.py +++ b/tests/testflows/rbac/tests/syntax/show_grants.py @@ -25,13 +25,13 @@ def feature(self, node="clickhouse1"): with Finally("I drop the user"): node.query(f"DROP USER IF EXISTS {user}") - with Scenario("I show grants for user", flags=TE, requirements=[ + with Scenario("I show grants for user", requirements=[ RQ_SRS_006_RBAC_Show_Grants_For("1.0")]): with setup("user0"): with When("I run show grants command"): node.query("SHOW GRANTS FOR user0") - with Scenario("I show grants for current user", flags=TE, requirements=[ + with Scenario("I show grants for current user", requirements=[ RQ_SRS_006_RBAC_Show_Grants("1.0")]): with When("I show grants"): node.query("SHOW GRANTS") \ No newline at end of file diff --git a/tests/testflows/rbac/tests/syntax/show_quotas.py b/tests/testflows/rbac/tests/syntax/show_quotas.py index 4003207354d..5fbae718a29 100755 --- a/tests/testflows/rbac/tests/syntax/show_quotas.py +++ b/tests/testflows/rbac/tests/syntax/show_quotas.py @@ -25,25 +25,25 @@ def feature(self, node="clickhouse1"): with Finally("I drop the quota"): node.query(f"DROP QUOTA IF EXISTS {quota}") - with Scenario("I show quotas", flags=TE, requirements=[ + with Scenario("I show quotas", requirements=[ RQ_SRS_006_RBAC_Quota_ShowQuotas("1.0")]): with cleanup("quota0"), cleanup("quota1"): with When("I run show quota command"): node.query("SHOW QUOTAS") - with Scenario("I show quotas into outfile", flags=TE, requirements=[ + with Scenario("I show quotas into outfile", requirements=[ RQ_SRS_006_RBAC_Quota_ShowQuotas_IntoOutfile("1.0")]): with cleanup("quota0"), cleanup("quota1"): with When("I run show quota command"): node.query("SHOW QUOTAS INTO OUTFILE 'quotas.txt'") - with Scenario("I show quotas with format", flags=TE, requirements=[ + with Scenario("I show quotas with format", requirements=[ RQ_SRS_006_RBAC_Quota_ShowQuotas_Format("1.0")]): with cleanup("quota0"), cleanup("quota1"): with When("I run show quota command"): node.query("SHOW QUOTAS FORMAT TabSeparated") - with Scenario("I show quotas with settings", flags=TE, requirements=[ + with Scenario("I show quotas with settings", requirements=[ RQ_SRS_006_RBAC_Quota_ShowQuotas("1.0")]): with cleanup("quota0"), cleanup("quota1"): with When("I run show quota command"): diff --git a/tests/testflows/rbac/tests/syntax/show_row_policies.py b/tests/testflows/rbac/tests/syntax/show_row_policies.py index 2bc1471fbe1..0dc7f7f1d1a 100755 --- a/tests/testflows/rbac/tests/syntax/show_row_policies.py +++ b/tests/testflows/rbac/tests/syntax/show_row_policies.py @@ -29,25 +29,25 @@ def feature(self, node="clickhouse1"): with Given("I have a table"): node.query(f"CREATE TABLE default.foo (x UInt64, y String) Engine=Memory") - with Scenario("I show row policies", flags=TE, requirements=[ + with Scenario("I show row policies", requirements=[ RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies("1.0")]): with cleanup("policy0"): with When("I run drop row policy command"): node.query("SHOW ROW POLICIES") - with Scenario("I show row policies using short syntax", flags=TE, requirements=[ + with Scenario("I show row policies using short syntax", requirements=[ RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies("1.0")]): with cleanup("policy1"): with When("I run drop row policy command"): node.query("SHOW POLICIES") - with Scenario("I show row policies on a database table", flags=TE, requirements=[ + with Scenario("I show row policies on a database table", requirements=[ RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_On("1.0")]): with cleanup("policy0"): with When("I run drop row policy command"): node.query("SHOW ROW POLICIES ON default.foo") - with Scenario("I show row policies on a table", flags=TE, requirements=[ + with Scenario("I show row policies on a table", requirements=[ RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_On("1.0")]): with cleanup("policy0"): with When("I run drop row policy command"): diff --git a/tests/testflows/rbac/tests/views/live_view.py b/tests/testflows/rbac/tests/views/live_view.py index a510877a95b..f0bc381bd84 100755 --- a/tests/testflows/rbac/tests/views/live_view.py +++ b/tests/testflows/rbac/tests/views/live_view.py @@ -1133,9 +1133,13 @@ def feature(self, stress=None, parallel=None, node="clickhouse1"): tasks = [] pool = Pool(3) + with allow_experimental_live_view(self.context.node): try: - for suite in loads(current_module(), Suite): - run_scenario(pool, tasks, suite) + try: + for suite in loads(current_module(), Suite): + run_scenario(pool, tasks, suite) + finally: + join(tasks) finally: - join(tasks) + pool.close() diff --git a/tests/testflows/rbac/tests/views/materialized_view.py b/tests/testflows/rbac/tests/views/materialized_view.py index fc3b393c114..b2b1d19e256 100755 --- a/tests/testflows/rbac/tests/views/materialized_view.py +++ b/tests/testflows/rbac/tests/views/materialized_view.py @@ -612,13 +612,17 @@ def create_with_populate_privilege_granted_directly_or_via_role(self, node=None) if node is None: node = self.context.node + with user(node, f"{user_name}"): + Scenario(test=create_with_populate, name="create with populate privilege granted directly")(grant_target_name=user_name, user_name=user_name) with user(node, f"{user_name}"), role(node, f"{role_name}"): + with When("I grant the role to the user"): node.query(f"GRANT {role_name} TO {user_name}") + Scenario(test=create_with_populate, name="create with populate privilege granted through a role")(grant_target_name=role_name, user_name=user_name) @@ -632,17 +636,22 @@ def create_with_populate(self, user_name, grant_target_name, node=None): if node is None: node = self.context.node + try: + with When("I grant CREATE VIEW privilege"): node.query(f"GRANT CREATE VIEW ON {view_name} TO {grant_target_name}") + with Then("I attempt to create a view as the user"): node.query(f"CREATE MATERIALIZED VIEW {view_name} ENGINE = Memory POPULATE AS SELECT 1", settings = [("user", f"{user_name}")], exitcode=exitcode, message=message) with When("I grant INSERT privilege on the view"): node.query(f"GRANT INSERT ON {view_name} TO {grant_target_name}") + with Given("I don't have a view"): node.query(f"DROP VIEW IF EXISTS {view_name}") + with Then("I attempt to create a view as the user"): node.query(f"CREATE MATERIALIZED VIEW {view_name} ENGINE = Memory POPULATE AS SELECT 1", settings = [("user", f"{user_name}")]) @@ -2262,7 +2271,10 @@ def feature(self, stress=None, parallel=None, node="clickhouse1"): pool = Pool(3) try: - for suite in loads(current_module(), Suite): - run_scenario(pool, tasks, suite) + try: + for suite in loads(current_module(), Suite): + run_scenario(pool, tasks, suite) + finally: + join(tasks) finally: - join(tasks) + pool.close() diff --git a/tests/testflows/regression.py b/tests/testflows/regression.py index 0e9a821cae0..05fec3ea985 100755 --- a/tests/testflows/regression.py +++ b/tests/testflows/regression.py @@ -18,6 +18,7 @@ def regression(self, local, clickhouse_binary_path, stress=None, parallel=None): Feature(test=load("ldap.regression", "regression"))(**args) Feature(test=load("rbac.regression", "regression"))(**args) Feature(test=load("aes_encryption.regression", "regression"))(**args) + # Feature(test=load("kerberos.regression", "regression"))(**args) if main(): regression() diff --git a/tests/testflows/runner b/tests/testflows/runner index 0acc3a25945..213ff6e50d8 100755 --- a/tests/testflows/runner +++ b/tests/testflows/runner @@ -120,3 +120,11 @@ if __name__ == "__main__": print(("Running testflows container as: '" + cmd + "'.")) # testflows return non zero error code on failed tests subprocess.call(cmd, shell=True) + + result_path = os.environ.get("CLICKHOUSE_TESTS_RESULT_PATH", None) + if result_path is not None: + move_from = os.path.join(args.clickhouse_root, 'tests/testflows') + status = os.path.join(move_from, 'check_status.tsv') + results = os.path.join(move_from, 'test_results.tsv') + subprocess.call("mv {} {}".format(status, result_path), shell=True) + subprocess.call("mv {} {}".format(results, result_path), shell=True) diff --git a/tests/ubsan_suppressions.txt b/tests/ubsan_suppressions.txt index 6a55155e330..8d10b4f73dd 100644 --- a/tests/ubsan_suppressions.txt +++ b/tests/ubsan_suppressions.txt @@ -1 +1,5 @@ -# We have no suppressions! +# https://github.com/llvm-mirror/compiler-rt/blob/master/lib/ubsan/ubsan_checks.inc + +# Some value is outside the range of representable values of type 'long' on user-provided data inside boost::geometry - ignore. +src:*/Functions/pointInPolygon.cpp +src:*/contrib/boost/boost/geometry/* diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 8a39d591612..d38b34f3419 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -32,6 +32,7 @@ if (NOT DEFINED ENABLE_UTILS OR ENABLE_UTILS) add_subdirectory (db-generator) add_subdirectory (wal-dump) add_subdirectory (check-mysql-binlog) + add_subdirectory (memcpy-bench) endif () if (ENABLE_CODE_QUALITY) diff --git a/utils/list-versions/version_date.tsv b/utils/list-versions/version_date.tsv index 3e63f8898c0..5edbc4bca1a 100644 --- a/utils/list-versions/version_date.tsv +++ b/utils/list-versions/version_date.tsv @@ -1,3 +1,4 @@ +v21.3.2.5-lts 2021-03-12 v21.2.5.5-stable 2021-03-02 v21.2.4.6-stable 2021-02-20 v21.2.3.15-stable 2021-02-14 diff --git a/utils/memcpy-bench/CMakeLists.txt b/utils/memcpy-bench/CMakeLists.txt new file mode 100644 index 00000000000..54dd0398912 --- /dev/null +++ b/utils/memcpy-bench/CMakeLists.txt @@ -0,0 +1,5 @@ +enable_language(ASM) +add_executable (memcpy-bench memcpy-bench.cpp memcpy_jart.S) +#target_compile_options(memcpy-bench PRIVATE -mavx) +target_link_libraries(memcpy-bench PRIVATE dbms) + diff --git a/utils/memcpy-bench/FastMemcpy.h b/utils/memcpy-bench/FastMemcpy.h new file mode 100644 index 00000000000..9c37524443a --- /dev/null +++ b/utils/memcpy-bench/FastMemcpy.h @@ -0,0 +1,770 @@ +#pragma once + +//===================================================================== +// +// FastMemcpy.c - skywind3000@163.com, 2015 +// +// feature: +// 50% speed up in avg. vs standard memcpy (tested in vc2012/gcc5.1) +// +//===================================================================== + +#include +#include +#include + + +//--------------------------------------------------------------------- +// force inline for compilers +//--------------------------------------------------------------------- +#ifndef INLINE +#ifdef __GNUC__ +#if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) + #define INLINE __inline__ __attribute__((always_inline)) +#else + #define INLINE __inline__ +#endif +#elif defined(_MSC_VER) + #define INLINE __forceinline +#elif (defined(__BORLANDC__) || defined(__WATCOMC__)) + #define INLINE __inline +#else + #define INLINE +#endif +#endif + +typedef __attribute__((__aligned__(1))) uint16_t uint16_unaligned_t; +typedef __attribute__((__aligned__(1))) uint32_t uint32_unaligned_t; +typedef __attribute__((__aligned__(1))) uint64_t uint64_unaligned_t; + +//--------------------------------------------------------------------- +// fast copy for different sizes +//--------------------------------------------------------------------- +static INLINE void memcpy_sse2_16(void * __restrict dst, const void * __restrict src) +{ + __m128i m0 = _mm_loadu_si128((reinterpret_cast(src)) + 0); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 0, m0); +} + +static INLINE void memcpy_sse2_32(void * __restrict dst, const void * __restrict src) +{ + __m128i m0 = _mm_loadu_si128((reinterpret_cast(src)) + 0); + __m128i m1 = _mm_loadu_si128((reinterpret_cast(src)) + 1); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 0, m0); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 1, m1); +} + +static INLINE void memcpy_sse2_64(void * __restrict dst, const void * __restrict src) +{ + __m128i m0 = _mm_loadu_si128((reinterpret_cast(src)) + 0); + __m128i m1 = _mm_loadu_si128((reinterpret_cast(src)) + 1); + __m128i m2 = _mm_loadu_si128((reinterpret_cast(src)) + 2); + __m128i m3 = _mm_loadu_si128((reinterpret_cast(src)) + 3); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 0, m0); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 1, m1); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 2, m2); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 3, m3); +} + +static INLINE void memcpy_sse2_128(void * __restrict dst, const void * __restrict src) +{ + __m128i m0 = _mm_loadu_si128((reinterpret_cast(src)) + 0); + __m128i m1 = _mm_loadu_si128((reinterpret_cast(src)) + 1); + __m128i m2 = _mm_loadu_si128((reinterpret_cast(src)) + 2); + __m128i m3 = _mm_loadu_si128((reinterpret_cast(src)) + 3); + __m128i m4 = _mm_loadu_si128((reinterpret_cast(src)) + 4); + __m128i m5 = _mm_loadu_si128((reinterpret_cast(src)) + 5); + __m128i m6 = _mm_loadu_si128((reinterpret_cast(src)) + 6); + __m128i m7 = _mm_loadu_si128((reinterpret_cast(src)) + 7); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 0, m0); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 1, m1); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 2, m2); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 3, m3); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 4, m4); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 5, m5); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 6, m6); + _mm_storeu_si128((reinterpret_cast<__m128i*>(dst)) + 7, m7); +} + + +//--------------------------------------------------------------------- +// tiny memory copy with jump table optimized +//--------------------------------------------------------------------- +/// Attribute is used to avoid an error with undefined behaviour sanitizer +/// ../contrib/FastMemcpy/FastMemcpy.h:91:56: runtime error: applying zero offset to null pointer +/// Found by 01307_orc_output_format.sh, cause - ORCBlockInputFormat and external ORC library. +__attribute__((__no_sanitize__("undefined"))) static INLINE void *memcpy_tiny(void * __restrict dst, const void * __restrict src, size_t size) +{ + unsigned char *dd = ((unsigned char*)dst) + size; + const unsigned char *ss = ((const unsigned char*)src) + size; + + switch (size) + { + case 64: + memcpy_sse2_64(dd - 64, ss - 64); + [[fallthrough]]; + case 0: + break; + + case 65: + memcpy_sse2_64(dd - 65, ss - 65); + [[fallthrough]]; + case 1: + dd[-1] = ss[-1]; + break; + + case 66: + memcpy_sse2_64(dd - 66, ss - 66); + [[fallthrough]]; + case 2: + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 67: + memcpy_sse2_64(dd - 67, ss - 67); + [[fallthrough]]; + case 3: + *((uint16_unaligned_t*)(dd - 3)) = *((const uint16_unaligned_t*)(ss - 3)); + dd[-1] = ss[-1]; + break; + + case 68: + memcpy_sse2_64(dd - 68, ss - 68); + [[fallthrough]]; + case 4: + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 69: + memcpy_sse2_64(dd - 69, ss - 69); + [[fallthrough]]; + case 5: + *((uint32_unaligned_t*)(dd - 5)) = *((const uint32_unaligned_t*)(ss - 5)); + dd[-1] = ss[-1]; + break; + + case 70: + memcpy_sse2_64(dd - 70, ss - 70); + [[fallthrough]]; + case 6: + *((uint32_unaligned_t*)(dd - 6)) = *((const uint32_unaligned_t*)(ss - 6)); + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 71: + memcpy_sse2_64(dd - 71, ss - 71); + [[fallthrough]]; + case 7: + *((uint32_unaligned_t*)(dd - 7)) = *((const uint32_unaligned_t*)(ss - 7)); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 72: + memcpy_sse2_64(dd - 72, ss - 72); + [[fallthrough]]; + case 8: + *((uint64_unaligned_t*)(dd - 8)) = *((const uint64_unaligned_t*)(ss - 8)); + break; + + case 73: + memcpy_sse2_64(dd - 73, ss - 73); + [[fallthrough]]; + case 9: + *((uint64_unaligned_t*)(dd - 9)) = *((const uint64_unaligned_t*)(ss - 9)); + dd[-1] = ss[-1]; + break; + + case 74: + memcpy_sse2_64(dd - 74, ss - 74); + [[fallthrough]]; + case 10: + *((uint64_unaligned_t*)(dd - 10)) = *((const uint64_unaligned_t*)(ss - 10)); + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 75: + memcpy_sse2_64(dd - 75, ss - 75); + [[fallthrough]]; + case 11: + *((uint64_unaligned_t*)(dd - 11)) = *((const uint64_unaligned_t*)(ss - 11)); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 76: + memcpy_sse2_64(dd - 76, ss - 76); + [[fallthrough]]; + case 12: + *((uint64_unaligned_t*)(dd - 12)) = *((const uint64_unaligned_t*)(ss - 12)); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 77: + memcpy_sse2_64(dd - 77, ss - 77); + [[fallthrough]]; + case 13: + *((uint64_unaligned_t*)(dd - 13)) = *((const uint64_unaligned_t*)(ss - 13)); + *((uint32_unaligned_t*)(dd - 5)) = *((const uint32_unaligned_t*)(ss - 5)); + dd[-1] = ss[-1]; + break; + + case 78: + memcpy_sse2_64(dd - 78, ss - 78); + [[fallthrough]]; + case 14: + *((uint64_unaligned_t*)(dd - 14)) = *((const uint64_unaligned_t*)(ss - 14)); + *((uint64_unaligned_t*)(dd - 8)) = *((const uint64_unaligned_t*)(ss - 8)); + break; + + case 79: + memcpy_sse2_64(dd - 79, ss - 79); + [[fallthrough]]; + case 15: + *((uint64_unaligned_t*)(dd - 15)) = *((const uint64_unaligned_t*)(ss - 15)); + *((uint64_unaligned_t*)(dd - 8)) = *((const uint64_unaligned_t*)(ss - 8)); + break; + + case 80: + memcpy_sse2_64(dd - 80, ss - 80); + [[fallthrough]]; + case 16: + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 81: + memcpy_sse2_64(dd - 81, ss - 81); + [[fallthrough]]; + case 17: + memcpy_sse2_16(dd - 17, ss - 17); + dd[-1] = ss[-1]; + break; + + case 82: + memcpy_sse2_64(dd - 82, ss - 82); + [[fallthrough]]; + case 18: + memcpy_sse2_16(dd - 18, ss - 18); + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 83: + memcpy_sse2_64(dd - 83, ss - 83); + [[fallthrough]]; + case 19: + memcpy_sse2_16(dd - 19, ss - 19); + *((uint16_unaligned_t*)(dd - 3)) = *((const uint16_unaligned_t*)(ss - 3)); + dd[-1] = ss[-1]; + break; + + case 84: + memcpy_sse2_64(dd - 84, ss - 84); + [[fallthrough]]; + case 20: + memcpy_sse2_16(dd - 20, ss - 20); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 85: + memcpy_sse2_64(dd - 85, ss - 85); + [[fallthrough]]; + case 21: + memcpy_sse2_16(dd - 21, ss - 21); + *((uint32_unaligned_t*)(dd - 5)) = *((const uint32_unaligned_t*)(ss - 5)); + dd[-1] = ss[-1]; + break; + + case 86: + memcpy_sse2_64(dd - 86, ss - 86); + [[fallthrough]]; + case 22: + memcpy_sse2_16(dd - 22, ss - 22); + *((uint32_unaligned_t*)(dd - 6)) = *((const uint32_unaligned_t*)(ss - 6)); + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 87: + memcpy_sse2_64(dd - 87, ss - 87); + [[fallthrough]]; + case 23: + memcpy_sse2_16(dd - 23, ss - 23); + *((uint32_unaligned_t*)(dd - 7)) = *((const uint32_unaligned_t*)(ss - 7)); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 88: + memcpy_sse2_64(dd - 88, ss - 88); + [[fallthrough]]; + case 24: + memcpy_sse2_16(dd - 24, ss - 24); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 89: + memcpy_sse2_64(dd - 89, ss - 89); + [[fallthrough]]; + case 25: + memcpy_sse2_16(dd - 25, ss - 25); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 90: + memcpy_sse2_64(dd - 90, ss - 90); + [[fallthrough]]; + case 26: + memcpy_sse2_16(dd - 26, ss - 26); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 91: + memcpy_sse2_64(dd - 91, ss - 91); + [[fallthrough]]; + case 27: + memcpy_sse2_16(dd - 27, ss - 27); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 92: + memcpy_sse2_64(dd - 92, ss - 92); + [[fallthrough]]; + case 28: + memcpy_sse2_16(dd - 28, ss - 28); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 93: + memcpy_sse2_64(dd - 93, ss - 93); + [[fallthrough]]; + case 29: + memcpy_sse2_16(dd - 29, ss - 29); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 94: + memcpy_sse2_64(dd - 94, ss - 94); + [[fallthrough]]; + case 30: + memcpy_sse2_16(dd - 30, ss - 30); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 95: + memcpy_sse2_64(dd - 95, ss - 95); + [[fallthrough]]; + case 31: + memcpy_sse2_16(dd - 31, ss - 31); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 96: + memcpy_sse2_64(dd - 96, ss - 96); + [[fallthrough]]; + case 32: + memcpy_sse2_32(dd - 32, ss - 32); + break; + + case 97: + memcpy_sse2_64(dd - 97, ss - 97); + [[fallthrough]]; + case 33: + memcpy_sse2_32(dd - 33, ss - 33); + dd[-1] = ss[-1]; + break; + + case 98: + memcpy_sse2_64(dd - 98, ss - 98); + [[fallthrough]]; + case 34: + memcpy_sse2_32(dd - 34, ss - 34); + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 99: + memcpy_sse2_64(dd - 99, ss - 99); + [[fallthrough]]; + case 35: + memcpy_sse2_32(dd - 35, ss - 35); + *((uint16_unaligned_t*)(dd - 3)) = *((const uint16_unaligned_t*)(ss - 3)); + dd[-1] = ss[-1]; + break; + + case 100: + memcpy_sse2_64(dd - 100, ss - 100); + [[fallthrough]]; + case 36: + memcpy_sse2_32(dd - 36, ss - 36); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 101: + memcpy_sse2_64(dd - 101, ss - 101); + [[fallthrough]]; + case 37: + memcpy_sse2_32(dd - 37, ss - 37); + *((uint32_unaligned_t*)(dd - 5)) = *((const uint32_unaligned_t*)(ss - 5)); + dd[-1] = ss[-1]; + break; + + case 102: + memcpy_sse2_64(dd - 102, ss - 102); + [[fallthrough]]; + case 38: + memcpy_sse2_32(dd - 38, ss - 38); + *((uint32_unaligned_t*)(dd - 6)) = *((const uint32_unaligned_t*)(ss - 6)); + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 103: + memcpy_sse2_64(dd - 103, ss - 103); + [[fallthrough]]; + case 39: + memcpy_sse2_32(dd - 39, ss - 39); + *((uint32_unaligned_t*)(dd - 7)) = *((const uint32_unaligned_t*)(ss - 7)); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 104: + memcpy_sse2_64(dd - 104, ss - 104); + [[fallthrough]]; + case 40: + memcpy_sse2_32(dd - 40, ss - 40); + *((uint64_unaligned_t*)(dd - 8)) = *((const uint64_unaligned_t*)(ss - 8)); + break; + + case 105: + memcpy_sse2_64(dd - 105, ss - 105); + [[fallthrough]]; + case 41: + memcpy_sse2_32(dd - 41, ss - 41); + *((uint64_unaligned_t*)(dd - 9)) = *((const uint64_unaligned_t*)(ss - 9)); + dd[-1] = ss[-1]; + break; + + case 106: + memcpy_sse2_64(dd - 106, ss - 106); + [[fallthrough]]; + case 42: + memcpy_sse2_32(dd - 42, ss - 42); + *((uint64_unaligned_t*)(dd - 10)) = *((const uint64_unaligned_t*)(ss - 10)); + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 107: + memcpy_sse2_64(dd - 107, ss - 107); + [[fallthrough]]; + case 43: + memcpy_sse2_32(dd - 43, ss - 43); + *((uint64_unaligned_t*)(dd - 11)) = *((const uint64_unaligned_t*)(ss - 11)); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 108: + memcpy_sse2_64(dd - 108, ss - 108); + [[fallthrough]]; + case 44: + memcpy_sse2_32(dd - 44, ss - 44); + *((uint64_unaligned_t*)(dd - 12)) = *((const uint64_unaligned_t*)(ss - 12)); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 109: + memcpy_sse2_64(dd - 109, ss - 109); + [[fallthrough]]; + case 45: + memcpy_sse2_32(dd - 45, ss - 45); + *((uint64_unaligned_t*)(dd - 13)) = *((const uint64_unaligned_t*)(ss - 13)); + *((uint32_unaligned_t*)(dd - 5)) = *((const uint32_unaligned_t*)(ss - 5)); + dd[-1] = ss[-1]; + break; + + case 110: + memcpy_sse2_64(dd - 110, ss - 110); + [[fallthrough]]; + case 46: + memcpy_sse2_32(dd - 46, ss - 46); + *((uint64_unaligned_t*)(dd - 14)) = *((const uint64_unaligned_t*)(ss - 14)); + *((uint64_unaligned_t*)(dd - 8)) = *((const uint64_unaligned_t*)(ss - 8)); + break; + + case 111: + memcpy_sse2_64(dd - 111, ss - 111); + [[fallthrough]]; + case 47: + memcpy_sse2_32(dd - 47, ss - 47); + *((uint64_unaligned_t*)(dd - 15)) = *((const uint64_unaligned_t*)(ss - 15)); + *((uint64_unaligned_t*)(dd - 8)) = *((const uint64_unaligned_t*)(ss - 8)); + break; + + case 112: + memcpy_sse2_64(dd - 112, ss - 112); + [[fallthrough]]; + case 48: + memcpy_sse2_32(dd - 48, ss - 48); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 113: + memcpy_sse2_64(dd - 113, ss - 113); + [[fallthrough]]; + case 49: + memcpy_sse2_32(dd - 49, ss - 49); + memcpy_sse2_16(dd - 17, ss - 17); + dd[-1] = ss[-1]; + break; + + case 114: + memcpy_sse2_64(dd - 114, ss - 114); + [[fallthrough]]; + case 50: + memcpy_sse2_32(dd - 50, ss - 50); + memcpy_sse2_16(dd - 18, ss - 18); + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 115: + memcpy_sse2_64(dd - 115, ss - 115); + [[fallthrough]]; + case 51: + memcpy_sse2_32(dd - 51, ss - 51); + memcpy_sse2_16(dd - 19, ss - 19); + *((uint16_unaligned_t*)(dd - 3)) = *((const uint16_unaligned_t*)(ss - 3)); + dd[-1] = ss[-1]; + break; + + case 116: + memcpy_sse2_64(dd - 116, ss - 116); + [[fallthrough]]; + case 52: + memcpy_sse2_32(dd - 52, ss - 52); + memcpy_sse2_16(dd - 20, ss - 20); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 117: + memcpy_sse2_64(dd - 117, ss - 117); + [[fallthrough]]; + case 53: + memcpy_sse2_32(dd - 53, ss - 53); + memcpy_sse2_16(dd - 21, ss - 21); + *((uint32_unaligned_t*)(dd - 5)) = *((const uint32_unaligned_t*)(ss - 5)); + dd[-1] = ss[-1]; + break; + + case 118: + memcpy_sse2_64(dd - 118, ss - 118); + [[fallthrough]]; + case 54: + memcpy_sse2_32(dd - 54, ss - 54); + memcpy_sse2_16(dd - 22, ss - 22); + *((uint32_unaligned_t*)(dd - 6)) = *((const uint32_unaligned_t*)(ss - 6)); + *((uint16_unaligned_t*)(dd - 2)) = *((const uint16_unaligned_t*)(ss - 2)); + break; + + case 119: + memcpy_sse2_64(dd - 119, ss - 119); + [[fallthrough]]; + case 55: + memcpy_sse2_32(dd - 55, ss - 55); + memcpy_sse2_16(dd - 23, ss - 23); + *((uint32_unaligned_t*)(dd - 7)) = *((const uint32_unaligned_t*)(ss - 7)); + *((uint32_unaligned_t*)(dd - 4)) = *((const uint32_unaligned_t*)(ss - 4)); + break; + + case 120: + memcpy_sse2_64(dd - 120, ss - 120); + [[fallthrough]]; + case 56: + memcpy_sse2_32(dd - 56, ss - 56); + memcpy_sse2_16(dd - 24, ss - 24); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 121: + memcpy_sse2_64(dd - 121, ss - 121); + [[fallthrough]]; + case 57: + memcpy_sse2_32(dd - 57, ss - 57); + memcpy_sse2_16(dd - 25, ss - 25); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 122: + memcpy_sse2_64(dd - 122, ss - 122); + [[fallthrough]]; + case 58: + memcpy_sse2_32(dd - 58, ss - 58); + memcpy_sse2_16(dd - 26, ss - 26); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 123: + memcpy_sse2_64(dd - 123, ss - 123); + [[fallthrough]]; + case 59: + memcpy_sse2_32(dd - 59, ss - 59); + memcpy_sse2_16(dd - 27, ss - 27); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 124: + memcpy_sse2_64(dd - 124, ss - 124); + [[fallthrough]]; + case 60: + memcpy_sse2_32(dd - 60, ss - 60); + memcpy_sse2_16(dd - 28, ss - 28); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 125: + memcpy_sse2_64(dd - 125, ss - 125); + [[fallthrough]]; + case 61: + memcpy_sse2_32(dd - 61, ss - 61); + memcpy_sse2_16(dd - 29, ss - 29); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 126: + memcpy_sse2_64(dd - 126, ss - 126); + [[fallthrough]]; + case 62: + memcpy_sse2_32(dd - 62, ss - 62); + memcpy_sse2_16(dd - 30, ss - 30); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 127: + memcpy_sse2_64(dd - 127, ss - 127); + [[fallthrough]]; + case 63: + memcpy_sse2_32(dd - 63, ss - 63); + memcpy_sse2_16(dd - 31, ss - 31); + memcpy_sse2_16(dd - 16, ss - 16); + break; + + case 128: + memcpy_sse2_128(dd - 128, ss - 128); + break; + } + + return dst; +} + + +//--------------------------------------------------------------------- +// main routine +//--------------------------------------------------------------------- +void* memcpy_fast_sse(void * __restrict destination, const void * __restrict source, size_t size) +{ + unsigned char *dst = (unsigned char*)destination; + const unsigned char *src = (const unsigned char*)source; + static size_t cachesize = 0x200000; // L2-cache size + size_t padding; + + // small memory copy + if (size <= 128) +{ + return memcpy_tiny(dst, src, size); + } + + // align destination to 16 bytes boundary + padding = (16 - (((size_t)dst) & 15)) & 15; + + if (padding > 0) + { + __m128i head = _mm_loadu_si128(reinterpret_cast(src)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), head); + dst += padding; + src += padding; + size -= padding; + } + + // medium size copy + if (size <= cachesize) + { + __m128i c0, c1, c2, c3, c4, c5, c6, c7; + + for (; size >= 128; size -= 128) + { + c0 = _mm_loadu_si128((reinterpret_cast(src)) + 0); + c1 = _mm_loadu_si128((reinterpret_cast(src)) + 1); + c2 = _mm_loadu_si128((reinterpret_cast(src)) + 2); + c3 = _mm_loadu_si128((reinterpret_cast(src)) + 3); + c4 = _mm_loadu_si128((reinterpret_cast(src)) + 4); + c5 = _mm_loadu_si128((reinterpret_cast(src)) + 5); + c6 = _mm_loadu_si128((reinterpret_cast(src)) + 6); + c7 = _mm_loadu_si128((reinterpret_cast(src)) + 7); + _mm_prefetch((const char*)(src + 256), _MM_HINT_NTA); + src += 128; + _mm_store_si128(((reinterpret_cast<__m128i*>(dst)) + 0), c0); + _mm_store_si128(((reinterpret_cast<__m128i*>(dst)) + 1), c1); + _mm_store_si128(((reinterpret_cast<__m128i*>(dst)) + 2), c2); + _mm_store_si128(((reinterpret_cast<__m128i*>(dst)) + 3), c3); + _mm_store_si128(((reinterpret_cast<__m128i*>(dst)) + 4), c4); + _mm_store_si128(((reinterpret_cast<__m128i*>(dst)) + 5), c5); + _mm_store_si128(((reinterpret_cast<__m128i*>(dst)) + 6), c6); + _mm_store_si128(((reinterpret_cast<__m128i*>(dst)) + 7), c7); + dst += 128; + } + } + else + { // big memory copy + __m128i c0, c1, c2, c3, c4, c5, c6, c7; + + _mm_prefetch((const char*)(src), _MM_HINT_NTA); + + if ((((size_t)src) & 15) == 0) + { // source aligned + for (; size >= 128; size -= 128) + { + c0 = _mm_load_si128((reinterpret_cast(src)) + 0); + c1 = _mm_load_si128((reinterpret_cast(src)) + 1); + c2 = _mm_load_si128((reinterpret_cast(src)) + 2); + c3 = _mm_load_si128((reinterpret_cast(src)) + 3); + c4 = _mm_load_si128((reinterpret_cast(src)) + 4); + c5 = _mm_load_si128((reinterpret_cast(src)) + 5); + c6 = _mm_load_si128((reinterpret_cast(src)) + 6); + c7 = _mm_load_si128((reinterpret_cast(src)) + 7); + _mm_prefetch((const char*)(src + 256), _MM_HINT_NTA); + src += 128; + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 0), c0); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 1), c1); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 2), c2); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 3), c3); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 4), c4); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 5), c5); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 6), c6); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 7), c7); + dst += 128; + } + } + else + { // source unaligned + for (; size >= 128; size -= 128) + { + c0 = _mm_loadu_si128((reinterpret_cast(src)) + 0); + c1 = _mm_loadu_si128((reinterpret_cast(src)) + 1); + c2 = _mm_loadu_si128((reinterpret_cast(src)) + 2); + c3 = _mm_loadu_si128((reinterpret_cast(src)) + 3); + c4 = _mm_loadu_si128((reinterpret_cast(src)) + 4); + c5 = _mm_loadu_si128((reinterpret_cast(src)) + 5); + c6 = _mm_loadu_si128((reinterpret_cast(src)) + 6); + c7 = _mm_loadu_si128((reinterpret_cast(src)) + 7); + _mm_prefetch((const char*)(src + 256), _MM_HINT_NTA); + src += 128; + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 0), c0); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 1), c1); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 2), c2); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 3), c3); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 4), c4); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 5), c5); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 6), c6); + _mm_stream_si128(((reinterpret_cast<__m128i*>(dst)) + 7), c7); + dst += 128; + } + } + _mm_sfence(); + } + + memcpy_tiny(dst, src, size); + + return destination; +} diff --git a/utils/memcpy-bench/FastMemcpy_Avx.h b/utils/memcpy-bench/FastMemcpy_Avx.h new file mode 100644 index 00000000000..ee7d4e19536 --- /dev/null +++ b/utils/memcpy-bench/FastMemcpy_Avx.h @@ -0,0 +1,496 @@ +#pragma once + +//===================================================================== +// +// FastMemcpy.c - skywind3000@163.com, 2015 +// +// feature: +// 50% speed up in avg. vs standard memcpy (tested in vc2012/gcc5.1) +// +//===================================================================== + +#include +#include +#include + + +//--------------------------------------------------------------------- +// force inline for compilers +//--------------------------------------------------------------------- +#ifndef INLINE +#ifdef __GNUC__ +#if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) + #define INLINE __inline__ __attribute__((always_inline)) +#else + #define INLINE __inline__ +#endif +#elif defined(_MSC_VER) + #define INLINE __forceinline +#elif (defined(__BORLANDC__) || defined(__WATCOMC__)) + #define INLINE __inline +#else + #define INLINE +#endif +#endif + + +//--------------------------------------------------------------------- +// fast copy for different sizes +//--------------------------------------------------------------------- +static INLINE void memcpy_avx_16(void * __restrict dst, const void * __restrict src) +{ +#if 1 + __m128i m0 = _mm_loadu_si128(((const __m128i*)src) + 0); + _mm_storeu_si128(((__m128i*)dst) + 0, m0); +#else + *((uint64_t*)((char*)dst + 0)) = *((uint64_t*)((const char*)src + 0)); + *((uint64_t*)((char*)dst + 8)) = *((uint64_t*)((const char*)src + 8)); +#endif +} + +static INLINE void memcpy_avx_32(void *dst, const void *src) +{ + __m256i m0 = _mm256_loadu_si256((reinterpret_cast(src)) + 0); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 0, m0); +} + +static INLINE void memcpy_avx_64(void *dst, const void *src) +{ + __m256i m0 = _mm256_loadu_si256((reinterpret_cast(src)) + 0); + __m256i m1 = _mm256_loadu_si256((reinterpret_cast(src)) + 1); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 0, m0); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 1, m1); +} + +static INLINE void memcpy_avx_128(void *dst, const void *src) +{ + __m256i m0 = _mm256_loadu_si256((reinterpret_cast(src)) + 0); + __m256i m1 = _mm256_loadu_si256((reinterpret_cast(src)) + 1); + __m256i m2 = _mm256_loadu_si256((reinterpret_cast(src)) + 2); + __m256i m3 = _mm256_loadu_si256((reinterpret_cast(src)) + 3); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 0, m0); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 1, m1); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 2, m2); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 3, m3); +} + +static INLINE void memcpy_avx_256(void *dst, const void *src) +{ + __m256i m0 = _mm256_loadu_si256((reinterpret_cast(src)) + 0); + __m256i m1 = _mm256_loadu_si256((reinterpret_cast(src)) + 1); + __m256i m2 = _mm256_loadu_si256((reinterpret_cast(src)) + 2); + __m256i m3 = _mm256_loadu_si256((reinterpret_cast(src)) + 3); + __m256i m4 = _mm256_loadu_si256((reinterpret_cast(src)) + 4); + __m256i m5 = _mm256_loadu_si256((reinterpret_cast(src)) + 5); + __m256i m6 = _mm256_loadu_si256((reinterpret_cast(src)) + 6); + __m256i m7 = _mm256_loadu_si256((reinterpret_cast(src)) + 7); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 0, m0); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 1, m1); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 2, m2); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 3, m3); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 4, m4); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 5, m5); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 6, m6); + _mm256_storeu_si256((reinterpret_cast<__m256i*>(dst)) + 7, m7); +} + + +//--------------------------------------------------------------------- +// tiny memory copy with jump table optimized +//--------------------------------------------------------------------- +static INLINE void *memcpy_tiny_avx(void * __restrict dst, const void * __restrict src, size_t size) +{ + unsigned char *dd = reinterpret_cast(dst) + size; + const unsigned char *ss = reinterpret_cast(src) + size; + + switch (size) + { + case 128: memcpy_avx_128(dd - 128, ss - 128); [[fallthrough]]; + case 0: break; + case 129: memcpy_avx_128(dd - 129, ss - 129); [[fallthrough]]; + case 1: dd[-1] = ss[-1]; break; + case 130: memcpy_avx_128(dd - 130, ss - 130); [[fallthrough]]; + case 2: *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; + case 131: memcpy_avx_128(dd - 131, ss - 131); [[fallthrough]]; + case 3: *((uint16_t*)(dd - 3)) = *((uint16_t*)(ss - 3)); dd[-1] = ss[-1]; break; + case 132: memcpy_avx_128(dd - 132, ss - 132); [[fallthrough]]; + case 4: *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 133: memcpy_avx_128(dd - 133, ss - 133); [[fallthrough]]; + case 5: *((uint32_t*)(dd - 5)) = *((uint32_t*)(ss - 5)); dd[-1] = ss[-1]; break; + case 134: memcpy_avx_128(dd - 134, ss - 134); [[fallthrough]]; + case 6: *((uint32_t*)(dd - 6)) = *((uint32_t*)(ss - 6)); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; + case 135: memcpy_avx_128(dd - 135, ss - 135); [[fallthrough]]; + case 7: *((uint32_t*)(dd - 7)) = *((uint32_t*)(ss - 7)); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 136: memcpy_avx_128(dd - 136, ss - 136); [[fallthrough]]; + case 8: *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 137: memcpy_avx_128(dd - 137, ss - 137); [[fallthrough]]; + case 9: *((uint64_t*)(dd - 9)) = *((uint64_t*)(ss - 9)); dd[-1] = ss[-1]; break; + case 138: memcpy_avx_128(dd - 138, ss - 138); [[fallthrough]]; + case 10: *((uint64_t*)(dd - 10)) = *((uint64_t*)(ss - 10)); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; + case 139: memcpy_avx_128(dd - 139, ss - 139); [[fallthrough]]; + case 11: *((uint64_t*)(dd - 11)) = *((uint64_t*)(ss - 11)); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 140: memcpy_avx_128(dd - 140, ss - 140); [[fallthrough]]; + case 12: *((uint64_t*)(dd - 12)) = *((uint64_t*)(ss - 12)); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 141: memcpy_avx_128(dd - 141, ss - 141); [[fallthrough]]; + case 13: *((uint64_t*)(dd - 13)) = *((uint64_t*)(ss - 13)); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 142: memcpy_avx_128(dd - 142, ss - 142); [[fallthrough]]; + case 14: *((uint64_t*)(dd - 14)) = *((uint64_t*)(ss - 14)); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 143: memcpy_avx_128(dd - 143, ss - 143); [[fallthrough]]; + case 15: *((uint64_t*)(dd - 15)) = *((uint64_t*)(ss - 15)); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 144: memcpy_avx_128(dd - 144, ss - 144); [[fallthrough]]; + case 16: memcpy_avx_16(dd - 16, ss - 16); break; + case 145: memcpy_avx_128(dd - 145, ss - 145); [[fallthrough]]; + case 17: memcpy_avx_16(dd - 17, ss - 17); dd[-1] = ss[-1]; break; + case 146: memcpy_avx_128(dd - 146, ss - 146); [[fallthrough]]; + case 18: memcpy_avx_16(dd - 18, ss - 18); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; + case 147: memcpy_avx_128(dd - 147, ss - 147); [[fallthrough]]; + case 19: memcpy_avx_16(dd - 19, ss - 19); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 148: memcpy_avx_128(dd - 148, ss - 148); [[fallthrough]]; + case 20: memcpy_avx_16(dd - 20, ss - 20); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 149: memcpy_avx_128(dd - 149, ss - 149); [[fallthrough]]; + case 21: memcpy_avx_16(dd - 21, ss - 21); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 150: memcpy_avx_128(dd - 150, ss - 150); [[fallthrough]]; + case 22: memcpy_avx_16(dd - 22, ss - 22); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 151: memcpy_avx_128(dd - 151, ss - 151); [[fallthrough]]; + case 23: memcpy_avx_16(dd - 23, ss - 23); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 152: memcpy_avx_128(dd - 152, ss - 152); [[fallthrough]]; + case 24: memcpy_avx_16(dd - 24, ss - 24); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 153: memcpy_avx_128(dd - 153, ss - 153); [[fallthrough]]; + case 25: memcpy_avx_16(dd - 25, ss - 25); memcpy_avx_16(dd - 16, ss - 16); break; + case 154: memcpy_avx_128(dd - 154, ss - 154); [[fallthrough]]; + case 26: memcpy_avx_16(dd - 26, ss - 26); memcpy_avx_16(dd - 16, ss - 16); break; + case 155: memcpy_avx_128(dd - 155, ss - 155); [[fallthrough]]; + case 27: memcpy_avx_16(dd - 27, ss - 27); memcpy_avx_16(dd - 16, ss - 16); break; + case 156: memcpy_avx_128(dd - 156, ss - 156); [[fallthrough]]; + case 28: memcpy_avx_16(dd - 28, ss - 28); memcpy_avx_16(dd - 16, ss - 16); break; + case 157: memcpy_avx_128(dd - 157, ss - 157); [[fallthrough]]; + case 29: memcpy_avx_16(dd - 29, ss - 29); memcpy_avx_16(dd - 16, ss - 16); break; + case 158: memcpy_avx_128(dd - 158, ss - 158); [[fallthrough]]; + case 30: memcpy_avx_16(dd - 30, ss - 30); memcpy_avx_16(dd - 16, ss - 16); break; + case 159: memcpy_avx_128(dd - 159, ss - 159); [[fallthrough]]; + case 31: memcpy_avx_16(dd - 31, ss - 31); memcpy_avx_16(dd - 16, ss - 16); break; + case 160: memcpy_avx_128(dd - 160, ss - 160); [[fallthrough]]; + case 32: memcpy_avx_32(dd - 32, ss - 32); break; + case 161: memcpy_avx_128(dd - 161, ss - 161); [[fallthrough]]; + case 33: memcpy_avx_32(dd - 33, ss - 33); dd[-1] = ss[-1]; break; + case 162: memcpy_avx_128(dd - 162, ss - 162); [[fallthrough]]; + case 34: memcpy_avx_32(dd - 34, ss - 34); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; + case 163: memcpy_avx_128(dd - 163, ss - 163); [[fallthrough]]; + case 35: memcpy_avx_32(dd - 35, ss - 35); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 164: memcpy_avx_128(dd - 164, ss - 164); [[fallthrough]]; + case 36: memcpy_avx_32(dd - 36, ss - 36); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 165: memcpy_avx_128(dd - 165, ss - 165); [[fallthrough]]; + case 37: memcpy_avx_32(dd - 37, ss - 37); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 166: memcpy_avx_128(dd - 166, ss - 166); [[fallthrough]]; + case 38: memcpy_avx_32(dd - 38, ss - 38); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 167: memcpy_avx_128(dd - 167, ss - 167); [[fallthrough]]; + case 39: memcpy_avx_32(dd - 39, ss - 39); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 168: memcpy_avx_128(dd - 168, ss - 168); [[fallthrough]]; + case 40: memcpy_avx_32(dd - 40, ss - 40); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 169: memcpy_avx_128(dd - 169, ss - 169); [[fallthrough]]; + case 41: memcpy_avx_32(dd - 41, ss - 41); memcpy_avx_16(dd - 16, ss - 16); break; + case 170: memcpy_avx_128(dd - 170, ss - 170); [[fallthrough]]; + case 42: memcpy_avx_32(dd - 42, ss - 42); memcpy_avx_16(dd - 16, ss - 16); break; + case 171: memcpy_avx_128(dd - 171, ss - 171); [[fallthrough]]; + case 43: memcpy_avx_32(dd - 43, ss - 43); memcpy_avx_16(dd - 16, ss - 16); break; + case 172: memcpy_avx_128(dd - 172, ss - 172); [[fallthrough]]; + case 44: memcpy_avx_32(dd - 44, ss - 44); memcpy_avx_16(dd - 16, ss - 16); break; + case 173: memcpy_avx_128(dd - 173, ss - 173); [[fallthrough]]; + case 45: memcpy_avx_32(dd - 45, ss - 45); memcpy_avx_16(dd - 16, ss - 16); break; + case 174: memcpy_avx_128(dd - 174, ss - 174); [[fallthrough]]; + case 46: memcpy_avx_32(dd - 46, ss - 46); memcpy_avx_16(dd - 16, ss - 16); break; + case 175: memcpy_avx_128(dd - 175, ss - 175); [[fallthrough]]; + case 47: memcpy_avx_32(dd - 47, ss - 47); memcpy_avx_16(dd - 16, ss - 16); break; + case 176: memcpy_avx_128(dd - 176, ss - 176); [[fallthrough]]; + case 48: memcpy_avx_32(dd - 48, ss - 48); memcpy_avx_16(dd - 16, ss - 16); break; + case 177: memcpy_avx_128(dd - 177, ss - 177); [[fallthrough]]; + case 49: memcpy_avx_32(dd - 49, ss - 49); memcpy_avx_32(dd - 32, ss - 32); break; + case 178: memcpy_avx_128(dd - 178, ss - 178); [[fallthrough]]; + case 50: memcpy_avx_32(dd - 50, ss - 50); memcpy_avx_32(dd - 32, ss - 32); break; + case 179: memcpy_avx_128(dd - 179, ss - 179); [[fallthrough]]; + case 51: memcpy_avx_32(dd - 51, ss - 51); memcpy_avx_32(dd - 32, ss - 32); break; + case 180: memcpy_avx_128(dd - 180, ss - 180); [[fallthrough]]; + case 52: memcpy_avx_32(dd - 52, ss - 52); memcpy_avx_32(dd - 32, ss - 32); break; + case 181: memcpy_avx_128(dd - 181, ss - 181); [[fallthrough]]; + case 53: memcpy_avx_32(dd - 53, ss - 53); memcpy_avx_32(dd - 32, ss - 32); break; + case 182: memcpy_avx_128(dd - 182, ss - 182); [[fallthrough]]; + case 54: memcpy_avx_32(dd - 54, ss - 54); memcpy_avx_32(dd - 32, ss - 32); break; + case 183: memcpy_avx_128(dd - 183, ss - 183); [[fallthrough]]; + case 55: memcpy_avx_32(dd - 55, ss - 55); memcpy_avx_32(dd - 32, ss - 32); break; + case 184: memcpy_avx_128(dd - 184, ss - 184); [[fallthrough]]; + case 56: memcpy_avx_32(dd - 56, ss - 56); memcpy_avx_32(dd - 32, ss - 32); break; + case 185: memcpy_avx_128(dd - 185, ss - 185); [[fallthrough]]; + case 57: memcpy_avx_32(dd - 57, ss - 57); memcpy_avx_32(dd - 32, ss - 32); break; + case 186: memcpy_avx_128(dd - 186, ss - 186); [[fallthrough]]; + case 58: memcpy_avx_32(dd - 58, ss - 58); memcpy_avx_32(dd - 32, ss - 32); break; + case 187: memcpy_avx_128(dd - 187, ss - 187); [[fallthrough]]; + case 59: memcpy_avx_32(dd - 59, ss - 59); memcpy_avx_32(dd - 32, ss - 32); break; + case 188: memcpy_avx_128(dd - 188, ss - 188); [[fallthrough]]; + case 60: memcpy_avx_32(dd - 60, ss - 60); memcpy_avx_32(dd - 32, ss - 32); break; + case 189: memcpy_avx_128(dd - 189, ss - 189); [[fallthrough]]; + case 61: memcpy_avx_32(dd - 61, ss - 61); memcpy_avx_32(dd - 32, ss - 32); break; + case 190: memcpy_avx_128(dd - 190, ss - 190); [[fallthrough]]; + case 62: memcpy_avx_32(dd - 62, ss - 62); memcpy_avx_32(dd - 32, ss - 32); break; + case 191: memcpy_avx_128(dd - 191, ss - 191); [[fallthrough]]; + case 63: memcpy_avx_32(dd - 63, ss - 63); memcpy_avx_32(dd - 32, ss - 32); break; + case 192: memcpy_avx_128(dd - 192, ss - 192); [[fallthrough]]; + case 64: memcpy_avx_64(dd - 64, ss - 64); break; + case 193: memcpy_avx_128(dd - 193, ss - 193); [[fallthrough]]; + case 65: memcpy_avx_64(dd - 65, ss - 65); dd[-1] = ss[-1]; break; + case 194: memcpy_avx_128(dd - 194, ss - 194); [[fallthrough]]; + case 66: memcpy_avx_64(dd - 66, ss - 66); *((uint16_t*)(dd - 2)) = *((uint16_t*)(ss - 2)); break; + case 195: memcpy_avx_128(dd - 195, ss - 195); [[fallthrough]]; + case 67: memcpy_avx_64(dd - 67, ss - 67); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 196: memcpy_avx_128(dd - 196, ss - 196); [[fallthrough]]; + case 68: memcpy_avx_64(dd - 68, ss - 68); *((uint32_t*)(dd - 4)) = *((uint32_t*)(ss - 4)); break; + case 197: memcpy_avx_128(dd - 197, ss - 197); [[fallthrough]]; + case 69: memcpy_avx_64(dd - 69, ss - 69); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 198: memcpy_avx_128(dd - 198, ss - 198); [[fallthrough]]; + case 70: memcpy_avx_64(dd - 70, ss - 70); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 199: memcpy_avx_128(dd - 199, ss - 199); [[fallthrough]]; + case 71: memcpy_avx_64(dd - 71, ss - 71); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 200: memcpy_avx_128(dd - 200, ss - 200); [[fallthrough]]; + case 72: memcpy_avx_64(dd - 72, ss - 72); *((uint64_t*)(dd - 8)) = *((uint64_t*)(ss - 8)); break; + case 201: memcpy_avx_128(dd - 201, ss - 201); [[fallthrough]]; + case 73: memcpy_avx_64(dd - 73, ss - 73); memcpy_avx_16(dd - 16, ss - 16); break; + case 202: memcpy_avx_128(dd - 202, ss - 202); [[fallthrough]]; + case 74: memcpy_avx_64(dd - 74, ss - 74); memcpy_avx_16(dd - 16, ss - 16); break; + case 203: memcpy_avx_128(dd - 203, ss - 203); [[fallthrough]]; + case 75: memcpy_avx_64(dd - 75, ss - 75); memcpy_avx_16(dd - 16, ss - 16); break; + case 204: memcpy_avx_128(dd - 204, ss - 204); [[fallthrough]]; + case 76: memcpy_avx_64(dd - 76, ss - 76); memcpy_avx_16(dd - 16, ss - 16); break; + case 205: memcpy_avx_128(dd - 205, ss - 205); [[fallthrough]]; + case 77: memcpy_avx_64(dd - 77, ss - 77); memcpy_avx_16(dd - 16, ss - 16); break; + case 206: memcpy_avx_128(dd - 206, ss - 206); [[fallthrough]]; + case 78: memcpy_avx_64(dd - 78, ss - 78); memcpy_avx_16(dd - 16, ss - 16); break; + case 207: memcpy_avx_128(dd - 207, ss - 207); [[fallthrough]]; + case 79: memcpy_avx_64(dd - 79, ss - 79); memcpy_avx_16(dd - 16, ss - 16); break; + case 208: memcpy_avx_128(dd - 208, ss - 208); [[fallthrough]]; + case 80: memcpy_avx_64(dd - 80, ss - 80); memcpy_avx_16(dd - 16, ss - 16); break; + case 209: memcpy_avx_128(dd - 209, ss - 209); [[fallthrough]]; + case 81: memcpy_avx_64(dd - 81, ss - 81); memcpy_avx_32(dd - 32, ss - 32); break; + case 210: memcpy_avx_128(dd - 210, ss - 210); [[fallthrough]]; + case 82: memcpy_avx_64(dd - 82, ss - 82); memcpy_avx_32(dd - 32, ss - 32); break; + case 211: memcpy_avx_128(dd - 211, ss - 211); [[fallthrough]]; + case 83: memcpy_avx_64(dd - 83, ss - 83); memcpy_avx_32(dd - 32, ss - 32); break; + case 212: memcpy_avx_128(dd - 212, ss - 212); [[fallthrough]]; + case 84: memcpy_avx_64(dd - 84, ss - 84); memcpy_avx_32(dd - 32, ss - 32); break; + case 213: memcpy_avx_128(dd - 213, ss - 213); [[fallthrough]]; + case 85: memcpy_avx_64(dd - 85, ss - 85); memcpy_avx_32(dd - 32, ss - 32); break; + case 214: memcpy_avx_128(dd - 214, ss - 214); [[fallthrough]]; + case 86: memcpy_avx_64(dd - 86, ss - 86); memcpy_avx_32(dd - 32, ss - 32); break; + case 215: memcpy_avx_128(dd - 215, ss - 215); [[fallthrough]]; + case 87: memcpy_avx_64(dd - 87, ss - 87); memcpy_avx_32(dd - 32, ss - 32); break; + case 216: memcpy_avx_128(dd - 216, ss - 216); [[fallthrough]]; + case 88: memcpy_avx_64(dd - 88, ss - 88); memcpy_avx_32(dd - 32, ss - 32); break; + case 217: memcpy_avx_128(dd - 217, ss - 217); [[fallthrough]]; + case 89: memcpy_avx_64(dd - 89, ss - 89); memcpy_avx_32(dd - 32, ss - 32); break; + case 218: memcpy_avx_128(dd - 218, ss - 218); [[fallthrough]]; + case 90: memcpy_avx_64(dd - 90, ss - 90); memcpy_avx_32(dd - 32, ss - 32); break; + case 219: memcpy_avx_128(dd - 219, ss - 219); [[fallthrough]]; + case 91: memcpy_avx_64(dd - 91, ss - 91); memcpy_avx_32(dd - 32, ss - 32); break; + case 220: memcpy_avx_128(dd - 220, ss - 220); [[fallthrough]]; + case 92: memcpy_avx_64(dd - 92, ss - 92); memcpy_avx_32(dd - 32, ss - 32); break; + case 221: memcpy_avx_128(dd - 221, ss - 221); [[fallthrough]]; + case 93: memcpy_avx_64(dd - 93, ss - 93); memcpy_avx_32(dd - 32, ss - 32); break; + case 222: memcpy_avx_128(dd - 222, ss - 222); [[fallthrough]]; + case 94: memcpy_avx_64(dd - 94, ss - 94); memcpy_avx_32(dd - 32, ss - 32); break; + case 223: memcpy_avx_128(dd - 223, ss - 223); [[fallthrough]]; + case 95: memcpy_avx_64(dd - 95, ss - 95); memcpy_avx_32(dd - 32, ss - 32); break; + case 224: memcpy_avx_128(dd - 224, ss - 224); [[fallthrough]]; + case 96: memcpy_avx_64(dd - 96, ss - 96); memcpy_avx_32(dd - 32, ss - 32); break; + case 225: memcpy_avx_128(dd - 225, ss - 225); [[fallthrough]]; + case 97: memcpy_avx_64(dd - 97, ss - 97); memcpy_avx_64(dd - 64, ss - 64); break; + case 226: memcpy_avx_128(dd - 226, ss - 226); [[fallthrough]]; + case 98: memcpy_avx_64(dd - 98, ss - 98); memcpy_avx_64(dd - 64, ss - 64); break; + case 227: memcpy_avx_128(dd - 227, ss - 227); [[fallthrough]]; + case 99: memcpy_avx_64(dd - 99, ss - 99); memcpy_avx_64(dd - 64, ss - 64); break; + case 228: memcpy_avx_128(dd - 228, ss - 228); [[fallthrough]]; + case 100: memcpy_avx_64(dd - 100, ss - 100); memcpy_avx_64(dd - 64, ss - 64); break; + case 229: memcpy_avx_128(dd - 229, ss - 229); [[fallthrough]]; + case 101: memcpy_avx_64(dd - 101, ss - 101); memcpy_avx_64(dd - 64, ss - 64); break; + case 230: memcpy_avx_128(dd - 230, ss - 230); [[fallthrough]]; + case 102: memcpy_avx_64(dd - 102, ss - 102); memcpy_avx_64(dd - 64, ss - 64); break; + case 231: memcpy_avx_128(dd - 231, ss - 231); [[fallthrough]]; + case 103: memcpy_avx_64(dd - 103, ss - 103); memcpy_avx_64(dd - 64, ss - 64); break; + case 232: memcpy_avx_128(dd - 232, ss - 232); [[fallthrough]]; + case 104: memcpy_avx_64(dd - 104, ss - 104); memcpy_avx_64(dd - 64, ss - 64); break; + case 233: memcpy_avx_128(dd - 233, ss - 233); [[fallthrough]]; + case 105: memcpy_avx_64(dd - 105, ss - 105); memcpy_avx_64(dd - 64, ss - 64); break; + case 234: memcpy_avx_128(dd - 234, ss - 234); [[fallthrough]]; + case 106: memcpy_avx_64(dd - 106, ss - 106); memcpy_avx_64(dd - 64, ss - 64); break; + case 235: memcpy_avx_128(dd - 235, ss - 235); [[fallthrough]]; + case 107: memcpy_avx_64(dd - 107, ss - 107); memcpy_avx_64(dd - 64, ss - 64); break; + case 236: memcpy_avx_128(dd - 236, ss - 236); [[fallthrough]]; + case 108: memcpy_avx_64(dd - 108, ss - 108); memcpy_avx_64(dd - 64, ss - 64); break; + case 237: memcpy_avx_128(dd - 237, ss - 237); [[fallthrough]]; + case 109: memcpy_avx_64(dd - 109, ss - 109); memcpy_avx_64(dd - 64, ss - 64); break; + case 238: memcpy_avx_128(dd - 238, ss - 238); [[fallthrough]]; + case 110: memcpy_avx_64(dd - 110, ss - 110); memcpy_avx_64(dd - 64, ss - 64); break; + case 239: memcpy_avx_128(dd - 239, ss - 239); [[fallthrough]]; + case 111: memcpy_avx_64(dd - 111, ss - 111); memcpy_avx_64(dd - 64, ss - 64); break; + case 240: memcpy_avx_128(dd - 240, ss - 240); [[fallthrough]]; + case 112: memcpy_avx_64(dd - 112, ss - 112); memcpy_avx_64(dd - 64, ss - 64); break; + case 241: memcpy_avx_128(dd - 241, ss - 241); [[fallthrough]]; + case 113: memcpy_avx_64(dd - 113, ss - 113); memcpy_avx_64(dd - 64, ss - 64); break; + case 242: memcpy_avx_128(dd - 242, ss - 242); [[fallthrough]]; + case 114: memcpy_avx_64(dd - 114, ss - 114); memcpy_avx_64(dd - 64, ss - 64); break; + case 243: memcpy_avx_128(dd - 243, ss - 243); [[fallthrough]]; + case 115: memcpy_avx_64(dd - 115, ss - 115); memcpy_avx_64(dd - 64, ss - 64); break; + case 244: memcpy_avx_128(dd - 244, ss - 244); [[fallthrough]]; + case 116: memcpy_avx_64(dd - 116, ss - 116); memcpy_avx_64(dd - 64, ss - 64); break; + case 245: memcpy_avx_128(dd - 245, ss - 245); [[fallthrough]]; + case 117: memcpy_avx_64(dd - 117, ss - 117); memcpy_avx_64(dd - 64, ss - 64); break; + case 246: memcpy_avx_128(dd - 246, ss - 246); [[fallthrough]]; + case 118: memcpy_avx_64(dd - 118, ss - 118); memcpy_avx_64(dd - 64, ss - 64); break; + case 247: memcpy_avx_128(dd - 247, ss - 247); [[fallthrough]]; + case 119: memcpy_avx_64(dd - 119, ss - 119); memcpy_avx_64(dd - 64, ss - 64); break; + case 248: memcpy_avx_128(dd - 248, ss - 248); [[fallthrough]]; + case 120: memcpy_avx_64(dd - 120, ss - 120); memcpy_avx_64(dd - 64, ss - 64); break; + case 249: memcpy_avx_128(dd - 249, ss - 249); [[fallthrough]]; + case 121: memcpy_avx_64(dd - 121, ss - 121); memcpy_avx_64(dd - 64, ss - 64); break; + case 250: memcpy_avx_128(dd - 250, ss - 250); [[fallthrough]]; + case 122: memcpy_avx_64(dd - 122, ss - 122); memcpy_avx_64(dd - 64, ss - 64); break; + case 251: memcpy_avx_128(dd - 251, ss - 251); [[fallthrough]]; + case 123: memcpy_avx_64(dd - 123, ss - 123); memcpy_avx_64(dd - 64, ss - 64); break; + case 252: memcpy_avx_128(dd - 252, ss - 252); [[fallthrough]]; + case 124: memcpy_avx_64(dd - 124, ss - 124); memcpy_avx_64(dd - 64, ss - 64); break; + case 253: memcpy_avx_128(dd - 253, ss - 253); [[fallthrough]]; + case 125: memcpy_avx_64(dd - 125, ss - 125); memcpy_avx_64(dd - 64, ss - 64); break; + case 254: memcpy_avx_128(dd - 254, ss - 254); [[fallthrough]]; + case 126: memcpy_avx_64(dd - 126, ss - 126); memcpy_avx_64(dd - 64, ss - 64); break; + case 255: memcpy_avx_128(dd - 255, ss - 255); [[fallthrough]]; + case 127: memcpy_avx_64(dd - 127, ss - 127); memcpy_avx_64(dd - 64, ss - 64); break; + case 256: memcpy_avx_256(dd - 256, ss - 256); break; + } + + return dst; +} + + +//--------------------------------------------------------------------- +// main routine +//--------------------------------------------------------------------- +void* memcpy_fast_avx(void * __restrict destination, const void * __restrict source, size_t size) +{ + unsigned char *dst = reinterpret_cast(destination); + const unsigned char *src = reinterpret_cast(source); + static size_t cachesize = 0x200000; // L3-cache size + size_t padding; + + // small memory copy + if (size <= 256) + { + memcpy_tiny_avx(dst, src, size); + _mm256_zeroupper(); + return destination; + } + + // align destination to 16 bytes boundary + padding = (32 - (((size_t)dst) & 31)) & 31; + +#if 0 + if (padding > 0) + { + __m256i head = _mm256_loadu_si256(reinterpret_cast(src)); + _mm256_storeu_si256((__m256i*)dst, head); + dst += padding; + src += padding; + size -= padding; + } +#else + __m256i head = _mm256_loadu_si256(reinterpret_cast(src)); + _mm256_storeu_si256((__m256i*)dst, head); + dst += padding; + src += padding; + size -= padding; +#endif + + // medium size copy + if (size <= cachesize) + { + __m256i c0, c1, c2, c3, c4, c5, c6, c7; + + for (; size >= 256; size -= 256) + { + c0 = _mm256_loadu_si256((reinterpret_cast(src)) + 0); + c1 = _mm256_loadu_si256((reinterpret_cast(src)) + 1); + c2 = _mm256_loadu_si256((reinterpret_cast(src)) + 2); + c3 = _mm256_loadu_si256((reinterpret_cast(src)) + 3); + c4 = _mm256_loadu_si256((reinterpret_cast(src)) + 4); + c5 = _mm256_loadu_si256((reinterpret_cast(src)) + 5); + c6 = _mm256_loadu_si256((reinterpret_cast(src)) + 6); + c7 = _mm256_loadu_si256((reinterpret_cast(src)) + 7); + src += 256; + _mm256_storeu_si256(((reinterpret_cast<__m256i*>(dst)) + 0), c0); + _mm256_storeu_si256(((reinterpret_cast<__m256i*>(dst)) + 1), c1); + _mm256_storeu_si256(((reinterpret_cast<__m256i*>(dst)) + 2), c2); + _mm256_storeu_si256(((reinterpret_cast<__m256i*>(dst)) + 3), c3); + _mm256_storeu_si256(((reinterpret_cast<__m256i*>(dst)) + 4), c4); + _mm256_storeu_si256(((reinterpret_cast<__m256i*>(dst)) + 5), c5); + _mm256_storeu_si256(((reinterpret_cast<__m256i*>(dst)) + 6), c6); + _mm256_storeu_si256(((reinterpret_cast<__m256i*>(dst)) + 7), c7); + dst += 256; + } + } + else + { // big memory copy + __m256i c0, c1, c2, c3, c4, c5, c6, c7; + /* __m256i c0, c1, c2, c3, c4, c5, c6, c7; */ + + if ((((size_t)src) & 31) == 0) + { // source aligned + for (; size >= 256; size -= 256) + { + c0 = _mm256_load_si256((reinterpret_cast(src)) + 0); + c1 = _mm256_load_si256((reinterpret_cast(src)) + 1); + c2 = _mm256_load_si256((reinterpret_cast(src)) + 2); + c3 = _mm256_load_si256((reinterpret_cast(src)) + 3); + c4 = _mm256_load_si256((reinterpret_cast(src)) + 4); + c5 = _mm256_load_si256((reinterpret_cast(src)) + 5); + c6 = _mm256_load_si256((reinterpret_cast(src)) + 6); + c7 = _mm256_load_si256((reinterpret_cast(src)) + 7); + src += 256; + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 0), c0); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 1), c1); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 2), c2); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 3), c3); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 4), c4); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 5), c5); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 6), c6); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 7), c7); + dst += 256; + } + } + else + { // source unaligned + for (; size >= 256; size -= 256) + { + c0 = _mm256_loadu_si256((reinterpret_cast(src)) + 0); + c1 = _mm256_loadu_si256((reinterpret_cast(src)) + 1); + c2 = _mm256_loadu_si256((reinterpret_cast(src)) + 2); + c3 = _mm256_loadu_si256((reinterpret_cast(src)) + 3); + c4 = _mm256_loadu_si256((reinterpret_cast(src)) + 4); + c5 = _mm256_loadu_si256((reinterpret_cast(src)) + 5); + c6 = _mm256_loadu_si256((reinterpret_cast(src)) + 6); + c7 = _mm256_loadu_si256((reinterpret_cast(src)) + 7); + src += 256; + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 0), c0); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 1), c1); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 2), c2); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 3), c3); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 4), c4); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 5), c5); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 6), c6); + _mm256_stream_si256(((reinterpret_cast<__m256i*>(dst)) + 7), c7); + dst += 256; + } + } + _mm_sfence(); + } + + memcpy_tiny_avx(dst, src, size); + _mm256_zeroupper(); + + return destination; +} diff --git a/utils/memcpy-bench/memcpy-bench.cpp b/utils/memcpy-bench/memcpy-bench.cpp new file mode 100644 index 00000000000..2df72cb5ccb --- /dev/null +++ b/utils/memcpy-bench/memcpy-bench.cpp @@ -0,0 +1,620 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Wcast-qual" +#include "FastMemcpy.h" +//#include "FastMemcpy_Avx.h" + +#include +#include + + +template +void NO_INLINE loop(uint8_t * dst, uint8_t * src, size_t size, F && chunk_size_distribution, MemcpyImpl && impl) +{ + while (size) + { + size_t bytes_to_copy = std::min(size, chunk_size_distribution()); + + impl(dst, src, bytes_to_copy); + + dst += bytes_to_copy; + src += bytes_to_copy; + size -= bytes_to_copy; + } +} + + +using RNG = pcg32_fast; + +template +size_t generatorUniform(RNG & rng) { return rng() % N; }; + + +template +void test(uint8_t * dst, uint8_t * src, size_t size, size_t iterations, size_t num_threads, F && generator, MemcpyImpl && impl) +{ + Stopwatch watch; + + std::vector threads; + threads.reserve(num_threads); + + for (size_t thread_num = 0; thread_num < num_threads; ++thread_num) + { + size_t begin = size * thread_num / num_threads; + size_t end = size * (thread_num + 1) / num_threads; + + threads.emplace_back([begin, end, iterations, &src, &dst, &generator, &impl] + { + for (size_t iteration = 0; iteration < iterations; ++iteration) + { + loop( + iteration % 2 ? &src[begin] : &dst[begin], + iteration % 2 ? &dst[begin] : &src[begin], + end - begin, + [rng = RNG(), &generator]() mutable { return generator(rng); }, + std::forward(impl)); + } + }); + } + + for (auto & thread : threads) + thread.join(); + + double elapsed_ns = watch.elapsed(); + + /// Validation + size_t sum = 0; + for (size_t i = 0; i < size; ++i) + sum += dst[i]; + + std::cerr << std::fixed << std::setprecision(3) + << "Processed in " << (elapsed_ns / 1e9) << "sec, " << (size * iterations * 1.0 / elapsed_ns) << " GB/sec (sum = " << sum << ")\n"; +} + + +using memcpy_type = void * (*)(const void * __restrict, void * __restrict, size_t); + + +static void * memcpy_erms(void * dst, const void * src, size_t size) +{ + asm volatile ( + "rep movsb" + : "=D"(dst), "=S"(src), "=c"(size) + : "0"(dst), "1"(src), "2"(size) + : "memory"); + return dst; +} + +extern "C" void * memcpy_jart(void * dst, const void * src, size_t size); +extern "C" void MemCpy(void * dst, const void * src, size_t size); + + +static void * memcpySSE2(void * __restrict destination, const void * __restrict source, size_t size) +{ + unsigned char *dst = reinterpret_cast(destination); + const unsigned char *src = reinterpret_cast(source); + size_t padding; + + // small memory copy + if (size <= 16) + return memcpy_tiny(dst, src, size); + + // align destination to 16 bytes boundary + padding = (16 - (reinterpret_cast(dst) & 15)) & 15; + + if (padding > 0) + { + __m128i head = _mm_loadu_si128(reinterpret_cast(src)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), head); + dst += padding; + src += padding; + size -= padding; + } + + // medium size copy + __m128i c0; + + for (; size >= 16; size -= 16) + { + c0 = _mm_loadu_si128(reinterpret_cast(src)); + src += 16; + _mm_store_si128((reinterpret_cast<__m128i*>(dst)), c0); + dst += 16; + } + + memcpy_tiny(dst, src, size); + return destination; +} + +static void * memcpySSE2Unrolled2(void * __restrict destination, const void * __restrict source, size_t size) +{ + unsigned char *dst = reinterpret_cast(destination); + const unsigned char *src = reinterpret_cast(source); + size_t padding; + + // small memory copy + if (size <= 32) + return memcpy_tiny(dst, src, size); + + // align destination to 16 bytes boundary + padding = (16 - (reinterpret_cast(dst) & 15)) & 15; + + if (padding > 0) + { + __m128i head = _mm_loadu_si128(reinterpret_cast(src)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), head); + dst += padding; + src += padding; + size -= padding; + } + + // medium size copy + __m128i c0, c1; + + for (; size >= 32; size -= 32) + { + c0 = _mm_loadu_si128(reinterpret_cast(src) + 0); + c1 = _mm_loadu_si128(reinterpret_cast(src) + 1); + src += 32; + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 0), c0); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 1), c1); + dst += 32; + } + + memcpy_tiny(dst, src, size); + return destination; +} + +static void * memcpySSE2Unrolled4(void * __restrict destination, const void * __restrict source, size_t size) +{ + unsigned char *dst = reinterpret_cast(destination); + const unsigned char *src = reinterpret_cast(source); + size_t padding; + + // small memory copy + if (size <= 64) + return memcpy_tiny(dst, src, size); + + // align destination to 16 bytes boundary + padding = (16 - (reinterpret_cast(dst) & 15)) & 15; + + if (padding > 0) + { + __m128i head = _mm_loadu_si128(reinterpret_cast(src)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), head); + dst += padding; + src += padding; + size -= padding; + } + + // medium size copy + __m128i c0, c1, c2, c3; + + for (; size >= 64; size -= 64) + { + c0 = _mm_loadu_si128(reinterpret_cast(src) + 0); + c1 = _mm_loadu_si128(reinterpret_cast(src) + 1); + c2 = _mm_loadu_si128(reinterpret_cast(src) + 2); + c3 = _mm_loadu_si128(reinterpret_cast(src) + 3); + src += 64; + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 0), c0); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 1), c1); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 2), c2); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 3), c3); + dst += 64; + } + + memcpy_tiny(dst, src, size); + return destination; +} + + +static void * memcpySSE2Unrolled8(void * __restrict destination, const void * __restrict source, size_t size) +{ + unsigned char *dst = reinterpret_cast(destination); + const unsigned char *src = reinterpret_cast(source); + size_t padding; + + // small memory copy + if (size <= 128) + return memcpy_tiny(dst, src, size); + + // align destination to 16 bytes boundary + padding = (16 - (reinterpret_cast(dst) & 15)) & 15; + + if (padding > 0) + { + __m128i head = _mm_loadu_si128(reinterpret_cast(src)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), head); + dst += padding; + src += padding; + size -= padding; + } + + // medium size copy + __m128i c0, c1, c2, c3, c4, c5, c6, c7; + + for (; size >= 128; size -= 128) + { + c0 = _mm_loadu_si128(reinterpret_cast(src) + 0); + c1 = _mm_loadu_si128(reinterpret_cast(src) + 1); + c2 = _mm_loadu_si128(reinterpret_cast(src) + 2); + c3 = _mm_loadu_si128(reinterpret_cast(src) + 3); + c4 = _mm_loadu_si128(reinterpret_cast(src) + 4); + c5 = _mm_loadu_si128(reinterpret_cast(src) + 5); + c6 = _mm_loadu_si128(reinterpret_cast(src) + 6); + c7 = _mm_loadu_si128(reinterpret_cast(src) + 7); + src += 128; + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 0), c0); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 1), c1); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 2), c2); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 3), c3); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 4), c4); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 5), c5); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 6), c6); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 7), c7); + dst += 128; + } + + memcpy_tiny(dst, src, size); + return destination; +} + + +//static __attribute__((__always_inline__, __target__("sse2"))) +__attribute__((__always_inline__)) +void memcpy_my_medium_sse(uint8_t * __restrict & dst, const uint8_t * __restrict & src, size_t & size) +{ + /// Align destination to 16 bytes boundary. + size_t padding = (16 - (reinterpret_cast(dst) & 15)) & 15; + + if (padding > 0) + { + __m128i head = _mm_loadu_si128(reinterpret_cast(src)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), head); + dst += padding; + src += padding; + size -= padding; + } + + /// Aligned unrolled copy. + __m128i c0, c1, c2, c3, c4, c5, c6, c7; + + while (size >= 128) + { + c0 = _mm_loadu_si128(reinterpret_cast(src) + 0); + c1 = _mm_loadu_si128(reinterpret_cast(src) + 1); + c2 = _mm_loadu_si128(reinterpret_cast(src) + 2); + c3 = _mm_loadu_si128(reinterpret_cast(src) + 3); + c4 = _mm_loadu_si128(reinterpret_cast(src) + 4); + c5 = _mm_loadu_si128(reinterpret_cast(src) + 5); + c6 = _mm_loadu_si128(reinterpret_cast(src) + 6); + c7 = _mm_loadu_si128(reinterpret_cast(src) + 7); + src += 128; + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 0), c0); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 1), c1); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 2), c2); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 3), c3); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 4), c4); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 5), c5); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 6), c6); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 7), c7); + dst += 128; + + size -= 128; + } +} + +__attribute__((__target__("avx"))) +void memcpy_my_medium_avx(uint8_t * __restrict & __restrict dst, const uint8_t * __restrict & __restrict src, size_t & __restrict size) +{ + size_t padding = (32 - (reinterpret_cast(dst) & 31)) & 31; + + if (padding > 0) + { + __m256i head = _mm256_loadu_si256(reinterpret_cast(src)); + _mm256_storeu_si256((__m256i*)dst, head); + dst += padding; + src += padding; + size -= padding; + } + + __m256i c0, c1, c2, c3, c4, c5, c6, c7; + + while (size >= 256) + { + c0 = _mm256_loadu_si256((reinterpret_cast(src)) + 0); + c1 = _mm256_loadu_si256((reinterpret_cast(src)) + 1); + c2 = _mm256_loadu_si256((reinterpret_cast(src)) + 2); + c3 = _mm256_loadu_si256((reinterpret_cast(src)) + 3); + c4 = _mm256_loadu_si256((reinterpret_cast(src)) + 4); + c5 = _mm256_loadu_si256((reinterpret_cast(src)) + 5); + c6 = _mm256_loadu_si256((reinterpret_cast(src)) + 6); + c7 = _mm256_loadu_si256((reinterpret_cast(src)) + 7); + src += 256; + _mm256_store_si256(((reinterpret_cast<__m256i*>(dst)) + 0), c0); + _mm256_store_si256(((reinterpret_cast<__m256i*>(dst)) + 1), c1); + _mm256_store_si256(((reinterpret_cast<__m256i*>(dst)) + 2), c2); + _mm256_store_si256(((reinterpret_cast<__m256i*>(dst)) + 3), c3); + _mm256_store_si256(((reinterpret_cast<__m256i*>(dst)) + 4), c4); + _mm256_store_si256(((reinterpret_cast<__m256i*>(dst)) + 5), c5); + _mm256_store_si256(((reinterpret_cast<__m256i*>(dst)) + 6), c6); + _mm256_store_si256(((reinterpret_cast<__m256i*>(dst)) + 7), c7); + dst += 256; + + size -= 256; + } +} + +bool have_avx = true; + +static uint8_t * memcpy_my(uint8_t * __restrict dst, const uint8_t * __restrict src, size_t size) +{ + uint8_t * ret = dst; + +tail: + if (size <= 16) + { + if (size >= 8) + { + __builtin_memcpy(dst + size - 8, src + size - 8, 8); + __builtin_memcpy(dst, src, 8); + } + else if (size >= 4) + { + __builtin_memcpy(dst + size - 4, src + size - 4, 4); + __builtin_memcpy(dst, src, 4); + } + else if (size >= 2) + { + __builtin_memcpy(dst + size - 2, src + size - 2, 2); + __builtin_memcpy(dst, src, 2); + } + else if (size >= 1) + { + *dst = *src; + } + } + else if (have_avx) + { + if (size <= 32) + { + __builtin_memcpy(dst, src, 8); + __builtin_memcpy(dst + 8, src + 8, 8); + + dst += 16; + src += 16; + size -= 16; + + goto tail; + } + + if (size <= 256) + { + __asm__( + "vmovups -0x20(%[s],%[size],1), %%ymm0\n" + "vmovups %%ymm0, -0x20(%[d],%[size],1)\n" + : [d]"+r"(dst), [s]"+r"(src) + : [size]"r"(size) + : "ymm0", "memory"); + + while (size > 32) + { + __asm__( + "vmovups (%[s]), %%ymm0\n" + "vmovups %%ymm0, (%[d])\n" + : [d]"+r"(dst), [s]"+r"(src) + : + : "ymm0", "memory"); + + dst += 32; + src += 32; + size -= 32; + } + } + else + { + size_t padding = (32 - (reinterpret_cast(dst) & 31)) & 31; + + if (padding > 0) + { + __asm__( + "vmovups (%[s]), %%ymm0\n" + "vmovups %%ymm0, (%[d])\n" + : [d]"+r"(dst), [s]"+r"(src) + : + : "ymm0", "memory"); + + dst += padding; + src += padding; + size -= padding; + } + + while (size >= 256) + { + __asm__( + "vmovups (%[s]), %%ymm0\n" + "vmovups 0x20(%[s]), %%ymm1\n" + "vmovups 0x40(%[s]), %%ymm2\n" + "vmovups 0x60(%[s]), %%ymm3\n" + "vmovups 0x80(%[s]), %%ymm4\n" + "vmovups 0xa0(%[s]), %%ymm5\n" + "vmovups 0xc0(%[s]), %%ymm6\n" + "vmovups 0xe0(%[s]), %%ymm7\n" + "add $0x100,%[s]\n" + "vmovaps %%ymm0, (%[d])\n" + "vmovaps %%ymm1, 0x20(%[d])\n" + "vmovaps %%ymm2, 0x40(%[d])\n" + "vmovaps %%ymm3, 0x60(%[d])\n" + "vmovaps %%ymm4, 0x80(%[d])\n" + "vmovaps %%ymm5, 0xa0(%[d])\n" + "vmovaps %%ymm6, 0xc0(%[d])\n" + "vmovaps %%ymm7, 0xe0(%[d])\n" + "add $0x100, %[d]\n" + : [d]"+r"(dst), [s]"+r"(src) + : + : "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "memory"); + + size -= 256; + } + + goto tail; + } + } + else + { + if (size <= 128) + { + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + size - 16), _mm_loadu_si128(reinterpret_cast(src + size - 16))); + + while (size > 16) + { + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), _mm_loadu_si128(reinterpret_cast(src))); + dst += 16; + src += 16; + size -= 16; + } + } + else + { + /// Align destination to 16 bytes boundary. + size_t padding = (16 - (reinterpret_cast(dst) & 15)) & 15; + + if (padding > 0) + { + __m128i head = _mm_loadu_si128(reinterpret_cast(src)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), head); + dst += padding; + src += padding; + size -= padding; + } + + /// Aligned unrolled copy. + __m128i c0, c1, c2, c3, c4, c5, c6, c7; + + while (size >= 128) + { + c0 = _mm_loadu_si128(reinterpret_cast(src) + 0); + c1 = _mm_loadu_si128(reinterpret_cast(src) + 1); + c2 = _mm_loadu_si128(reinterpret_cast(src) + 2); + c3 = _mm_loadu_si128(reinterpret_cast(src) + 3); + c4 = _mm_loadu_si128(reinterpret_cast(src) + 4); + c5 = _mm_loadu_si128(reinterpret_cast(src) + 5); + c6 = _mm_loadu_si128(reinterpret_cast(src) + 6); + c7 = _mm_loadu_si128(reinterpret_cast(src) + 7); + src += 128; + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 0), c0); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 1), c1); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 2), c2); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 3), c3); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 4), c4); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 5), c5); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 6), c6); + _mm_store_si128((reinterpret_cast<__m128i*>(dst) + 7), c7); + dst += 128; + + size -= 128; + } + + goto tail; + } + } + + return ret; +} + + +template +void dispatchMemcpyVariants(size_t memcpy_variant, uint8_t * dst, uint8_t * src, size_t size, size_t iterations, size_t num_threads, F && generator) +{ + memcpy_type memcpy_libc = reinterpret_cast(dlsym(RTLD_NEXT, "memcpy")); + + if (memcpy_variant == 1) + test(dst, src, size, iterations, num_threads, std::forward(generator), memcpy); + if (memcpy_variant == 2) + test(dst, src, size, iterations, num_threads, std::forward(generator), memcpy_libc); + if (memcpy_variant == 3) + test(dst, src, size, iterations, num_threads, std::forward(generator), memcpy_erms); + if (memcpy_variant == 4) + test(dst, src, size, iterations, num_threads, std::forward(generator), MemCpy); + if (memcpy_variant == 5) + test(dst, src, size, iterations, num_threads, std::forward(generator), memcpySSE2); + if (memcpy_variant == 6) + test(dst, src, size, iterations, num_threads, std::forward(generator), memcpySSE2Unrolled2); + if (memcpy_variant == 7) + test(dst, src, size, iterations, num_threads, std::forward(generator), memcpySSE2Unrolled4); + if (memcpy_variant == 8) + test(dst, src, size, iterations, num_threads, std::forward(generator), memcpySSE2Unrolled8); +// if (memcpy_variant == 9) +// test(dst, src, size, iterations, num_threads, std::forward(generator), memcpy_fast_avx); + if (memcpy_variant == 10) + test(dst, src, size, iterations, num_threads, std::forward(generator), memcpy_my); +} + +void dispatchVariants(size_t memcpy_variant, size_t generator_variant, uint8_t * dst, uint8_t * src, size_t size, size_t iterations, size_t num_threads) +{ + if (generator_variant == 1) + dispatchMemcpyVariants(memcpy_variant, dst, src, size, iterations, num_threads, generatorUniform<16>); + if (generator_variant == 2) + dispatchMemcpyVariants(memcpy_variant, dst, src, size, iterations, num_threads, generatorUniform<256>); + if (generator_variant == 3) + dispatchMemcpyVariants(memcpy_variant, dst, src, size, iterations, num_threads, generatorUniform<4096>); + if (generator_variant == 4) + dispatchMemcpyVariants(memcpy_variant, dst, src, size, iterations, num_threads, generatorUniform<65536>); + if (generator_variant == 5) + dispatchMemcpyVariants(memcpy_variant, dst, src, size, iterations, num_threads, generatorUniform<1048576>); +} + + +int main(int argc, char ** argv) +{ + size_t size = 1000000000; + if (argc >= 2) + size = std::stoull(argv[1]); + + size_t iterations = 10; + if (argc >= 3) + iterations = std::stoull(argv[2]); + + size_t num_threads = 1; + if (argc >= 4) + num_threads = std::stoull(argv[3]); + + size_t memcpy_variant = 1; + if (argc >= 5) + memcpy_variant = std::stoull(argv[4]); + + size_t generator_variant = 1; + if (argc >= 6) + generator_variant = std::stoull(argv[5]); + + std::unique_ptr src(new uint8_t[size]); + std::unique_ptr dst(new uint8_t[size]); + + /// Fill src with some pattern for validation. + for (size_t i = 0; i < size; ++i) + src[i] = i; + + /// Fill dst to avoid page faults. + memset(dst.get(), 0, size); + + dispatchVariants(memcpy_variant, generator_variant, dst.get(), src.get(), size, iterations, num_threads); + + return 0; +} diff --git a/utils/memcpy-bench/memcpy_jart.S b/utils/memcpy-bench/memcpy_jart.S new file mode 100644 index 00000000000..50430d0abe0 --- /dev/null +++ b/utils/memcpy-bench/memcpy_jart.S @@ -0,0 +1,138 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ + +// Copies memory. +// +// DEST and SRC must not overlap, unless DEST≤SRC. +// +// @param rdi is dest +// @param rsi is src +// @param rdx is number of bytes +// @return original rdi copied to rax +// @mode long +// @asyncsignalsafe +memcpy_jart: mov %rdi,%rax +// 𝑠𝑙𝑖𝑑𝑒 + .align 16 + .type memcpy_jart,@function + .size memcpy_jart,.-memcpy_jart + .globl memcpy_jart + +// Copies memory w/ minimal impact ABI. +// +// @param rdi is dest +// @param rsi is src +// @param rdx is number of bytes +// @clob flags,rcx,xmm3,xmm4 +// @mode long +MemCpy: mov $.Lmemcpytab.size,%ecx + cmp %rcx,%rdx + cmovb %rdx,%rcx + jmp *memcpytab(,%rcx,8) +.Lanchorpoint: +.L16r: cmp $1024,%rdx + jae .Lerms +.L16: movdqu -16(%rsi,%rdx),%xmm4 + mov $16,%rcx +0: add $16,%rcx + movdqu -32(%rsi,%rcx),%xmm3 + movdqu %xmm3,-32(%rdi,%rcx) + cmp %rcx,%rdx + ja 0b + movdqu %xmm4,-16(%rdi,%rdx) + pxor %xmm4,%xmm4 + pxor %xmm3,%xmm3 + jmp .L0 +.L8: push %rbx + mov (%rsi),%rcx + mov -8(%rsi,%rdx),%rbx + mov %rcx,(%rdi) + mov %rbx,-8(%rdi,%rdx) +1: pop %rbx +.L0: ret +.L4: push %rbx + mov (%rsi),%ecx + mov -4(%rsi,%rdx),%ebx + mov %ecx,(%rdi) + mov %ebx,-4(%rdi,%rdx) + jmp 1b +.L3: push %rbx + mov (%rsi),%cx + mov -2(%rsi,%rdx),%bx + mov %cx,(%rdi) + mov %bx,-2(%rdi,%rdx) + jmp 1b +.L2: mov (%rsi),%cx + mov %cx,(%rdi) + jmp .L0 +.L1: mov (%rsi),%cl + mov %cl,(%rdi) + jmp .L0 +.Lerms: cmp $1024*1024,%rdx + ja .Lnts + push %rdi + push %rsi + mov %rdx,%rcx + rep movsb + pop %rsi + pop %rdi + jmp .L0 +.Lnts: movdqu (%rsi),%xmm3 + movdqu %xmm3,(%rdi) + lea 16(%rdi),%rcx + and $-16,%rcx + sub %rdi,%rcx + add %rcx,%rdi + add %rcx,%rsi + sub %rcx,%rdx + mov $16,%rcx +0: add $16,%rcx + movdqu -32(%rsi,%rcx),%xmm3 + movntdq %xmm3,-32(%rdi,%rcx) + cmp %rcx,%rdx + ja 0b + sfence + movdqu -16(%rsi,%rdx),%xmm3 + movdqu %xmm3,-16(%rdi,%rdx) + pxor %xmm3,%xmm3 + jmp .L0 + .type MemCpy,@function + .size MemCpy,.-MemCpy + .globl MemCpy + + .section .rodata + .align 8 +memcpytab: + .quad .L0 + .quad .L1 + .quad .L2 + .quad .L3 + .rept 4 + .quad .L4 + .endr + .rept 8 + .quad .L8 + .endr + .rept 16 + .quad .L16 + .endr + .equ .Lmemcpytab.size,(.-memcpytab)/8 + .quad .L16r # SSE + ERMS + NTS + .type memcpytab,@object + .previous diff --git a/utils/simple-backport/changelog.sh b/utils/simple-backport/changelog.sh index d3d9714cb04..ca2dcfffff0 100755 --- a/utils/simple-backport/changelog.sh +++ b/utils/simple-backport/changelog.sh @@ -39,7 +39,7 @@ function github_download() local file=${2} if ! [ -f "$file" ] then - if ! curl -H "Authorization: token $GITHUB_TOKEN" \ + if ! curl -u "$GITHUB_USER:$GITHUB_TOKEN" \ -sSf "$url" \ > "$file" then diff --git a/website/benchmark/hardware/index.html b/website/benchmark/hardware/index.html index 6e6664af55a..92da6328f0f 100644 --- a/website/benchmark/hardware/index.html +++ b/website/benchmark/hardware/index.html @@ -73,7 +73,8 @@ Results for Digital Ocean are from Zimin Aleksey.
Results for 2x EPYC 7642 w/ 512 GB RAM (192 Cores) + 12X 1TB SSD (RAID6) are from Yiğit Konur and Metehan Çetinkaya of seo.do.
Results for Raspberry Pi and Digital Ocean CPU-optimized are from Fritz Wijaya.
Results for Digitalocean (Storage-intesinve VMs) + (CPU/GP) are from Yiğit Konur and Metehan Çetinkaya of seo.do.
-Results for 2x AMD EPYC 7F72 3.2 Ghz (Total 96 Cores, IBM Cloud's Bare Metal Service) from Yiğit Konur and Metehan Çetinkaya of seo.do. +Results for 2x AMD EPYC 7F72 3.2 Ghz (Total 96 Cores, IBM Cloud's Bare Metal Service) from Yiğit Konur and Metehan Çetinkaya of seo.do.
+Results for 2x AMD EPYC 7742 (128 physical cores, 1 TB DDR4-3200 RAM) from Yedige Davletgaliyev and Nikita Zhavoronkov of blockchair.com.

diff --git a/website/benchmark/hardware/results/amd_epyc_7742.json b/website/benchmark/hardware/results/amd_epyc_7742.json new file mode 100644 index 00000000000..61b76d9e37b --- /dev/null +++ b/website/benchmark/hardware/results/amd_epyc_7742.json @@ -0,0 +1,54 @@ +[ + { + "system": "AMD EPYC 7742", + "system_full": "AMD EPYC 7742, 256 cores, 1 TiB Samsung 16x64GB DDR4-3200 ECC, 2 * Samsung PM1725b 12.8TB (RAID 0)", + "time": "2021-02-23 00:00:00", + "kind": "server", + "result": + [ +[0.001, 0.001, 0.001], +[0.075, 0.080, 0.015], +[0.030, 0.029, 0.025], +[0.052, 0.027, 0.028], +[0.141, 0.104, 0.105], +[0.180, 0.127, 0.129], +[0.023, 0.018, 0.017], +[0.018, 0.016, 0.016], +[0.135, 0.097, 0.096], +[0.146, 0.109, 0.108], +[0.106, 0.070, 0.069], +[0.105, 0.068, 0.070], +[0.180, 0.137, 0.136], +[0.216, 0.171, 0.175], +[0.193, 0.160, 0.156], +[0.148, 0.123, 0.132], +[0.364, 0.317, 0.317], +[0.276, 0.245, 0.240], +[0.636, 0.562, 0.615], +[0.070, 0.018, 0.015], +[0.576, 0.131, 0.125], +[0.595, 0.124, 0.121], +[0.861, 0.596, 0.610], +[1.172, 0.262, 0.276], +[0.152, 0.054, 0.050], +[0.114, 0.046, 0.046], +[0.149, 0.052, 0.051], +[0.536, 0.288, 0.306], +[0.587, 0.207, 0.217], +[0.436, 0.419, 0.406], +[0.178, 0.110, 0.113], +[0.337, 0.165, 0.162], +[1.072, 0.855, 0.882], +[0.908, 0.600, 0.612], +[0.904, 0.604, 0.629], +[0.223, 0.207, 0.216], +[0.151, 0.143, 0.172], +[0.063, 0.061, 0.060], +[0.059, 0.053, 0.054], +[0.321, 0.318, 0.321], +[0.026, 0.021, 0.020], +[0.018, 0.015, 0.016], +[0.005, 0.005, 0.004] + ] + } +] diff --git a/website/blog/en/2021/fuzzing-clickhouse.md b/website/blog/en/2021/fuzzing-clickhouse.md new file mode 100644 index 00000000000..b6852dcce15 --- /dev/null +++ b/website/blog/en/2021/fuzzing-clickhouse.md @@ -0,0 +1,61 @@ +--- +title: 'Fuzzing ClickHouse' +image: 'https://blog-images.clickhouse.tech/en/2021/fuzzing-clickhouse/some-checks-were-not-successful.png' +date: '2021-03-11' +author: '[Alexander Kuzmenkov](https://github.com/akuzm)' +tags: ['fuzzing', 'testing'] +--- + +Testing is a major problem in software development: there is never enough of it. It becomes especially true for a database management system, whose task is to interpret a query language that works on the persistent state managed by the system in a distributed fashion. Each of these three functions is hard enough to test even in isolation, and it gets much worse when you combine them. As ClickHouse developers, we know this from experience. Despite a large amount of automated testing of all kinds we routinely perform as part of our continuous integration system, new bugs and regressions are creeping in. We are always looking for the ways to improve our test coverage, and this article will describe our recent development in this area — the AST-based query fuzzer. + +## How to Test a SQL DBMS + +A natural form of testing for a SQL DBMS is to create a SQL script describing the test case, and record its reference result. To test, we run the script and check that the result matches the reference. This is used in many SQL DBMS, and it is the default kind of a test you are expected to write for any ClickHouse feature or fix. Currently we have [73k lines of SQL tests alone](https://github.com/ClickHouse/ClickHouse/tree/master/tests/queries/0_stateless), that reach the [code coverage of 76%](https://clickhouse-test-reports.s3.yandex.net/0/47d684a5c35410201d4dd4f63f3287bf25cdabb7/coverage_report/test_output/index.html). + +This form of testing, where a developer writes a few simplified examples of how the feature can and cannot be used, is sometimes called "example-based testing". Sadly, the bugs often appear in various corner cases and intersections of features, and it is not practical to enumerate all of these cases by hand. There is a technique for automating this process, called "property-based testing". It lets you write more general tests of the form "for all values matching these specs, the result of some operation on them should match this other spec". For example, such a test can check that if you add two positive numbers, the result is greater than both of them. But you don't specify which numbers exactly, only these properties. Then, the property testing system randomly generates some examples with particular numbers that match the specification, and checks that the result also matches its specification. + +Property-based testing is said to be very efficient, but requires some developer effort and expertise to write the tests in a special way. There is another well-known testing technique that is in some sense a corner case of property-based testing, and that doesn't require much developer time. It is called fuzzing. When you are fuzzing your program, you feed it random inputs generated according to some grammar, and the property you are checking is that your program terminates correctly (no segfaults or assertions or other kinds of program errors). Most often, the grammar of input for fuzzing is simple — say, bit flips and additions, or maybe some dictionary. The space of possible inputs is huge, so to find interesting paths in it, fuzzing software records the code paths taken by the program under test for a particular input, and focuses on the inputs that lead to new code paths that were not seen before. It also employs some techniques for finding interesting constant values, and so on. In general, fuzzing allows you to find many interesting corner cases in your program automatically, without much developer involvement. + +Generating valid SQL queries with bit flips would take a long time, so there are systems that generate queries based on the SQL grammar, such as [SQLSmith](https://github.com/anse1/sqlsmith). They are succesfully used for finding bugs in databases. It would be interesting to use such a system for ClickHouse, but it requires some up-front effort to support the ClickHouse SQL grammar and functions, which may be different from the standard. Also, such systems don't use any feedback, so while they are much better than systems with primitive grammar, they still might have a hard time finding interesting examples. But we already have a big corpus of human-written interesting SQL queries — it's in our regression tests. Maybe we can use them as a base for fuzzing? We tried to do this, and it turned out to be surprisingly simple and efficient. + +## AST-based Query Fuzzer + +Consider some SQL query from a regression test. After parsing, it is easy to mutate the resulting AST (abstract syntax tree, an internal representation of the parsed query) before execution to introduce random changes into the query. For strings and arrays, we make random modifications such as inserting a random character or doubling the string. For numbers, there are well-known Bad Numbers such as 0, 1, powers of two and nearby, integer limits, `NaN`. `NaN`s proved to be especially efficient in finding bugs, because you can often have some alternative branches in your numeric code, but for a `NaN`, both branches hold (or not) simultaneously, so this leads to nasty effects. + +Another interesting thing we can do is change the arguments of functions, or the list of expressions in `SELECT`, `ORDER BY` and so on. Naturally, all the interesting arguments can be taken from other test queries. Same goes for changing the tables used in the queries. When the fuzzer runs in CI, it runs queries from all the SQL tests in random order, mixing into them some parts of queries it has seen previously. This process can eventually cover all the possible permutations of our features. + +The core implementation of the fuzzer is relatively small, consisting of about 700 lines of C++ code. A prototype was made in a couple of days, but naturally it took significantly longer to polish it and to start routinely using it in CI. It is very productive and let us find more than 200 bugs already (see the label [fuzz](https://github.com/ClickHouse/ClickHouse/labels/fuzz) on GitHub), some of which are serious logic errors or even memory errors. When we only started, we could segfault the server or make it enter a never-ending loop with simplest read-only queries such as `SELECT arrayReverseFill(x -> (x < 10), [])` or `SELECT geoDistance(0., 0., -inf, 1.)`. Of course I couldn't resist bringing down our [public playground](https://gh-api.clickhouse.tech/play?user=play#LS0gWW91IGNhbiBxdWVyeSB0aGUgR2l0SHViIGhpc3RvcnkgZGF0YSBoZXJlLiBTZWUgaHR0cHM6Ly9naC5jbGlja2hvdXNlLnRlY2gvZXhwbG9yZXIvIGZvciB0aGUgZGVzY3JpcHRpb24gYW5kIGV4YW1wbGUgcXVlcmllcy4Kc2VsZWN0ICdoZWxsbyB3b3JsZCc=) with some of these queries, and was content to see that the server soon restarts correctly. These queries are actually minified by hand, normally the fuzzer would generate something barely intelligible such as: +``` +SELECT + (val + 257, + (((tuple(NULL), 10.000100135803223), tuple(-inf)), '-1', (NULL, '0.10', NULL), NULL), + (val + 9223372036854775807) = (rval * 100), + tuple(65535), tuple(NULL), NULL, NULL), + * +FROM +( + SELECT dummy AS val + FROM system.one +) AS s1 +ANY LEFT JOIN +( + SELECT toLowCardinality(toNullable(dummy)) AS rval + FROM system.one +) AS s2 ON (val + 100) = (rval * 7) +``` +In principle, we could add automated test case minification by modifying AST in the same vein with fuzzing. This is somewhat complicated by the fact that the server dies after every, excuse my pun, successfully failed query, so we didn't implement it yet. + +Not all errors the fuzzer finds are significant, some of them are pretty boring and harmless, such as a wrong error code for an out-of-bounds argument. We still try to fix all of them, because this lets us ensure that under normal operation, the fuzzer doesn't find any errors. This is similar to the approach usually taken with compiler warnings and other optional diagnostics — it's better to fix or disable every single case, so that you can be sure you have no diagnostics if everything is OK, and it's easy to notice new problems. + +After fixing the majority of pre-existing error, this fuzzer became efficient for finding errors in new features. Pull requests introducing new features normally add an SQL test, and we pay extra attention to the new tests when fuzzing, generating more permutations for them. Even if the coverage of the test is not sufficient, there is a good chance that the fuzzer will find the missing corner cases. So when we see that all the fuzzer runs in different configurations have failed for a particular pull request, this almost always means that it introduces a new bug. When developing a feature that requires new grammar, it is also helpful to add fuzzing support for it. I did this for window functions early in the development, and it helped me find several bugs. + +A major factor that makes fuzzing really efficient for us is that we have a lot of assertions and other checks of program logic in our code. For debug-only checks, we use the plain `assert` macro from ``. For checks that are needed even in release mode, we use an exception with a special code `LOGICAL_ERROR` that signifies an internal program error. We did some work to ensure that these errors are distinct from errors caused by the wrong user actions. A user error reported for a randomly generated query is normal (e.g. it references some non-existent columns), but when we see an internal program error, we know that it's definitely a bug, same as an assertion. Of course, even without assertions, you get some checks for memory errors provided by the OS (segfaults). Another way to add runtime checks to your program is to use some kind of sanitizer. We already run most of our tests under clang's Address, Memory, UndefinedBehavior and Thread sanitizers. Using them in conjunction with this fuzzer also proved to be very efficient. + +To see for yourself how the fuzzer works, you only need the normal ClickHouse client. Start `clickhouse-client --query-fuzzer-runs=100`, enter any query, and enjoy the client going crazy and running a hundred of random queries instead. All queries from the current session become a source for expressions for fuzzing, so try entering several different queries to get more interesting results. Be careful not to do this in production! When you do this experiment, you'll soon notice that the fuzzer tends to generate queries that take very long to run. This is why for the CI fuzzer runs we have to configure the server to limit query execution time, memory usage and so on using the corresponding [server settings](https://clickhouse.tech/docs/en/operations/settings/query-complexity/#:~:text=In%20the%20default%20configuration%20file,query%20within%20a%20single%20server.). We had a hilarious situation after that: the fuzzer figured out how to remove the limits by generating a `SET max_execution_time = 0` query, and then generated a never-ending query and failed. Thankfully we were able to defeat its cleverness by using [settings constraints](https://clickhouse.tech/docs/en/operations/settings/constraints-on-settings/). + +## Other Fuzzers + +The AST-based fuzzer we discussed is only one of the many kinds of fuzzers we have in ClickHouse. There is a [talk](https://www.youtube.com/watch?v=GbmK84ZwSeI&t=4481s) (in Russian, [slides are here](https://presentations.clickhouse.tech/cpp_siberia_2021/)) by Alexey Milovidov that explores all the fuzzers we have. Another interesting recent development is application of pivoted query synthesis technique, implemented in [SQLancer](https://github.com/sqlancer/sqlancer), to ClickHouse. The authors are going to give [a talk about this](https://heisenbug-piter.ru/2021/spb/talks/nr1cwknssdodjkqgzsbvh/) soon, so stay tuned. + +_2021-03-11 [Alexander Kuzmenkov](https://github.com/akuzm)_ +