mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 23:21:59 +00:00
Merge branch 'master' into replicated-merge-tree-s3
This commit is contained in:
commit
bc349a563a
55
dbms/src/IO/tests/gtest_s3_uri.cpp
Normal file
55
dbms/src/IO/tests/gtest_s3_uri.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <Common/config.h>
|
||||
|
||||
#if USE_AWS_S3
|
||||
|
||||
# include <IO/S3Common.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace DB;
|
||||
|
||||
class S3UriTest : public testing::TestWithParam<std::string>
|
||||
{
|
||||
};
|
||||
|
||||
TEST(S3UriTest, validPatterns)
|
||||
{
|
||||
{
|
||||
S3::URI uri(Poco::URI("https://jokserfn.s3.yandexcloud.net/data"));
|
||||
ASSERT_EQ("https://jokserfn.s3.yandexcloud.net", uri.endpoint);
|
||||
ASSERT_EQ("jokserfn", uri.bucket);
|
||||
ASSERT_EQ("data", uri.key);
|
||||
}
|
||||
{
|
||||
S3::URI uri(Poco::URI("https://storage.yandexcloud.net/jokserfn/data"));
|
||||
ASSERT_EQ("https://storage.yandexcloud.net", uri.endpoint);
|
||||
ASSERT_EQ("jokserfn", uri.bucket);
|
||||
ASSERT_EQ("data", uri.key);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(S3UriTest, invalidPatterns)
|
||||
{
|
||||
ASSERT_ANY_THROW(S3::URI(Poco::URI(GetParam())));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
S3,
|
||||
S3UriTest,
|
||||
testing::Values(
|
||||
"https:///",
|
||||
"https://jokserfn.s3.yandexcloud.net/",
|
||||
"https://.s3.yandexcloud.net/key",
|
||||
"https://s3.yandexcloud.net/key",
|
||||
"https://jokserfn.s3yandexcloud.net/key",
|
||||
"https://s3.yandexcloud.net/key/",
|
||||
"https://s3.yandexcloud.net//",
|
||||
"https://yandexcloud.net/",
|
||||
"https://yandexcloud.net//",
|
||||
"https://yandexcloud.net/bucket/",
|
||||
"https://yandexcloud.net//key"));
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -148,7 +148,7 @@ function run_tests
|
||||
|
||||
TIMEFORMAT=$(printf "$test_name\t%%3R\t%%3U\t%%3S\n")
|
||||
# the grep is to filter out set -x output and keep only time output
|
||||
{ time "$script_dir/perf.py" --host=localhost --port=9001 --host=localhost --port=9002 "$test" > "$test_name-raw.tsv" 2> "$test_name-err.log" ; } 2>&1 >/dev/null | grep -v ^+ >> "wall-clock-times.tsv" || continue
|
||||
{ time "$script_dir/perf.py" --host localhost localhost --port 9001 9002 -- "$test" > "$test_name-raw.tsv" 2> "$test_name-err.log" ; } 2>&1 >/dev/null | grep -v ^+ >> "wall-clock-times.tsv" || continue
|
||||
|
||||
# The test completed with zero status, so we treat stderr as warnings
|
||||
mv "$test_name-err.log" "$test_name-warn.log"
|
||||
|
@ -73,6 +73,7 @@ CMD dpkg -i package_folder/clickhouse-common-static_*.deb; \
|
||||
ln -s /usr/share/clickhouse-test/config/server.key /etc/clickhouse-server/; \
|
||||
ln -s /usr/share/clickhouse-test/config/server.crt /etc/clickhouse-server/; \
|
||||
ln -s /usr/share/clickhouse-test/config/dhparam.pem /etc/clickhouse-server/; \
|
||||
if [ -n $USE_POLYMORPHIC_PARTS ] && [ $USE_POLYMORPHIC_PARTS -eq 1 ]; then ln -s /usr/share/clickhouse-test/config/polymorphic_parts.xml /etc/clickhouse-server/config.d/; fi; \
|
||||
ln -sf /usr/share/clickhouse-test/config/client_config.xml /etc/clickhouse-client/config.xml; \
|
||||
service zookeeper start; sleep 5; \
|
||||
service clickhouse-server start && sleep 5 && clickhouse-test --testname --shard --zookeeper $ADDITIONAL_OPTIONS $SKIP_TESTS_OPTION 2>&1 | ts '%Y-%m-%d %H:%M:%S' | tee test_output/test_result.txt
|
||||
|
@ -42,6 +42,7 @@ ln -s /usr/share/clickhouse-test/config/zookeeper.xml /etc/clickhouse-server/con
|
||||
ln -s /usr/share/clickhouse-test/config/query_masking_rules.xml /etc/clickhouse-server/config.d/; \
|
||||
ln -s /usr/share/clickhouse-test/config/log_queries.xml /etc/clickhouse-server/users.d/; \
|
||||
ln -s /usr/share/clickhouse-test/config/readonly.xml /etc/clickhouse-server/users.d/; \
|
||||
ln -s /usr/share/clickhouse-test/config/access_management.xml /etc/clickhouse-server/users.d/; \
|
||||
ln -s /usr/share/clickhouse-test/config/ints_dictionary.xml /etc/clickhouse-server/; \
|
||||
ln -s /usr/share/clickhouse-test/config/strings_dictionary.xml /etc/clickhouse-server/; \
|
||||
ln -s /usr/share/clickhouse-test/config/decimals_dictionary.xml /etc/clickhouse-server/; \
|
||||
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
toc_title: Commercial
|
||||
toc_folder_title: Commercial
|
||||
toc_priority: 70
|
||||
---
|
||||
|
@ -9,7 +9,7 @@ With this instruction you can run basic ClickHouse performance test on any serve
|
||||
|
||||
1. Go to “commits” page: https://github.com/ClickHouse/ClickHouse/commits/master
|
||||
|
||||
2. Click on the first green check mark or red cross with green “ClickHouse Build Check” and click on the “Details” link near “ClickHouse Build Check”.
|
||||
2. Click on the first green check mark or red cross with green “ClickHouse Build Check” and click on the “Details” link near “ClickHouse Build Check”. There is no such link in some commits, for example commits with documentation. In this case, choose the nearest commit having this link.
|
||||
|
||||
3. Copy the link to “clickhouse” binary for amd64 or aarch64.
|
||||
|
||||
|
@ -839,32 +839,31 @@ If this query doesn’t return anything, it means that everything is fine.
|
||||
|
||||
## system.settings {#system-tables-system-settings}
|
||||
|
||||
Contains information about session settings for current user.
|
||||
Contains information about session settings for current user.
|
||||
|
||||
Columns:
|
||||
|
||||
- `name` ([String](../data_types/string.md)) — Setting name.
|
||||
- `value` ([String](../data_types/string.md)) — Setting value.
|
||||
- `changed` ([UInt8](../data_types/int_uint.md#uint-ranges)) — Shows whether a setting is changed from its default value.
|
||||
- `description` ([String](../data_types/string.md)) — Short setting description.
|
||||
- `min` ([Nullable](../data_types/nullable.md)([String](../data_types/string.md))) — Minimum value of the setting, if any is set via [constraints](settings/constraints_on_settings.md#constraints-on-settings). If the setting has no minimum value, contains [NULL](../query_language/syntax.md#null-literal).
|
||||
- `max` ([Nullable](../data_types/nullable.md)([String](../data_types/string.md))) — Maximum value of the setting, if any is set via [constraints](settings/constraints_on_settings.md#constraints-on-settings). If the setting has no maximum value, contains [NULL](../query_language/syntax.md#null-literal).
|
||||
- `readonly` ([UInt8](../data_types/int_uint.md#uint-ranges)) — Shows whether the current user can change the setting:
|
||||
- `0` — Current user can change the setting.
|
||||
- `1` — Current user can't change the setting.
|
||||
|
||||
- `name` ([String](../sql_reference/data_types/string.md)) — Setting name.
|
||||
- `value` ([String](../sql_reference/data_types/string.md)) — Setting value.
|
||||
- `changed` ([UInt8](../sql_reference/data_types/int_uint.md#uint-ranges)) — Shows whether a setting is changed from its default value.
|
||||
- `description` ([String](../sql_reference/data_types/string.md)) — Short setting description.
|
||||
- `min` ([Nullable](../sql_reference/data_types/nullable.md)([String](../sql_reference/data_types/string.md))) — Minimum value of the setting, if any is set via [constraints](settings/constraints_on_settings.md#constraints-on-settings). If the setting has no minimum value, contains [NULL](../sql_reference/syntax.md#null-literal).
|
||||
- `max` ([Nullable](../sql_reference/data_types/nullable.md)([String](../sql_reference/data_types/string.md))) — Maximum value of the setting, if any is set via [constraints](settings/constraints_on_settings.md#constraints-on-settings). If the setting has no maximum value, contains [NULL](../sql_reference/syntax.md#null-literal).
|
||||
- `readonly` ([UInt8](../sql_reference/data_types/int_uint.md#uint-ranges)) — Shows whether the current user can change the setting:
|
||||
- `0` — Current user can change the setting.
|
||||
- `1` — Current user can’t change the setting.
|
||||
|
||||
**Example**
|
||||
|
||||
The following example shows how to get information about settings which name contains `min_i`.
|
||||
|
||||
```sql
|
||||
``` sql
|
||||
SELECT *
|
||||
FROM system.settings
|
||||
WHERE name LIKE '%min_i%'
|
||||
```
|
||||
|
||||
```text
|
||||
``` text
|
||||
┌─name────────────────────────────────────────┬─value─────┬─changed─┬─description───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─min──┬─max──┬─readonly─┐
|
||||
│ min_insert_block_size_rows │ 1048576 │ 0 │ Squash blocks passed to INSERT query to specified size in rows, if blocks are not big enough. │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ 0 │
|
||||
│ min_insert_block_size_bytes │ 268435456 │ 0 │ Squash blocks passed to INSERT query to specified size in bytes, if blocks are not big enough. │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ 0 │
|
||||
@ -874,20 +873,23 @@ WHERE name LIKE '%min_i%'
|
||||
|
||||
Using of `WHERE changed` can be useful, for example, when you want to check:
|
||||
|
||||
- Whether settings in configuration files are loaded correctly and are in use.
|
||||
- Settings that changed in the current session.
|
||||
- Whether settings in configuration files are loaded correctly and are in use.
|
||||
- Settings that changed in the current session.
|
||||
|
||||
```sql
|
||||
<!-- -->
|
||||
|
||||
``` sql
|
||||
SELECT * FROM system.settings WHERE changed AND name='load_balancing'
|
||||
```
|
||||
|
||||
**See also**
|
||||
|
||||
- [Settings](settings/index.md#settings)
|
||||
- [Permissions for Queries](settings/permissions_for_queries.md#settings_readonly)
|
||||
- [Constraints on Settings](settings/constraints_on_settings.md)
|
||||
- [Settings](settings/index.md#settings)
|
||||
- [Permissions for Queries](settings/permissions_for_queries.md#settings_readonly)
|
||||
- [Constraints on Settings](settings/constraints_on_settings.md)
|
||||
|
||||
## system.table\_engines {#system.table_engines}
|
||||
|
||||
## system.table_engines
|
||||
``` text
|
||||
┌─name───────────────────┬─value───────┐
|
||||
│ max_threads │ 8 │
|
||||
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
en_copy: true
|
||||
---
|
||||
|
||||
../../../CHANGELOG.md
|
1
docs/ru/changelog/index.md
Symbolic link
1
docs/ru/changelog/index.md
Symbolic link
@ -0,0 +1 @@
|
||||
../../../CHANGELOG.md
|
@ -54,7 +54,7 @@ SELECT * FROM hdfs_engine_table LIMIT 2
|
||||
- `*` — Заменяет любое количество любых символов кроме `/`, включая отсутствие символов.
|
||||
- `?` — Заменяет ровно один любой символ.
|
||||
- `{some_string,another_string,yet_another_one}` — Заменяет любую из строк `'some_string', 'another_string', 'yet_another_one'`.
|
||||
- `{N..M}` — Заменяет любое число в интервале от `N` до `M` включительно.
|
||||
- `{N..M}` — Заменяет любое число в интервале от `N` до `M` включительно (может содержать ведущие нули).
|
||||
|
||||
Конструкция с `{}` аналогична табличной функции [remote](../../query_language/table_functions/remote.md).
|
||||
|
||||
|
@ -50,7 +50,7 @@ LIMIT 2
|
||||
- `*` — Заменяет любое количество любых символов кроме `/`, включая отсутствие символов.
|
||||
- `?` — Заменяет ровно один любой символ.
|
||||
- `{some_string,another_string,yet_another_one}` — Заменяет любую из строк `'some_string', 'another_string', 'yet_another_one'`.
|
||||
- `{N..M}` — Заменяет любое число в интервале от `N` до `M` включительно.
|
||||
- `{N..M}` — Заменяет любое число в интервале от `N` до `M` включительно (может содержать ведущие нули).
|
||||
|
||||
Конструкция с `{}` аналогична табличной функции [remote](remote.md).
|
||||
|
||||
|
@ -38,7 +38,7 @@ LIMIT 2
|
||||
- `*` — Заменяет любое количество любых символов кроме `/`, включая отсутствие символов.
|
||||
- `?` — Заменяет ровно один любой символ.
|
||||
- `{some_string,another_string,yet_another_one}` — Заменяет любую из строк `'some_string', 'another_string', 'yet_another_one'`.
|
||||
- `{N..M}` — Заменяет любое число в интервале от `N` до `M` включительно.
|
||||
- `{N..M}` — Заменяет любое число в интервале от `N` до `M` включительно (может содержать ведущие нули).
|
||||
|
||||
Конструкция с `{}` аналогична табличной функции [remote](remote.md).
|
||||
|
||||
|
@ -125,9 +125,9 @@ def sync_translation():
|
||||
lang_meta, lang_content = util.read_md_file(lang_src)
|
||||
en_meta.update(lang_meta)
|
||||
|
||||
for src, dst in redirects.items():
|
||||
lang_content = lang_content.replace('(' + src, '(' + dst)
|
||||
lang_content = lang_content.replace('../' + src, '../' + dst)
|
||||
for src_link, dst_link in redirects.items():
|
||||
lang_content = lang_content.replace('(' + src_link, '(' + dst)
|
||||
lang_content = lang_content.replace('../' + src_link, '../' + dst)
|
||||
|
||||
util.write_md_file(lang_dst, en_meta, lang_content)
|
||||
subprocess.check_call(f'git add {lang_dst}', shell=True)
|
||||
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
en_copy: true
|
||||
---
|
||||
|
||||
../../../CHANGELOG.md
|
1
docs/zh/changelog/index.md
Symbolic link
1
docs/zh/changelog/index.md
Symbolic link
@ -0,0 +1 @@
|
||||
../../../CHANGELOG.md
|
@ -62,7 +62,7 @@ Multiple path components can have globs. For being processed file should exists
|
||||
- `*` — Substitutes any number of any characters except `/` including empty string.
|
||||
- `?` — Substitutes any single character.
|
||||
- `{some_string,another_string,yet_another_one}` — Substitutes any of strings `'some_string', 'another_string', 'yet_another_one'`.
|
||||
- `{N..M}` — Substitutes any number in range from N to M including both borders.
|
||||
- `{N..M}` — Substitutes any number in range from N to M including both borders (could include leading zeros).
|
||||
|
||||
Constructions with `{}` are similar to the [remote](../../query_language/table_functions/remote.md) table function.
|
||||
|
||||
|
@ -61,7 +61,7 @@ Multiple path components can have globs. For being processed file should exists
|
||||
- `*` — Substitutes any number of any characters except `/` including empty string.
|
||||
- `?` — Substitutes any single character.
|
||||
- `{some_string,another_string,yet_another_one}` — Substitutes any of strings `'some_string', 'another_string', 'yet_another_one'`.
|
||||
- `{N..M}` — Substitutes any number in range from N to M including both borders.
|
||||
- `{N..M}` — Substitutes any number in range from N to M including both borders (could include leading zeros).
|
||||
|
||||
Constructions with `{}` are similar to the [remote table function](../../query_language/table_functions/remote.md)).
|
||||
|
||||
|
@ -44,7 +44,7 @@ Multiple path components can have globs. For being processed file should exists
|
||||
- `*` — Substitutes any number of any characters except `/` including empty string.
|
||||
- `?` — Substitutes any single character.
|
||||
- `{some_string,another_string,yet_another_one}` — Substitutes any of strings `'some_string', 'another_string', 'yet_another_one'`.
|
||||
- `{N..M}` — Substitutes any number in range from N to M including both borders.
|
||||
- `{N..M}` — Substitutes any number in range from N to M including both borders (could include leading zeros).
|
||||
|
||||
Constructions with `{}` are similar to the [remote table function](../../query_language/table_functions/remote.md)).
|
||||
|
||||
|
@ -128,6 +128,9 @@
|
||||
<!-- Directory with user provided files that are accessible by 'file' table function. -->
|
||||
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path>
|
||||
|
||||
<!-- Path to folder where users and roles created by SQL commands are stored. -->
|
||||
<access_control_path>/var/lib/clickhouse/access/</access_control_path>
|
||||
|
||||
<!-- Path to configuration file with users, access rights, profiles of settings, quotas. -->
|
||||
<users_config>users.xml</users_config>
|
||||
|
||||
|
@ -83,6 +83,9 @@
|
||||
|
||||
<!-- Quota for user. -->
|
||||
<quota>default</quota>
|
||||
|
||||
<!-- User can create other users and grant rights to them. -->
|
||||
<!-- <access_management>1</access_management> -->
|
||||
</default>
|
||||
</users>
|
||||
|
||||
|
@ -23,7 +23,10 @@ namespace
|
||||
std::vector<std::unique_ptr<IAccessStorage>> list;
|
||||
list.emplace_back(std::make_unique<DiskAccessStorage>());
|
||||
list.emplace_back(std::make_unique<UsersConfigAccessStorage>());
|
||||
|
||||
#if 0 /// Memory access storage is disabled.
|
||||
list.emplace_back(std::make_unique<MemoryAccessStorage>());
|
||||
#endif
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,19 @@
|
||||
#include <Common/Exception.h>
|
||||
#include <ext/range.h>
|
||||
#include <ext/push_back.h>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <bitset>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
/// Represents a combination of access types which can be granted globally, on databases, tables, columns, etc.
|
||||
/// For example "SELECT, CREATE USER" is an access type.
|
||||
class AccessFlags
|
||||
@ -175,9 +182,10 @@ public:
|
||||
const Flags & getDictionaryFlags() const { return all_flags_for_target[DICTIONARY]; }
|
||||
|
||||
private:
|
||||
enum Target
|
||||
enum NodeType
|
||||
{
|
||||
UNKNOWN_TARGET,
|
||||
UNKNOWN = -2,
|
||||
GROUP = -1,
|
||||
GLOBAL,
|
||||
DATABASE,
|
||||
TABLE,
|
||||
@ -186,46 +194,190 @@ private:
|
||||
DICTIONARY,
|
||||
};
|
||||
|
||||
static constexpr size_t NUM_TARGETS = static_cast<size_t>(DICTIONARY) + 1;
|
||||
|
||||
struct Node;
|
||||
using NodePtr = std::unique_ptr<Node>;
|
||||
using Nodes = std::vector<NodePtr>;
|
||||
|
||||
template <typename... Args>
|
||||
static Nodes nodes(Args&& ... args)
|
||||
{
|
||||
Nodes res;
|
||||
ext::push_back(res, std::move(args)...);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct Node
|
||||
{
|
||||
std::string_view keyword;
|
||||
std::vector<String> aliases;
|
||||
const String keyword;
|
||||
NodeType node_type;
|
||||
AccessType type = AccessType::NONE;
|
||||
Strings aliases;
|
||||
Flags flags;
|
||||
Target target = UNKNOWN_TARGET;
|
||||
Nodes children;
|
||||
std::vector<NodePtr> children;
|
||||
|
||||
Node(std::string_view keyword_, size_t flag_, Target target_)
|
||||
: keyword(keyword_), target(target_)
|
||||
Node(String keyword_, NodeType node_type_ = UNKNOWN) : keyword(std::move(keyword_)), node_type(node_type_) {}
|
||||
|
||||
void setFlag(size_t flag) { flags.set(flag); }
|
||||
|
||||
void addChild(NodePtr child)
|
||||
{
|
||||
flags.set(flag_);
|
||||
flags |= child->flags;
|
||||
children.push_back(std::move(child));
|
||||
}
|
||||
|
||||
Node(std::string_view keyword_, Nodes children_)
|
||||
: keyword(keyword_), children(std::move(children_))
|
||||
{
|
||||
for (const auto & child : children)
|
||||
flags |= child->flags;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Node(std::string_view keyword_, NodePtr first_child, Args &&... other_children)
|
||||
: Node(keyword_, nodes(std::move(first_child), std::move(other_children)...)) {}
|
||||
};
|
||||
|
||||
static String replaceUnderscoreWithSpace(const std::string_view & str)
|
||||
{
|
||||
String res{str};
|
||||
boost::replace_all(res, "_", " ");
|
||||
return res;
|
||||
}
|
||||
|
||||
static Strings splitAliases(const std::string_view & str)
|
||||
{
|
||||
Strings aliases;
|
||||
boost::split(aliases, str, boost::is_any_of(","));
|
||||
for (auto & alias : aliases)
|
||||
boost::trim(alias);
|
||||
return aliases;
|
||||
}
|
||||
|
||||
static void makeFlagsToKeywordTreeNode(
|
||||
AccessType type,
|
||||
const std::string_view & name,
|
||||
const std::string_view & aliases,
|
||||
NodeType node_type,
|
||||
const std::string_view & parent_group_name,
|
||||
std::unordered_map<std::string_view, Node *> & nodes,
|
||||
std::unordered_map<std::string_view, NodePtr> & owned_nodes,
|
||||
size_t & next_flag)
|
||||
{
|
||||
NodePtr node;
|
||||
auto keyword = replaceUnderscoreWithSpace(name);
|
||||
auto it = owned_nodes.find(keyword);
|
||||
if (it != owned_nodes.end())
|
||||
{
|
||||
node = std::move(it->second);
|
||||
owned_nodes.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nodes.contains(keyword))
|
||||
throw Exception(keyword + " declared twice", ErrorCodes::LOGICAL_ERROR);
|
||||
node = std::make_unique<Node>(keyword, node_type);
|
||||
nodes[node->keyword] = node.get();
|
||||
}
|
||||
|
||||
node->type = type;
|
||||
node->node_type = node_type;
|
||||
node->aliases = splitAliases(aliases);
|
||||
if (node_type != GROUP)
|
||||
node->setFlag(next_flag++);
|
||||
|
||||
bool has_parent_group = (parent_group_name != "NONE");
|
||||
if (!has_parent_group)
|
||||
{
|
||||
std::string_view keyword_as_string_view = node->keyword;
|
||||
owned_nodes[keyword_as_string_view] = std::move(node);
|
||||
return;
|
||||
}
|
||||
|
||||
auto parent_keyword = replaceUnderscoreWithSpace(parent_group_name);
|
||||
auto it_parent = nodes.find(parent_keyword);
|
||||
if (it_parent == nodes.end())
|
||||
{
|
||||
auto parent_node = std::make_unique<Node>(parent_keyword);
|
||||
it_parent = nodes.emplace(parent_node->keyword, parent_node.get()).first;
|
||||
assert(!owned_nodes.contains(parent_node->keyword));
|
||||
std::string_view parent_keyword_as_string_view = parent_node->keyword;
|
||||
owned_nodes[parent_keyword_as_string_view] = std::move(parent_node);
|
||||
}
|
||||
it_parent->second->addChild(std::move(node));
|
||||
}
|
||||
|
||||
void makeFlagsToKeywordTree()
|
||||
{
|
||||
std::unordered_map<std::string_view, NodePtr> owned_nodes;
|
||||
std::unordered_map<std::string_view, Node *> nodes;
|
||||
size_t next_flag = 0;
|
||||
|
||||
#define MAKE_ACCESS_FLAGS_TO_KEYWORD_TREE_NODE(name, aliases, node_type, parent_group_name) \
|
||||
makeFlagsToKeywordTreeNode(AccessType::name, #name, aliases, node_type, #parent_group_name, nodes, owned_nodes, next_flag);
|
||||
|
||||
APPLY_FOR_ACCESS_TYPES(MAKE_ACCESS_FLAGS_TO_KEYWORD_TREE_NODE)
|
||||
|
||||
#undef MAKE_ACCESS_FLAGS_TO_KEYWORD_TREE_NODE
|
||||
|
||||
if (!owned_nodes.contains("NONE"))
|
||||
throw Exception("'NONE' not declared", ErrorCodes::LOGICAL_ERROR);
|
||||
if (!owned_nodes.contains("ALL"))
|
||||
throw Exception("'ALL' not declared", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
flags_to_keyword_tree = std::move(owned_nodes["ALL"]);
|
||||
none_node = std::move(owned_nodes["NONE"]);
|
||||
owned_nodes.erase("ALL");
|
||||
owned_nodes.erase("NONE");
|
||||
|
||||
if (!owned_nodes.empty())
|
||||
{
|
||||
const auto & unused_node = *(owned_nodes.begin()->second);
|
||||
if (unused_node.node_type == UNKNOWN)
|
||||
throw Exception("Parent group '" + unused_node.keyword + "' not found", ErrorCodes::LOGICAL_ERROR);
|
||||
else
|
||||
throw Exception("Access type '" + unused_node.keyword + "' should have parent group", ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void makeKeywordToFlagsMap(Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
makeKeywordToFlagsMap(none_node.get());
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
}
|
||||
|
||||
start_node->aliases.emplace_back(start_node->keyword);
|
||||
for (auto & alias : start_node->aliases)
|
||||
{
|
||||
boost::to_upper(alias);
|
||||
keyword_to_flags_map[alias] = start_node->flags;
|
||||
}
|
||||
|
||||
for (auto & child : start_node->children)
|
||||
makeKeywordToFlagsMap(child.get());
|
||||
}
|
||||
|
||||
void makeAccessTypeToFlagsMapping(Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
makeAccessTypeToFlagsMapping(none_node.get());
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
}
|
||||
|
||||
size_t index = static_cast<size_t>(start_node->type);
|
||||
access_type_to_flags_mapping.resize(std::max(index + 1, access_type_to_flags_mapping.size()));
|
||||
access_type_to_flags_mapping[index] = start_node->flags;
|
||||
|
||||
for (auto & child : start_node->children)
|
||||
makeAccessTypeToFlagsMapping(child.get());
|
||||
}
|
||||
|
||||
void collectAllFlags(const Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
all_flags = start_node->flags;
|
||||
}
|
||||
if (start_node->node_type != GROUP)
|
||||
{
|
||||
assert(static_cast<size_t>(start_node->node_type) < std::size(all_flags_for_target));
|
||||
all_flags_for_target[start_node->node_type] |= start_node->flags;
|
||||
}
|
||||
for (const auto & child : start_node->children)
|
||||
collectAllFlags(child.get());
|
||||
}
|
||||
|
||||
Impl()
|
||||
{
|
||||
makeFlagsToKeywordTree();
|
||||
makeKeywordToFlagsMap();
|
||||
makeAccessTypeToFlagsMapping();
|
||||
collectAllFlags();
|
||||
}
|
||||
|
||||
static void flagsToKeywordsRec(const Flags & flags_, std::vector<std::string_view> & keywords, const Node & start_node)
|
||||
{
|
||||
Flags matching_flags = (flags_ & start_node.flags);
|
||||
@ -243,275 +395,12 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
static NodePtr makeFlagsToKeywordTree()
|
||||
{
|
||||
size_t next_flag = 0;
|
||||
Nodes all;
|
||||
|
||||
auto show_databases = std::make_unique<Node>("SHOW DATABASES", next_flag++, DATABASE);
|
||||
auto show_tables = std::make_unique<Node>("SHOW TABLES", next_flag++, TABLE);
|
||||
auto show_columns = std::make_unique<Node>("SHOW COLUMNS", next_flag++, COLUMN);
|
||||
auto show_dictionaries = std::make_unique<Node>("SHOW DICTIONARIES", next_flag++, DICTIONARY);
|
||||
auto show = std::make_unique<Node>("SHOW", std::move(show_databases), std::move(show_tables), std::move(show_columns), std::move(show_dictionaries));
|
||||
ext::push_back(all, std::move(show));
|
||||
|
||||
auto select = std::make_unique<Node>("SELECT", next_flag++, COLUMN);
|
||||
auto insert = std::make_unique<Node>("INSERT", next_flag++, COLUMN);
|
||||
ext::push_back(all, std::move(select), std::move(insert));
|
||||
|
||||
auto update = std::make_unique<Node>("UPDATE", next_flag++, COLUMN);
|
||||
ext::push_back(update->aliases, "ALTER UPDATE");
|
||||
auto delet = std::make_unique<Node>("DELETE", next_flag++, TABLE);
|
||||
ext::push_back(delet->aliases, "ALTER DELETE");
|
||||
|
||||
auto add_column = std::make_unique<Node>("ADD COLUMN", next_flag++, COLUMN);
|
||||
add_column->aliases.push_back("ALTER ADD COLUMN");
|
||||
auto modify_column = std::make_unique<Node>("MODIFY COLUMN", next_flag++, COLUMN);
|
||||
modify_column->aliases.push_back("ALTER MODIFY COLUMN");
|
||||
auto drop_column = std::make_unique<Node>("DROP COLUMN", next_flag++, COLUMN);
|
||||
drop_column->aliases.push_back("ALTER DROP COLUMN");
|
||||
auto comment_column = std::make_unique<Node>("COMMENT COLUMN", next_flag++, COLUMN);
|
||||
comment_column->aliases.push_back("ALTER COMMENT COLUMN");
|
||||
auto clear_column = std::make_unique<Node>("CLEAR COLUMN", next_flag++, COLUMN);
|
||||
clear_column->aliases.push_back("ALTER CLEAR COLUMN");
|
||||
auto rename_column = std::make_unique<Node>("RENAME COLUMN", next_flag++, COLUMN);
|
||||
rename_column->aliases.push_back("ALTER RENAME COLUMN");
|
||||
|
||||
auto alter_column = std::make_unique<Node>(
|
||||
"ALTER COLUMN",
|
||||
std::move(add_column),
|
||||
std::move(modify_column),
|
||||
std::move(drop_column),
|
||||
std::move(comment_column),
|
||||
std::move(clear_column),
|
||||
std::move(rename_column));
|
||||
|
||||
auto alter_order_by = std::make_unique<Node>("ALTER ORDER BY", next_flag++, TABLE);
|
||||
alter_order_by->aliases.push_back("MODIFY ORDER BY");
|
||||
alter_order_by->aliases.push_back("ALTER MODIFY ORDER BY");
|
||||
auto add_index = std::make_unique<Node>("ADD INDEX", next_flag++, TABLE);
|
||||
add_index->aliases.push_back("ALTER ADD INDEX");
|
||||
auto drop_index = std::make_unique<Node>("DROP INDEX", next_flag++, TABLE);
|
||||
drop_index->aliases.push_back("ALTER DROP INDEX");
|
||||
auto materialize_index = std::make_unique<Node>("MATERIALIZE INDEX", next_flag++, TABLE);
|
||||
materialize_index->aliases.push_back("ALTER MATERIALIZE INDEX");
|
||||
auto clear_index = std::make_unique<Node>("CLEAR INDEX", next_flag++, TABLE);
|
||||
clear_index->aliases.push_back("ALTER CLEAR INDEX");
|
||||
auto index = std::make_unique<Node>("INDEX", std::move(alter_order_by), std::move(add_index), std::move(drop_index), std::move(materialize_index), std::move(clear_index));
|
||||
index->aliases.push_back("ALTER INDEX");
|
||||
|
||||
auto add_constraint = std::make_unique<Node>("ADD CONSTRAINT", next_flag++, TABLE);
|
||||
add_constraint->aliases.push_back("ALTER ADD CONSTRAINT");
|
||||
auto drop_constraint = std::make_unique<Node>("DROP CONSTRAINT", next_flag++, TABLE);
|
||||
drop_constraint->aliases.push_back("ALTER DROP CONSTRAINT");
|
||||
auto alter_constraint = std::make_unique<Node>("CONSTRAINT", std::move(add_constraint), std::move(drop_constraint));
|
||||
alter_constraint->aliases.push_back("ALTER CONSTRAINT");
|
||||
|
||||
auto modify_ttl = std::make_unique<Node>("MODIFY TTL", next_flag++, TABLE);
|
||||
modify_ttl->aliases.push_back("ALTER MODIFY TTL");
|
||||
auto materialize_ttl = std::make_unique<Node>("MATERIALIZE TTL", next_flag++, TABLE);
|
||||
materialize_ttl->aliases.push_back("ALTER MATERIALIZE TTL");
|
||||
|
||||
auto modify_setting = std::make_unique<Node>("MODIFY SETTING", next_flag++, TABLE);
|
||||
modify_setting->aliases.push_back("ALTER MODIFY SETTING");
|
||||
|
||||
auto move_partition = std::make_unique<Node>("MOVE PARTITION", next_flag++, TABLE);
|
||||
ext::push_back(move_partition->aliases, "ALTER MOVE PARTITION", "MOVE PART", "ALTER MOVE PART");
|
||||
auto fetch_partition = std::make_unique<Node>("FETCH PARTITION", next_flag++, TABLE);
|
||||
ext::push_back(fetch_partition->aliases, "ALTER FETCH PARTITION");
|
||||
auto freeze_partition = std::make_unique<Node>("FREEZE PARTITION", next_flag++, TABLE);
|
||||
ext::push_back(freeze_partition->aliases, "ALTER FREEZE PARTITION");
|
||||
|
||||
auto alter_table = std::make_unique<Node>("ALTER TABLE", std::move(update), std::move(delet), std::move(alter_column), std::move(index), std::move(alter_constraint), std::move(modify_ttl), std::move(materialize_ttl), std::move(modify_setting), std::move(move_partition), std::move(fetch_partition), std::move(freeze_partition));
|
||||
|
||||
auto refresh_view = std::make_unique<Node>("REFRESH VIEW", next_flag++, VIEW);
|
||||
ext::push_back(refresh_view->aliases, "ALTER LIVE VIEW REFRESH");
|
||||
auto modify_view_query = std::make_unique<Node>("MODIFY VIEW QUERY", next_flag++, VIEW);
|
||||
auto alter_view = std::make_unique<Node>("ALTER VIEW", std::move(refresh_view), std::move(modify_view_query));
|
||||
|
||||
auto alter = std::make_unique<Node>("ALTER", std::move(alter_table), std::move(alter_view));
|
||||
ext::push_back(all, std::move(alter));
|
||||
|
||||
auto create_database = std::make_unique<Node>("CREATE DATABASE", next_flag++, DATABASE);
|
||||
auto create_table = std::make_unique<Node>("CREATE TABLE", next_flag++, TABLE);
|
||||
auto create_view = std::make_unique<Node>("CREATE VIEW", next_flag++, VIEW);
|
||||
auto create_dictionary = std::make_unique<Node>("CREATE DICTIONARY", next_flag++, DICTIONARY);
|
||||
auto create = std::make_unique<Node>("CREATE", std::move(create_database), std::move(create_table), std::move(create_view), std::move(create_dictionary));
|
||||
ext::push_back(all, std::move(create));
|
||||
|
||||
auto create_temporary_table = std::make_unique<Node>("CREATE TEMPORARY TABLE", next_flag++, GLOBAL);
|
||||
ext::push_back(all, std::move(create_temporary_table));
|
||||
|
||||
auto drop_database = std::make_unique<Node>("DROP DATABASE", next_flag++, DATABASE);
|
||||
auto drop_table = std::make_unique<Node>("DROP TABLE", next_flag++, TABLE);
|
||||
auto drop_view = std::make_unique<Node>("DROP VIEW", next_flag++, VIEW);
|
||||
auto drop_dictionary = std::make_unique<Node>("DROP DICTIONARY", next_flag++, DICTIONARY);
|
||||
auto drop = std::make_unique<Node>("DROP", std::move(drop_database), std::move(drop_table), std::move(drop_view), std::move(drop_dictionary));
|
||||
ext::push_back(all, std::move(drop));
|
||||
|
||||
auto truncate_table = std::make_unique<Node>("TRUNCATE TABLE", next_flag++, TABLE);
|
||||
auto truncate_view = std::make_unique<Node>("TRUNCATE VIEW", next_flag++, VIEW);
|
||||
auto truncate = std::make_unique<Node>("TRUNCATE", std::move(truncate_table), std::move(truncate_view));
|
||||
ext::push_back(all, std::move(truncate));
|
||||
|
||||
auto optimize = std::make_unique<Node>("OPTIMIZE", next_flag++, TABLE);
|
||||
optimize->aliases.push_back("OPTIMIZE TABLE");
|
||||
ext::push_back(all, std::move(optimize));
|
||||
|
||||
auto kill_query = std::make_unique<Node>("KILL QUERY", next_flag++, GLOBAL);
|
||||
ext::push_back(all, std::move(kill_query));
|
||||
|
||||
auto create_user = std::make_unique<Node>("CREATE USER", next_flag++, GLOBAL);
|
||||
auto alter_user = std::make_unique<Node>("ALTER USER", next_flag++, GLOBAL);
|
||||
auto drop_user = std::make_unique<Node>("DROP USER", next_flag++, GLOBAL);
|
||||
auto create_role = std::make_unique<Node>("CREATE ROLE", next_flag++, GLOBAL);
|
||||
auto alter_role = std::make_unique<Node>("ALTER ROLE", next_flag++, GLOBAL);
|
||||
auto drop_role = std::make_unique<Node>("DROP ROLE", next_flag++, GLOBAL);
|
||||
auto create_policy = std::make_unique<Node>("CREATE POLICY", next_flag++, GLOBAL);
|
||||
auto alter_policy = std::make_unique<Node>("ALTER POLICY", next_flag++, GLOBAL);
|
||||
auto drop_policy = std::make_unique<Node>("DROP POLICY", next_flag++, GLOBAL);
|
||||
auto create_quota = std::make_unique<Node>("CREATE QUOTA", next_flag++, GLOBAL);
|
||||
auto alter_quota = std::make_unique<Node>("ALTER QUOTA", next_flag++, GLOBAL);
|
||||
auto drop_quota = std::make_unique<Node>("DROP QUOTA", next_flag++, GLOBAL);
|
||||
auto create_profile = std::make_unique<Node>("CREATE SETTINGS PROFILE", next_flag++, GLOBAL);
|
||||
ext::push_back(create_profile->aliases, "CREATE PROFILE");
|
||||
auto alter_profile = std::make_unique<Node>("ALTER SETTINGS PROFILE", next_flag++, GLOBAL);
|
||||
ext::push_back(alter_profile->aliases, "ALTER PROFILE");
|
||||
auto drop_profile = std::make_unique<Node>("DROP SETTINGS PROFILE", next_flag++, GLOBAL);
|
||||
ext::push_back(drop_profile->aliases, "DROP PROFILE");
|
||||
auto role_admin = std::make_unique<Node>("ROLE ADMIN", next_flag++, GLOBAL);
|
||||
ext::push_back(all, std::move(create_user), std::move(alter_user), std::move(drop_user), std::move(create_role), std::move(alter_role), std::move(drop_role), std::move(create_policy), std::move(alter_policy), std::move(drop_policy), std::move(create_quota), std::move(alter_quota), std::move(drop_quota), std::move(create_profile), std::move(alter_profile), std::move(drop_profile), std::move(role_admin));
|
||||
|
||||
auto shutdown = std::make_unique<Node>("SHUTDOWN", next_flag++, GLOBAL);
|
||||
ext::push_back(shutdown->aliases, "SYSTEM SHUTDOWN", "SYSTEM KILL");
|
||||
auto drop_cache = std::make_unique<Node>("DROP CACHE", next_flag++, GLOBAL);
|
||||
ext::push_back(drop_cache->aliases, "SYSTEM DROP CACHE", "DROP DNS CACHE", "SYSTEM DROP DNS CACHE", "DROP MARK CACHE", "SYSTEM DROP MARK CACHE", "DROP UNCOMPRESSED CACHE", "SYSTEM DROP UNCOMPRESSED CACHE", "DROP COMPILED EXPRESSION CACHE", "SYSTEM DROP COMPILED EXPRESSION CACHE");
|
||||
auto reload_config = std::make_unique<Node>("RELOAD CONFIG", next_flag++, GLOBAL);
|
||||
ext::push_back(reload_config->aliases, "SYSTEM RELOAD CONFIG");
|
||||
auto reload_dictionary = std::make_unique<Node>("RELOAD DICTIONARY", next_flag++, GLOBAL);
|
||||
ext::push_back(reload_dictionary->aliases, "SYSTEM RELOAD DICTIONARY", "RELOAD DICTIONARIES", "SYSTEM RELOAD DICTIONARIES", "RELOAD EMBEDDED DICTIONARIES", "SYSTEM RELOAD EMBEDDED DICTIONARIES");
|
||||
auto stop_merges = std::make_unique<Node>("STOP MERGES", next_flag++, TABLE);
|
||||
ext::push_back(stop_merges->aliases, "SYSTEM STOP MERGES", "START MERGES", "SYSTEM START MERGES");
|
||||
auto stop_ttl_merges = std::make_unique<Node>("STOP TTL MERGES", next_flag++, TABLE);
|
||||
ext::push_back(stop_ttl_merges->aliases, "SYSTEM STOP TTL MERGES", "START TTL MERGES", "SYSTEM START TTL MERGES");
|
||||
auto stop_fetches = std::make_unique<Node>("STOP FETCHES", next_flag++, TABLE);
|
||||
ext::push_back(stop_fetches->aliases, "SYSTEM STOP FETCHES", "START FETCHES", "SYSTEM START FETCHES");
|
||||
auto stop_moves = std::make_unique<Node>("STOP MOVES", next_flag++, TABLE);
|
||||
ext::push_back(stop_moves->aliases, "SYSTEM STOP MOVES", "START MOVES", "SYSTEM START MOVES");
|
||||
auto stop_distributed_sends = std::make_unique<Node>("STOP DISTRIBUTED SENDS", next_flag++, TABLE);
|
||||
ext::push_back(stop_distributed_sends->aliases, "SYSTEM STOP DISTRIBUTED SENDS", "START DISTRIBUTED SENDS", "SYSTEM START DISTRIBUTED SENDS");
|
||||
auto stop_replicated_sends = std::make_unique<Node>("STOP REPLICATED SENDS", next_flag++, TABLE);
|
||||
ext::push_back(stop_replicated_sends->aliases, "SYSTEM STOP REPLICATED SENDS", "START REPLICATED SENDS", "SYSTEM START REPLICATED SENDS");
|
||||
auto stop_replication_queues = std::make_unique<Node>("STOP REPLICATION QUEUES", next_flag++, TABLE);
|
||||
ext::push_back(stop_replication_queues->aliases, "SYSTEM STOP REPLICATION QUEUES", "START REPLICATION QUEUES", "SYSTEM START REPLICATION QUEUES");
|
||||
auto sync_replica = std::make_unique<Node>("SYNC REPLICA", next_flag++, TABLE);
|
||||
ext::push_back(sync_replica->aliases, "SYSTEM SYNC REPLICA");
|
||||
auto restart_replica = std::make_unique<Node>("RESTART REPLICA", next_flag++, TABLE);
|
||||
ext::push_back(restart_replica->aliases, "SYSTEM RESTART REPLICA");
|
||||
auto flush_distributed = std::make_unique<Node>("FLUSH DISTRIBUTED", next_flag++, TABLE);
|
||||
ext::push_back(flush_distributed->aliases, "SYSTEM FLUSH DISTRIBUTED");
|
||||
auto flush_logs = std::make_unique<Node>("FLUSH LOGS", next_flag++, GLOBAL);
|
||||
ext::push_back(flush_logs->aliases, "SYSTEM FLUSH LOGS");
|
||||
auto system = std::make_unique<Node>("SYSTEM", std::move(shutdown), std::move(drop_cache), std::move(reload_config), std::move(reload_dictionary), std::move(stop_merges), std::move(stop_ttl_merges), std::move(stop_fetches), std::move(stop_moves), std::move(stop_distributed_sends), std::move(stop_replicated_sends), std::move(stop_replication_queues), std::move(sync_replica), std::move(restart_replica), std::move(flush_distributed), std::move(flush_logs));
|
||||
ext::push_back(all, std::move(system));
|
||||
|
||||
auto dict_get = std::make_unique<Node>("dictGet()", next_flag++, DICTIONARY);
|
||||
dict_get->aliases.push_back("dictHas()");
|
||||
dict_get->aliases.push_back("dictGetHierarchy()");
|
||||
dict_get->aliases.push_back("dictIsIn()");
|
||||
ext::push_back(all, std::move(dict_get));
|
||||
|
||||
auto address_to_line = std::make_unique<Node>("addressToLine()", next_flag++, GLOBAL);
|
||||
auto address_to_symbol = std::make_unique<Node>("addressToSymbol()", next_flag++, GLOBAL);
|
||||
auto demangle = std::make_unique<Node>("demangle()", next_flag++, GLOBAL);
|
||||
auto introspection = std::make_unique<Node>("INTROSPECTION", std::move(address_to_line), std::move(address_to_symbol), std::move(demangle));
|
||||
ext::push_back(introspection->aliases, "INTROSPECTION FUNCTIONS");
|
||||
ext::push_back(all, std::move(introspection));
|
||||
|
||||
auto file = std::make_unique<Node>("file()", next_flag++, GLOBAL);
|
||||
auto url = std::make_unique<Node>("url()", next_flag++, GLOBAL);
|
||||
auto input = std::make_unique<Node>("input()", next_flag++, GLOBAL);
|
||||
auto values = std::make_unique<Node>("values()", next_flag++, GLOBAL);
|
||||
auto numbers = std::make_unique<Node>("numbers()", next_flag++, GLOBAL);
|
||||
auto zeros = std::make_unique<Node>("zeros()", next_flag++, GLOBAL);
|
||||
auto merge = std::make_unique<Node>("merge()", next_flag++, DATABASE);
|
||||
auto remote = std::make_unique<Node>("remote()", next_flag++, GLOBAL);
|
||||
ext::push_back(remote->aliases, "remoteSecure()", "cluster()");
|
||||
auto mysql = std::make_unique<Node>("mysql()", next_flag++, GLOBAL);
|
||||
auto odbc = std::make_unique<Node>("odbc()", next_flag++, GLOBAL);
|
||||
auto jdbc = std::make_unique<Node>("jdbc()", next_flag++, GLOBAL);
|
||||
auto hdfs = std::make_unique<Node>("hdfs()", next_flag++, GLOBAL);
|
||||
auto s3 = std::make_unique<Node>("s3()", next_flag++, GLOBAL);
|
||||
auto table_functions = std::make_unique<Node>("TABLE FUNCTIONS", std::move(file), std::move(url), std::move(input), std::move(values), std::move(numbers), std::move(zeros), std::move(merge), std::move(remote), std::move(mysql), std::move(odbc), std::move(jdbc), std::move(hdfs), std::move(s3));
|
||||
ext::push_back(all, std::move(table_functions));
|
||||
|
||||
auto node_all = std::make_unique<Node>("ALL", std::move(all));
|
||||
node_all->aliases.push_back("ALL PRIVILEGES");
|
||||
return node_all;
|
||||
}
|
||||
|
||||
void makeKeywordToFlagsMap(Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
keyword_to_flags_map["USAGE"] = {};
|
||||
keyword_to_flags_map["NONE"] = {};
|
||||
keyword_to_flags_map["NO PRIVILEGES"] = {};
|
||||
}
|
||||
start_node->aliases.emplace_back(start_node->keyword);
|
||||
for (auto & alias : start_node->aliases)
|
||||
{
|
||||
boost::to_upper(alias);
|
||||
keyword_to_flags_map[alias] = start_node->flags;
|
||||
}
|
||||
for (auto & child : start_node->children)
|
||||
makeKeywordToFlagsMap(child.get());
|
||||
}
|
||||
|
||||
void makeAccessTypeToFlagsMapping()
|
||||
{
|
||||
access_type_to_flags_mapping.resize(MAX_ACCESS_TYPE);
|
||||
for (auto access_type : ext::range_with_static_cast<AccessType>(0, MAX_ACCESS_TYPE))
|
||||
{
|
||||
auto str = toKeyword(access_type);
|
||||
auto it = keyword_to_flags_map.find(str);
|
||||
if (it == keyword_to_flags_map.end())
|
||||
{
|
||||
String uppercased{str};
|
||||
boost::to_upper(uppercased);
|
||||
it = keyword_to_flags_map.find(uppercased);
|
||||
}
|
||||
access_type_to_flags_mapping[static_cast<size_t>(access_type)] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
void collectAllFlags(const Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
all_flags = start_node->flags;
|
||||
}
|
||||
if (start_node->target != UNKNOWN_TARGET)
|
||||
all_flags_for_target[start_node->target] |= start_node->flags;
|
||||
for (const auto & child : start_node->children)
|
||||
collectAllFlags(child.get());
|
||||
}
|
||||
|
||||
Impl()
|
||||
{
|
||||
flags_to_keyword_tree = makeFlagsToKeywordTree();
|
||||
makeKeywordToFlagsMap();
|
||||
makeAccessTypeToFlagsMapping();
|
||||
collectAllFlags();
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> flags_to_keyword_tree;
|
||||
NodePtr flags_to_keyword_tree;
|
||||
NodePtr none_node;
|
||||
std::unordered_map<std::string_view, Flags> keyword_to_flags_map;
|
||||
std::vector<Flags> access_type_to_flags_mapping;
|
||||
Flags all_flags;
|
||||
Flags all_flags_for_target[NUM_TARGETS];
|
||||
Flags all_flags_for_target[static_cast<size_t>(DICTIONARY) + 1];
|
||||
};
|
||||
|
||||
|
||||
|
@ -49,10 +49,13 @@ namespace
|
||||
const AccessFlags create_temporary_table_flag = AccessType::CREATE_TEMPORARY_TABLE;
|
||||
const AccessFlags alter_table_flag = AccessType::ALTER_TABLE;
|
||||
const AccessFlags alter_view_flag = AccessType::ALTER_VIEW;
|
||||
const AccessFlags truncate_table_flag = AccessType::TRUNCATE_TABLE;
|
||||
const AccessFlags truncate_view_flag = AccessType::TRUNCATE_VIEW;
|
||||
const AccessFlags truncate_flag = AccessType::TRUNCATE;
|
||||
const AccessFlags drop_table_flag = AccessType::DROP_TABLE;
|
||||
const AccessFlags drop_view_flag = AccessType::DROP_VIEW;
|
||||
const AccessFlags alter_ttl_flag = AccessType::ALTER_TTL;
|
||||
const AccessFlags alter_materialize_ttl_flag = AccessType::ALTER_MATERIALIZE_TTL;
|
||||
const AccessFlags system_reload_dictionary = AccessType::SYSTEM_RELOAD_DICTIONARY;
|
||||
const AccessFlags system_reload_embedded_dictionaries = AccessType::SYSTEM_RELOAD_EMBEDDED_DICTIONARIES;
|
||||
};
|
||||
|
||||
std::string_view checkCurrentDatabase(const std::string_view & current_database)
|
||||
@ -413,8 +416,14 @@ private:
|
||||
implicit_access |= helper.show_tables_flag;
|
||||
}
|
||||
|
||||
if ((level == GLOBAL_LEVEL) && ((access | max_access_among_children) & helper.create_table_flag))
|
||||
implicit_access |= helper.create_temporary_table_flag;
|
||||
if (level == GLOBAL_LEVEL)
|
||||
{
|
||||
if ((access | max_access_among_children) & helper.create_table_flag)
|
||||
implicit_access |= helper.create_temporary_table_flag;
|
||||
|
||||
if (access & helper.system_reload_dictionary)
|
||||
implicit_access |= helper.system_reload_embedded_dictionaries;
|
||||
}
|
||||
|
||||
if (level <= TABLE_LEVEL)
|
||||
{
|
||||
@ -427,8 +436,8 @@ private:
|
||||
if (access & helper.alter_table_flag)
|
||||
implicit_access |= helper.alter_view_flag;
|
||||
|
||||
if (access & helper.truncate_table_flag)
|
||||
implicit_access |= helper.truncate_view_flag;
|
||||
if (access & helper.alter_ttl_flag)
|
||||
implicit_access |= helper.alter_materialize_ttl_flag;
|
||||
}
|
||||
|
||||
final_access = access | implicit_access;
|
||||
|
@ -11,139 +11,162 @@ namespace DB
|
||||
/// Represents an access type which can be granted on databases, tables, columns, etc.
|
||||
enum class AccessType
|
||||
{
|
||||
NONE, /// no access
|
||||
ALL, /// full access
|
||||
/// Macro M should be defined as M(name, aliases, node_type, parent_group_name)
|
||||
/// where name is identifier with underscores (instead of spaces);
|
||||
/// aliases is a string containing comma-separated list;
|
||||
/// node_type either specifies access type's level (GLOBAL/DATABASE/TABLE/DICTIONARY/VIEW/COLUMNS),
|
||||
/// or specifies that the access type is a GROUP of other access types;
|
||||
/// parent_group_name is the name of the group containing this access type (or NONE if there is no such group).
|
||||
#define APPLY_FOR_ACCESS_TYPES(M) \
|
||||
M(SHOW_DATABASES, "", DATABASE, SHOW) /* allows to execute SHOW DATABASES, SHOW CREATE DATABASE, USE <database>;
|
||||
implicitly enabled by any grant on the database */\
|
||||
M(SHOW_TABLES, "", TABLE, SHOW) /* allows to execute SHOW TABLES, EXISTS <table>, CHECK <table>;
|
||||
implicitly enabled by any grant on the table */\
|
||||
M(SHOW_COLUMNS, "", COLUMN, SHOW) /* allows to execute SHOW CREATE TABLE, DESCRIBE;
|
||||
implicitly enabled with any grant on the column */\
|
||||
M(SHOW_DICTIONARIES, "", DICTIONARY, SHOW) /* allows to execute SHOW DICTIONARIES, SHOW CREATE DICTIONARY, EXISTS <dictionary>;
|
||||
implicitly enabled by any grant on the dictionary */\
|
||||
M(SHOW, "", GROUP, ALL) /* allows to execute SHOW, USE, EXISTS, CHECK, DESCRIBE */\
|
||||
\
|
||||
M(SELECT, "", COLUMN, ALL) \
|
||||
M(INSERT, "", COLUMN, ALL) \
|
||||
M(ALTER_UPDATE, "UPDATE", COLUMN, ALTER_TABLE) /* allows to execute ALTER UPDATE */\
|
||||
M(ALTER_DELETE, "DELETE", COLUMN, ALTER_TABLE) /* allows to execute ALTER DELETE */\
|
||||
\
|
||||
M(ALTER_ADD_COLUMN, "ADD COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_MODIFY_COLUMN, "MODIFY COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_DROP_COLUMN, "DROP COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_COMMENT_COLUMN, "COMMENT COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_CLEAR_COLUMN, "CLEAR COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_RENAME_COLUMN, "RENAME COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_COLUMN, "", GROUP, ALTER_TABLE) /* allow to execute ALTER {ADD|DROP|MODIFY...} COLUMN */\
|
||||
\
|
||||
M(ALTER_ORDER_BY, "ALTER MODIFY ORDER BY, MODIFY ORDER BY", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_ADD_INDEX, "ADD INDEX", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_DROP_INDEX, "DROP INDEX", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_MATERIALIZE_INDEX, "MATERIALIZE INDEX", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_CLEAR_INDEX, "CLEAR INDEX", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_INDEX, "INDEX", GROUP, ALTER_TABLE) /* allows to execute ALTER ORDER BY or ALTER {ADD|DROP...} INDEX */\
|
||||
\
|
||||
M(ALTER_ADD_CONSTRAINT, "ADD CONSTRAINT", TABLE, ALTER_CONSTRAINT) \
|
||||
M(ALTER_DROP_CONSTRAINT, "DROP CONSTRAINT", TABLE, ALTER_CONSTRAINT) \
|
||||
M(ALTER_CONSTRAINT, "CONSTRAINT", GROUP, ALTER_TABLE) /* allows to execute ALTER {ADD|DROP} CONSTRAINT */\
|
||||
\
|
||||
M(ALTER_TTL, "ALTER MODIFY TTL, MODIFY TTL", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY TTL */\
|
||||
M(ALTER_MATERIALIZE_TTL, "MATERIALIZE TTL", TABLE, ALTER_TABLE) /* allows to execute ALTER MATERIALIZE TTL;
|
||||
enabled implicitly by the grant ALTER_TABLE */\
|
||||
M(ALTER_SETTINGS, "ALTER SETTING, ALTER MODIFY SETTING, MODIFY SETTING", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY SETTING */\
|
||||
M(ALTER_MOVE_PARTITION, "ALTER MOVE PART, MOVE PARTITION, MOVE PART", TABLE, ALTER_TABLE) \
|
||||
M(ALTER_FETCH_PARTITION, "FETCH PARTITION", TABLE, ALTER_TABLE) \
|
||||
M(ALTER_FREEZE_PARTITION, "FREEZE PARTITION", TABLE, ALTER_TABLE) \
|
||||
\
|
||||
M(ALTER_TABLE, "", GROUP, ALTER) \
|
||||
\
|
||||
M(ALTER_VIEW_REFRESH, "ALTER LIVE VIEW REFRESH, REFRESH VIEW", VIEW, ALTER_VIEW) \
|
||||
M(ALTER_VIEW_MODIFY_QUERY, "ALTER TABLE MODIFY QUERY", VIEW, ALTER_VIEW) \
|
||||
M(ALTER_VIEW, "", GROUP, ALTER) /* allows to execute ALTER VIEW REFRESH, ALTER VIEW MODIFY QUERY;
|
||||
implicitly enabled by the grant ALTER_TABLE */\
|
||||
\
|
||||
M(ALTER, "", GROUP, ALL) /* allows to execute ALTER {TABLE|LIVE VIEW} */\
|
||||
\
|
||||
M(CREATE_DATABASE, "", DATABASE, CREATE) /* allows to execute {CREATE|ATTACH} DATABASE */\
|
||||
M(CREATE_TABLE, "", TABLE, CREATE) /* allows to execute {CREATE|ATTACH} {TABLE|VIEW} */\
|
||||
M(CREATE_VIEW, "", VIEW, CREATE) /* allows to execute {CREATE|ATTACH} VIEW;
|
||||
implicitly enabled by the grant CREATE_TABLE */\
|
||||
M(CREATE_DICTIONARY, "", DICTIONARY, CREATE) /* allows to execute {CREATE|ATTACH} DICTIONARY */\
|
||||
M(CREATE_TEMPORARY_TABLE, "", GLOBAL, CREATE) /* allows to create and manipulate temporary tables;
|
||||
implicitly enabled by the grant CREATE_TABLE on any table */ \
|
||||
M(CREATE, "", GROUP, ALL) /* allows to execute {CREATE|ATTACH} */ \
|
||||
\
|
||||
M(DROP_DATABASE, "", DATABASE, DROP) /* allows to execute {DROP|DETACH} DATABASE */\
|
||||
M(DROP_TABLE, "", TABLE, DROP) /* allows to execute {DROP|DETACH} TABLE */\
|
||||
M(DROP_VIEW, "", VIEW, DROP) /* allows to execute {DROP|DETACH} TABLE for views;
|
||||
implicitly enabled by the grant DROP_TABLE */\
|
||||
M(DROP_DICTIONARY, "", DICTIONARY, DROP) /* allows to execute {DROP|DETACH} DICTIONARY */\
|
||||
M(DROP, "", GROUP, ALL) /* allows to execute {DROP|DETACH} */\
|
||||
\
|
||||
M(TRUNCATE, "TRUNCATE TABLE", TABLE, ALL) \
|
||||
M(OPTIMIZE, "OPTIMIZE TABLE", TABLE, ALL) \
|
||||
\
|
||||
M(KILL_QUERY, "", GLOBAL, ALL) /* allows to kill a query started by another user
|
||||
(anyone can kill his own queries) */\
|
||||
\
|
||||
M(CREATE_USER, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_USER, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_USER, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(CREATE_ROLE, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_ROLE, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_ROLE, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ROLE_ADMIN, "", GLOBAL, ACCESS_MANAGEMENT) /* allows to grant and revoke the roles which are not granted to the current user with admin option */\
|
||||
M(CREATE_ROW_POLICY, "CREATE POLICY", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_ROW_POLICY, "ALTER POLICY", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_ROW_POLICY, "DROP POLICY", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(CREATE_QUOTA, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_QUOTA, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_QUOTA, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(CREATE_SETTINGS_PROFILE, "CREATE PROFILE", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_SETTINGS_PROFILE, "ALTER PROFILE", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_SETTINGS_PROFILE, "DROP PROFILE", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(SHOW_USERS, "SHOW CREATE USER", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_ROLES, "SHOW CREATE ROLE", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_ROW_POLICIES, "SHOW POLICIES, SHOW CREATE ROW POLICY, SHOW CREATE POLICY", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_QUOTAS, "SHOW CREATE QUOTA", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_SETTINGS_PROFILES, "SHOW PROFILES, SHOW CREATE SETTINGS PROFILE, SHOW CREATE PROFILE", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_ACCESS, "", GROUP, ACCESS_MANAGEMENT) \
|
||||
M(ACCESS_MANAGEMENT, "", GROUP, ALL) \
|
||||
\
|
||||
M(SYSTEM_SHUTDOWN, "SYSTEM KILL, SHUTDOWN", GLOBAL, SYSTEM) \
|
||||
M(SYSTEM_DROP_DNS_CACHE, "SYSTEM DROP DNS, DROP DNS CACHE, DROP DNS", GLOBAL, SYSTEM_DROP_CACHE) \
|
||||
M(SYSTEM_DROP_MARK_CACHE, "SYSTEM DROP MARK, DROP MARK CACHE, DROP MARKS", GLOBAL, SYSTEM_DROP_CACHE) \
|
||||
M(SYSTEM_DROP_UNCOMPRESSED_CACHE, "SYSTEM DROP UNCOMPRESSED, DROP UNCOMPRESSED CACHE, DROP UNCOMPRESSED", GLOBAL, SYSTEM_DROP_CACHE) \
|
||||
M(SYSTEM_DROP_COMPILED_EXPRESSION_CACHE, "SYSTEM DROP COMPILED EXPRESSION, DROP COMPILED EXPRESSION CACHE, DROP COMPILED EXPRESSIONS", GLOBAL, SYSTEM_DROP_CACHE) \
|
||||
M(SYSTEM_DROP_CACHE, "DROP CACHE", GROUP, SYSTEM) \
|
||||
M(SYSTEM_RELOAD_CONFIG, "RELOAD CONFIG", GLOBAL, SYSTEM_RELOAD) \
|
||||
M(SYSTEM_RELOAD_DICTIONARY, "SYSTEM RELOAD DICTIONARIES, RELOAD DICTIONARY, RELOAD DICTIONARIES", GLOBAL, SYSTEM_RELOAD) \
|
||||
M(SYSTEM_RELOAD_EMBEDDED_DICTIONARIES, "RELOAD EMBEDDED DICTIONARIES", GLOBAL, SYSTEM_RELOAD) /* implicitly enabled by the grant SYSTEM_RELOAD_DICTIONARY ON *.* */\
|
||||
M(SYSTEM_RELOAD, "", GROUP, SYSTEM) \
|
||||
M(SYSTEM_MERGES, "SYSTEM STOP MERGES, SYSTEM START MERGES, STOP_MERGES, START MERGES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_TTL_MERGES, "SYSTEM STOP TTL MERGES, SYSTEM START TTL MERGES, STOP TTL MERGES, START TTL MERGES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_FETCHES, "SYSTEM STOP FETCHES, SYSTEM START FETCHES, STOP FETCHES, START FETCHES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_MOVES, "SYSTEM STOP MOVES, SYSTEM START MOVES, STOP MOVES, START MOVES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_DISTRIBUTED_SENDS, "SYSTEM STOP DISTRIBUTED SENDS, SYSTEM START DISTRIBUTED SENDS, STOP DISTRIBUTED SENDS, START DISTRIBUTED SENDS", TABLE, SYSTEM_SENDS) \
|
||||
M(SYSTEM_REPLICATED_SENDS, "SYSTEM STOP REPLICATED SENDS, SYSTEM START REPLICATED SENDS, STOP_REPLICATED_SENDS, START REPLICATED SENDS", TABLE, SYSTEM_SENDS) \
|
||||
M(SYSTEM_SENDS, "SYSTEM STOP SENDS, SYSTEM START SENDS, STOP SENDS, START SENDS", GROUP, SYSTEM) \
|
||||
M(SYSTEM_REPLICATION_QUEUES, "SYSTEM STOP REPLICATION QUEUES, SYSTEM START REPLICATION QUEUES, STOP_REPLICATION_QUEUES, START REPLICATION QUEUES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_SYNC_REPLICA, "SYNC REPLICA", TABLE, SYSTEM) \
|
||||
M(SYSTEM_RESTART_REPLICA, "RESTART REPLICA", TABLE, SYSTEM) \
|
||||
M(SYSTEM_FLUSH_DISTRIBUTED, "FLUSH DISTRIBUTED", TABLE, SYSTEM_FLUSH) \
|
||||
M(SYSTEM_FLUSH_LOGS, "FLUSH LOGS", GLOBAL, SYSTEM_FLUSH) \
|
||||
M(SYSTEM_FLUSH, "", GROUP, SYSTEM) \
|
||||
M(SYSTEM, "", GROUP, ALL) /* allows to execute SYSTEM {SHUTDOWN|RELOAD CONFIG|...} */ \
|
||||
\
|
||||
M(dictGet, "dictHas, dictGetHierarchy, dictIsIn", DICTIONARY, ALL) /* allows to execute functions dictGet(), dictHas(), dictGetHierarchy(), dictIsIn() */\
|
||||
\
|
||||
M(addressToLine, "", GLOBAL, INTROSPECTION) /* allows to execute function addressToLine() */\
|
||||
M(addressToSymbol, "", GLOBAL, INTROSPECTION) /* allows to execute function addressToSymbol() */\
|
||||
M(demangle, "", GLOBAL, INTROSPECTION) /* allows to execute function demangle() */\
|
||||
M(INTROSPECTION, "INTROSPECTION FUNCTIONS", GROUP, ALL) /* allows to execute functions addressToLine(), addressToSymbol(), demangle()*/\
|
||||
\
|
||||
M(FILE, "", GLOBAL, SOURCES) \
|
||||
M(URL, "", GLOBAL, SOURCES) \
|
||||
M(REMOTE, "", GLOBAL, SOURCES) \
|
||||
M(MYSQL, "", GLOBAL, SOURCES) \
|
||||
M(ODBC, "", GLOBAL, SOURCES) \
|
||||
M(JDBC, "", GLOBAL, SOURCES) \
|
||||
M(HDFS, "", GLOBAL, SOURCES) \
|
||||
M(S3, "", GLOBAL, SOURCES) \
|
||||
M(SOURCES, "", GROUP, ALL) \
|
||||
\
|
||||
M(ALL, "ALL PRIVILEGES", GROUP, NONE) /* full access */ \
|
||||
M(NONE, "USAGE, NO PRIVILEGES", GROUP, NONE) /* no access */
|
||||
|
||||
SHOW_DATABASES, /// allows to execute SHOW DATABASES, SHOW CREATE DATABASE, USE <database>
|
||||
SHOW_TABLES, /// allows to execute SHOW TABLES, EXISTS <table>, CHECK <table>
|
||||
SHOW_COLUMNS, /// allows to execute SHOW CREATE TABLE, DESCRIBE
|
||||
SHOW_DICTIONARIES, /// allows to execute SHOW DICTIONARIES, SHOW CREATE DICTIONARY, EXISTS <dictionary>
|
||||
SHOW, /// allows to execute SHOW, USE, EXISTS, CHECK, DESCRIBE
|
||||
#define DECLARE_ACCESS_TYPE_ENUM_CONST(name, aliases, node_type, parent_group_name) \
|
||||
name,
|
||||
|
||||
SELECT,
|
||||
INSERT,
|
||||
UPDATE, /// allows to execute ALTER UPDATE
|
||||
DELETE, /// allows to execute ALTER DELETE
|
||||
|
||||
ADD_COLUMN,
|
||||
DROP_COLUMN,
|
||||
MODIFY_COLUMN,
|
||||
COMMENT_COLUMN,
|
||||
CLEAR_COLUMN,
|
||||
RENAME_COLUMN,
|
||||
ALTER_COLUMN, /// allow to execute ALTER {ADD|DROP|MODIFY...} COLUMN
|
||||
|
||||
ALTER_ORDER_BY,
|
||||
ADD_INDEX,
|
||||
DROP_INDEX,
|
||||
MATERIALIZE_INDEX,
|
||||
CLEAR_INDEX,
|
||||
INDEX, /// allows to execute ALTER ORDER BY or ALTER {ADD|DROP...} INDEX
|
||||
|
||||
ADD_CONSTRAINT,
|
||||
DROP_CONSTRAINT,
|
||||
ALTER_CONSTRAINT, /// allows to execute ALTER {ADD|DROP} CONSTRAINT
|
||||
|
||||
MODIFY_TTL, /// allows to execute ALTER MODIFY TTL
|
||||
MATERIALIZE_TTL, /// allows to execute ALTER MATERIALIZE TTL
|
||||
MODIFY_SETTING, /// allows to execute ALTER MODIFY SETTING
|
||||
|
||||
MOVE_PARTITION,
|
||||
FETCH_PARTITION,
|
||||
FREEZE_PARTITION,
|
||||
|
||||
ALTER_TABLE, /// allows to execute ALTER TABLE ...
|
||||
|
||||
REFRESH_VIEW, /// allows to execute ALTER LIVE VIEW REFRESH
|
||||
MODIFY_VIEW_QUERY, /// allows to execute ALTER TABLE MODIFY QUERY
|
||||
ALTER_VIEW, /// allows to execute ALTER LIVE VIEW REFRESH, ALTER TABLE MODIFY QUERY
|
||||
|
||||
ALTER, /// allows to execute ALTER {TABLE|LIVE VIEW} ...
|
||||
|
||||
CREATE_DATABASE, /// allows to execute {CREATE|ATTACH} DATABASE
|
||||
CREATE_TABLE, /// allows to execute {CREATE|ATTACH} TABLE
|
||||
CREATE_VIEW, /// allows to execute {CREATE|ATTACH} VIEW
|
||||
CREATE_DICTIONARY, /// allows to execute {CREATE|ATTACH} DICTIONARY
|
||||
CREATE_TEMPORARY_TABLE, /// allows to create and manipulate temporary tables and views.
|
||||
CREATE, /// allows to execute {CREATE|ATTACH} [TEMPORARY] {DATABASE|TABLE|VIEW|DICTIONARY}
|
||||
|
||||
DROP_DATABASE,
|
||||
DROP_TABLE,
|
||||
DROP_VIEW,
|
||||
DROP_DICTIONARY,
|
||||
DROP, /// allows to execute DROP {DATABASE|TABLE|VIEW|DICTIONARY}
|
||||
|
||||
TRUNCATE_TABLE,
|
||||
TRUNCATE_VIEW,
|
||||
TRUNCATE, /// allows to execute TRUNCATE {TABLE|VIEW}
|
||||
|
||||
OPTIMIZE, /// allows to execute OPTIMIZE TABLE
|
||||
|
||||
KILL_QUERY, /// allows to kill a query started by another user (anyone can kill his own queries)
|
||||
|
||||
CREATE_USER,
|
||||
ALTER_USER,
|
||||
DROP_USER,
|
||||
CREATE_ROLE,
|
||||
ALTER_ROLE,
|
||||
DROP_ROLE,
|
||||
CREATE_POLICY,
|
||||
ALTER_POLICY,
|
||||
DROP_POLICY,
|
||||
CREATE_QUOTA,
|
||||
ALTER_QUOTA,
|
||||
DROP_QUOTA,
|
||||
CREATE_SETTINGS_PROFILE,
|
||||
ALTER_SETTINGS_PROFILE,
|
||||
DROP_SETTINGS_PROFILE,
|
||||
|
||||
ROLE_ADMIN, /// allows to grant and revoke any roles.
|
||||
|
||||
SHUTDOWN,
|
||||
DROP_CACHE,
|
||||
RELOAD_CONFIG,
|
||||
RELOAD_DICTIONARY,
|
||||
STOP_MERGES,
|
||||
STOP_TTL_MERGES,
|
||||
STOP_FETCHES,
|
||||
STOP_MOVES,
|
||||
STOP_DISTRIBUTED_SENDS,
|
||||
STOP_REPLICATED_SENDS,
|
||||
STOP_REPLICATION_QUEUES,
|
||||
SYNC_REPLICA,
|
||||
RESTART_REPLICA,
|
||||
FLUSH_DISTRIBUTED,
|
||||
FLUSH_LOGS,
|
||||
SYSTEM, /// allows to execute SYSTEM {SHUTDOWN|RELOAD CONFIG|...}
|
||||
|
||||
dictGet, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
|
||||
dictHas, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
|
||||
dictGetHierarchy, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
|
||||
dictIsIn, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
|
||||
|
||||
addressToLine, /// allows to execute function addressToLine
|
||||
addressToSymbol, /// allows to execute function addressToSymbol
|
||||
demangle, /// allows to execute function demangle
|
||||
INTROSPECTION, /// allows to execute functions addressToLine, addressToSymbol, demangle
|
||||
|
||||
file,
|
||||
url,
|
||||
input,
|
||||
values,
|
||||
numbers,
|
||||
zeros,
|
||||
merge,
|
||||
remote,
|
||||
mysql,
|
||||
odbc,
|
||||
jdbc,
|
||||
hdfs,
|
||||
s3,
|
||||
TABLE_FUNCTIONS, /// allows to execute any table function
|
||||
APPLY_FOR_ACCESS_TYPES(DECLARE_ACCESS_TYPE_ENUM_CONST)
|
||||
#undef DECLARE_ACCESS_TYPE_ENUM_CONST
|
||||
};
|
||||
|
||||
constexpr size_t MAX_ACCESS_TYPE = static_cast<size_t>(AccessType::TABLE_FUNCTIONS) + 1;
|
||||
|
||||
std::string_view toString(AccessType type);
|
||||
|
||||
|
||||
@ -165,153 +188,26 @@ namespace impl
|
||||
}
|
||||
|
||||
private:
|
||||
void addToMapping(AccessType type, const std::string_view & str)
|
||||
AccessTypeToKeywordConverter()
|
||||
{
|
||||
#define INSERT_ACCESS_TYPE_KEYWORD_PAIR_TO_MAPPING(name, aliases, node_type, parent_group_name) \
|
||||
insertToMapping(AccessType::name, #name);
|
||||
|
||||
APPLY_FOR_ACCESS_TYPES(INSERT_ACCESS_TYPE_KEYWORD_PAIR_TO_MAPPING)
|
||||
|
||||
#undef INSERT_ACCESS_TYPE_KEYWORD_PAIR_TO_MAPPING
|
||||
}
|
||||
|
||||
void insertToMapping(AccessType type, const std::string_view & str)
|
||||
{
|
||||
String str2{str};
|
||||
boost::replace_all(str2, "_", " ");
|
||||
if (islower(str2[0]))
|
||||
str2 += "()";
|
||||
access_type_to_keyword_mapping[static_cast<size_t>(type)] = str2;
|
||||
size_t index = static_cast<size_t>(type);
|
||||
access_type_to_keyword_mapping.resize(std::max(index + 1, access_type_to_keyword_mapping.size()));
|
||||
access_type_to_keyword_mapping[index] = str2;
|
||||
}
|
||||
|
||||
AccessTypeToKeywordConverter()
|
||||
{
|
||||
#define ACCESS_TYPE_TO_KEYWORD_CASE(type) \
|
||||
addToMapping(AccessType::type, #type)
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(NONE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALL);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_DATABASES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_TABLES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_COLUMNS);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_DICTIONARIES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SELECT);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(INSERT);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(UPDATE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DELETE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ADD_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(COMMENT_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CLEAR_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(RENAME_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_COLUMN);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_ORDER_BY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ADD_INDEX);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_INDEX);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MATERIALIZE_INDEX);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CLEAR_INDEX);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(INDEX);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ADD_CONSTRAINT);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_CONSTRAINT);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_CONSTRAINT);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_TTL);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MATERIALIZE_TTL);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_SETTING);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MOVE_PARTITION);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(FETCH_PARTITION);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(FREEZE_PARTITION);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_TABLE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(REFRESH_VIEW);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_VIEW_QUERY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_VIEW);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_DATABASE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_TABLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_VIEW);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_DICTIONARY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_TEMPORARY_TABLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_DATABASE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_TABLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_VIEW);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_DICTIONARY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(TRUNCATE_TABLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(TRUNCATE_VIEW);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(TRUNCATE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(OPTIMIZE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(KILL_QUERY);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_USER);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_USER);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_USER);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_ROLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_ROLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_ROLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_POLICY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_POLICY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_POLICY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_QUOTA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_QUOTA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_QUOTA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_SETTINGS_PROFILE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_SETTINGS_PROFILE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_SETTINGS_PROFILE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ROLE_ADMIN);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHUTDOWN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_CACHE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(RELOAD_CONFIG);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(RELOAD_DICTIONARY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_MERGES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_TTL_MERGES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_FETCHES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_MOVES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_DISTRIBUTED_SENDS);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_REPLICATED_SENDS);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_REPLICATION_QUEUES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SYNC_REPLICA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(RESTART_REPLICA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(FLUSH_DISTRIBUTED);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(FLUSH_LOGS);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SYSTEM);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(dictGet);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(dictHas);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(dictGetHierarchy);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(dictIsIn);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(addressToLine);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(addressToSymbol);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(demangle);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(INTROSPECTION);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(file);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(url);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(input);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(values);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(numbers);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(zeros);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(merge);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(remote);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(mysql);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(odbc);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(jdbc);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(hdfs);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(s3);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(TABLE_FUNCTIONS);
|
||||
|
||||
#undef ACCESS_TYPE_TO_KEYWORD_CASE
|
||||
}
|
||||
|
||||
std::array<String, MAX_ACCESS_TYPE> access_type_to_keyword_mapping;
|
||||
Strings access_type_to_keyword_mapping;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ public:
|
||||
|
||||
/// Allows IP addresses or host names using LIKE pattern.
|
||||
/// This pattern can contain % and _ wildcard characters.
|
||||
/// For example, addLikePattern("@") will allow all addresses.
|
||||
/// For example, addLikePattern("%") will allow all addresses.
|
||||
void addLikePattern(const String & pattern);
|
||||
void removeLikePattern(const String & like_pattern);
|
||||
const std::vector<String> & getLikePatterns() const { return like_patterns; }
|
||||
@ -298,7 +298,7 @@ inline void AllowedClientHosts::addLikePattern(const String & pattern)
|
||||
{
|
||||
if (boost::iequals(pattern, "localhost") || (pattern == "127.0.0.1") || (pattern == "::1"))
|
||||
local_host = true;
|
||||
else if ((pattern == "@") || (pattern == "0.0.0.0/0") || (pattern == "::/0"))
|
||||
else if ((pattern == "%") || (pattern == "0.0.0.0/0") || (pattern == "::/0"))
|
||||
any_host = true;
|
||||
else if (boost::range::find(like_patterns, pattern) == name_regexps.end())
|
||||
like_patterns.push_back(pattern);
|
||||
@ -308,7 +308,7 @@ inline void AllowedClientHosts::removeLikePattern(const String & pattern)
|
||||
{
|
||||
if (boost::iequals(pattern, "localhost") || (pattern == "127.0.0.1") || (pattern == "::1"))
|
||||
local_host = false;
|
||||
else if ((pattern == "@") || (pattern == "0.0.0.0/0") || (pattern == "::/0"))
|
||||
else if ((pattern == "%") || (pattern == "0.0.0.0/0") || (pattern == "::/0"))
|
||||
any_host = false;
|
||||
else
|
||||
boost::range::remove_erase(like_patterns, pattern);
|
||||
|
@ -404,23 +404,19 @@ boost::shared_ptr<const AccessRights> ContextAccess::calculateResultAccess(bool
|
||||
static const AccessFlags table_ddl = AccessType::CREATE_DATABASE | AccessType::CREATE_TABLE | AccessType::CREATE_VIEW
|
||||
| AccessType::ALTER_TABLE | AccessType::ALTER_VIEW | AccessType::DROP_DATABASE | AccessType::DROP_TABLE | AccessType::DROP_VIEW
|
||||
| AccessType::TRUNCATE;
|
||||
|
||||
static const AccessFlags dictionary_ddl = AccessType::CREATE_DICTIONARY | AccessType::DROP_DICTIONARY;
|
||||
static const AccessFlags table_and_dictionary_ddl = table_ddl | dictionary_ddl;
|
||||
static const AccessFlags write_table_access = AccessType::INSERT | AccessType::OPTIMIZE;
|
||||
static const AccessFlags all_dcl = AccessType::CREATE_USER | AccessType::CREATE_ROLE | AccessType::CREATE_POLICY
|
||||
| AccessType::CREATE_QUOTA | AccessType::CREATE_SETTINGS_PROFILE | AccessType::ALTER_USER | AccessType::ALTER_ROLE
|
||||
| AccessType::ALTER_POLICY | AccessType::ALTER_QUOTA | AccessType::ALTER_SETTINGS_PROFILE | AccessType::DROP_USER
|
||||
| AccessType::DROP_ROLE | AccessType::DROP_POLICY | AccessType::DROP_QUOTA | AccessType::DROP_SETTINGS_PROFILE
|
||||
| AccessType::ROLE_ADMIN;
|
||||
|
||||
if (readonly_)
|
||||
merged_access->revoke(write_table_access | all_dcl | table_and_dictionary_ddl | AccessType::SYSTEM | AccessType::KILL_QUERY);
|
||||
merged_access->revoke(write_table_access | table_and_dictionary_ddl | AccessType::SYSTEM | AccessType::KILL_QUERY | AccessType::ACCESS_MANAGEMENT);
|
||||
|
||||
if (readonly_ == 1)
|
||||
{
|
||||
/// Table functions are forbidden in readonly mode.
|
||||
/// For example, for readonly = 2 - allowed.
|
||||
merged_access->revoke(AccessType::CREATE_TEMPORARY_TABLE | AccessType::TABLE_FUNCTIONS);
|
||||
merged_access->revoke(AccessType::CREATE_TEMPORARY_TABLE);
|
||||
}
|
||||
|
||||
if (!allow_ddl_ && !grant_option)
|
||||
|
@ -51,25 +51,25 @@ ExtendedRoleSet::ExtendedRoleSet(const boost::container::flat_set<UUID> & ids_)
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast)
|
||||
{
|
||||
init(ast, nullptr, nullptr);
|
||||
init(ast, nullptr);
|
||||
}
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const UUID & current_user_id)
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const std::optional<UUID> & current_user_id)
|
||||
{
|
||||
init(ast, nullptr, ¤t_user_id);
|
||||
init(ast, nullptr, current_user_id);
|
||||
}
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager)
|
||||
{
|
||||
init(ast, &manager, nullptr);
|
||||
init(ast, &manager);
|
||||
}
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const UUID & current_user_id)
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id)
|
||||
{
|
||||
init(ast, &manager, ¤t_user_id);
|
||||
init(ast, &manager, current_user_id);
|
||||
}
|
||||
|
||||
void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager, const UUID * current_user_id)
|
||||
void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager, const std::optional<UUID> & current_user_id)
|
||||
{
|
||||
all = ast.all;
|
||||
|
||||
|
@ -32,9 +32,9 @@ struct ExtendedRoleSet
|
||||
|
||||
/// The constructor from AST requires the AccessControlManager if `ast.id_mode == false`.
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const UUID & current_user_id);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const std::optional<UUID> & current_user_id);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const UUID & current_user_id);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id);
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> toAST() const;
|
||||
String toString() const;
|
||||
@ -69,7 +69,7 @@ struct ExtendedRoleSet
|
||||
boost::container::flat_set<UUID> except_ids;
|
||||
|
||||
private:
|
||||
void init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager = nullptr, const UUID * current_user_id = nullptr);
|
||||
void init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager = nullptr, const std::optional<UUID> & current_user_id = {});
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -168,7 +168,14 @@ namespace
|
||||
user->access.grant(AccessFlags::allDictionaryFlags(), IDictionary::NO_DATABASE_TAG, dictionary);
|
||||
}
|
||||
|
||||
user->access_with_grant_option = user->access;
|
||||
user->access_with_grant_option = user->access; /// By default the user can grant everything he has.
|
||||
|
||||
bool access_management = config.getBool(user_config + ".access_management", false);
|
||||
if (!access_management)
|
||||
{
|
||||
user->access.revoke(AccessType::ACCESS_MANAGEMENT);
|
||||
user->access_with_grant_option.clear();
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
@ -17,8 +17,10 @@
|
||||
|
||||
#include <unordered_map>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <Common/hex.h>
|
||||
|
||||
|
||||
using namespace DB;
|
||||
|
||||
template <typename T>
|
||||
@ -69,6 +71,8 @@ void checkColumn(
|
||||
std::unordered_map<UInt32, T> map;
|
||||
size_t num_collisions = 0;
|
||||
|
||||
std::stringstream collitions_str;
|
||||
|
||||
for (size_t i = 0; i < eq_class.size(); ++i)
|
||||
{
|
||||
auto & val = eq_class[i];
|
||||
@ -82,12 +86,16 @@ void checkColumn(
|
||||
|
||||
if (num_collisions <= max_collisions_to_print)
|
||||
{
|
||||
std::cout << "Collision:\n";
|
||||
std::cout << print_for_row(it->second) << '\n';
|
||||
std::cout << print_for_row(i) << std::endl;
|
||||
collitions_str << "Collision:\n";
|
||||
collitions_str << print_for_row(it->second) << '\n';
|
||||
collitions_str << print_for_row(i) << std::endl;
|
||||
}
|
||||
else if (num_collisions > allowed_collisions)
|
||||
|
||||
if (num_collisions > allowed_collisions)
|
||||
{
|
||||
std::cerr << collitions_str.rdbuf();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/ReadWriteBufferFromHTTP.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Access/AccessType.h>
|
||||
#include <Parsers/IdentifierQuotingStyle.h>
|
||||
#include <Poco/File.h>
|
||||
#include <Poco/Logger.h>
|
||||
@ -230,6 +231,10 @@ struct JDBCBridgeMixin
|
||||
{
|
||||
return "JDBC";
|
||||
}
|
||||
static AccessType getSourceAccessType()
|
||||
{
|
||||
return AccessType::JDBC;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ShellCommand> startBridge(const Poco::Util::AbstractConfiguration &, const Poco::Logger *, const Poco::Timespan &)
|
||||
{
|
||||
@ -253,6 +258,10 @@ struct ODBCBridgeMixin
|
||||
{
|
||||
return "ODBC";
|
||||
}
|
||||
static AccessType getSourceAccessType()
|
||||
{
|
||||
return AccessType::ODBC;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ShellCommand> startBridge(const Poco::Util::AbstractConfiguration & config, Poco::Logger * log, const Poco::Timespan & http_timeout)
|
||||
{
|
||||
|
@ -123,14 +123,17 @@ TEST(zkutil, MultiAsync)
|
||||
ops.clear();
|
||||
|
||||
auto res = fut.get();
|
||||
ASSERT_EQ(res.error, Coordination::ZNODEEXISTS);
|
||||
ASSERT_EQ(res.responses.size(), 2);
|
||||
|
||||
/// The test is quite heavy. It is normal if session is expired during this test.
|
||||
/// If we don't check that, the test will be flacky.
|
||||
if (res.error != Coordination::ZSESSIONEXPIRED && res.error != Coordination::ZCONNECTIONLOSS)
|
||||
{
|
||||
ASSERT_EQ(res.error, Coordination::ZNODEEXISTS);
|
||||
ASSERT_EQ(res.responses.size(), 2);
|
||||
}
|
||||
}
|
||||
catch (const Coordination::Exception & e)
|
||||
{
|
||||
/// The test is quite heavy. It is normal if session is expired during this test.
|
||||
/// If we don't check that, the test will be flacky.
|
||||
|
||||
if (e.code != Coordination::ZSESSIONEXPIRED && e.code != Coordination::ZCONNECTIONLOSS)
|
||||
throw;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -46,10 +47,17 @@ std::string makeRegexpPatternFromGlobs(const std::string & initial_str_with_glob
|
||||
std::istringstream iss_range(buffer);
|
||||
iss_range >> range_begin >> point >> point >> range_end;
|
||||
assert(iss_range.good());
|
||||
bool leading_zeros = buffer[0] == '0';
|
||||
size_t num_len = std::to_string(range_end).size();
|
||||
if (leading_zeros)
|
||||
oss_for_replacing << std::setfill('0') << std::setw(num_len);
|
||||
oss_for_replacing << range_begin;
|
||||
for (size_t i = range_begin + 1; i <= range_end; ++i)
|
||||
{
|
||||
oss_for_replacing << '|' << i;
|
||||
oss_for_replacing << '|';
|
||||
if (leading_zeros)
|
||||
oss_for_replacing << std::setfill('0') << std::setw(num_len);
|
||||
oss_for_replacing << i;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <memory>
|
||||
#include <Client/ConnectionPool.h>
|
||||
#include <DataStreams/RemoteBlockInputStream.h>
|
||||
#include <DataStreams/ConvertingBlockInputStream.h>
|
||||
#include <IO/ConnectionTimeouts.h>
|
||||
#include <Interpreters/executeQuery.h>
|
||||
#include <Common/isLocalAddress.h>
|
||||
@ -131,6 +132,7 @@ BlockInputStreamPtr ClickHouseDictionarySource::loadAll()
|
||||
{
|
||||
BlockIO res = executeQuery(load_all_query, context, true);
|
||||
/// FIXME res.in may implicitly use some objects owned be res, but them will be destructed after return
|
||||
res.in = std::make_shared<ConvertingBlockInputStream>(context, res.in, sample_block, ConvertingBlockInputStream::MatchColumnsMode::Position);
|
||||
return res.in;
|
||||
}
|
||||
return std::make_shared<RemoteBlockInputStream>(pool, load_all_query, sample_block, context);
|
||||
@ -140,7 +142,11 @@ BlockInputStreamPtr ClickHouseDictionarySource::loadUpdatedAll()
|
||||
{
|
||||
std::string load_update_query = getUpdateFieldAndDate();
|
||||
if (is_local)
|
||||
return executeQuery(load_update_query, context, true).in;
|
||||
{
|
||||
auto res = executeQuery(load_update_query, context, true);
|
||||
res.in = std::make_shared<ConvertingBlockInputStream>(context, res.in, sample_block, ConvertingBlockInputStream::MatchColumnsMode::Position);
|
||||
return res.in;
|
||||
}
|
||||
return std::make_shared<RemoteBlockInputStream>(pool, load_update_query, sample_block, context);
|
||||
}
|
||||
|
||||
@ -183,7 +189,12 @@ std::string ClickHouseDictionarySource::toString() const
|
||||
BlockInputStreamPtr ClickHouseDictionarySource::createStreamForSelectiveLoad(const std::string & query)
|
||||
{
|
||||
if (is_local)
|
||||
return executeQuery(query, context, true).in;
|
||||
{
|
||||
auto res = executeQuery(query, context, true);
|
||||
res.in = std::make_shared<ConvertingBlockInputStream>(
|
||||
context, res.in, sample_block, ConvertingBlockInputStream::MatchColumnsMode::Position);
|
||||
return res.in;
|
||||
}
|
||||
|
||||
return std::make_shared<RemoteBlockInputStream>(pool, query, sample_block, context);
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ private:
|
||||
|
||||
auto dict = dictionaries_loader.getDictionary(dict_name_col->getValue<String>());
|
||||
const auto dict_ptr = dict.get();
|
||||
context.checkAccess(AccessType::dictHas, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
context.checkAccess(AccessType::dictGet, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
|
||||
if (!executeDispatchSimple<FlatDictionary>(block, arguments, result, dict_ptr) &&
|
||||
!executeDispatchSimple<HashedDictionary>(block, arguments, result, dict_ptr) &&
|
||||
@ -1652,7 +1652,7 @@ private:
|
||||
|
||||
auto dict = dictionaries_loader.getDictionary(dict_name_col->getValue<String>());
|
||||
const auto dict_ptr = dict.get();
|
||||
context.checkAccess(AccessType::dictGetHierarchy, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
context.checkAccess(AccessType::dictGet, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
|
||||
if (!executeDispatch<FlatDictionary>(block, arguments, result, dict_ptr) &&
|
||||
!executeDispatch<HashedDictionary>(block, arguments, result, dict_ptr) &&
|
||||
@ -1816,7 +1816,7 @@ private:
|
||||
|
||||
auto dict = dictionaries_loader.getDictionary(dict_name_col->getValue<String>());
|
||||
const auto dict_ptr = dict.get();
|
||||
context.checkAccess(AccessType::dictIsIn, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
context.checkAccess(AccessType::dictGet, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
|
||||
if (!executeDispatch<FlatDictionary>(block, arguments, result, dict_ptr)
|
||||
&& !executeDispatch<HashedDictionary>(block, arguments, result, dict_ptr)
|
||||
|
@ -2,15 +2,15 @@
|
||||
|
||||
#if USE_AWS_S3
|
||||
|
||||
#include <IO/S3Common.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
# include <IO/S3Common.h>
|
||||
# include <IO/WriteBufferFromString.h>
|
||||
|
||||
#include <regex>
|
||||
#include <aws/s3/S3Client.h>
|
||||
#include <aws/core/auth/AWSCredentialsProvider.h>
|
||||
#include <aws/core/utils/logging/LogSystemInterface.h>
|
||||
#include <aws/core/utils/logging/LogMacros.h>
|
||||
#include <common/logger_useful.h>
|
||||
# include <aws/core/auth/AWSCredentialsProvider.h>
|
||||
# include <aws/core/utils/logging/LogMacros.h>
|
||||
# include <aws/core/utils/logging/LogSystemInterface.h>
|
||||
# include <aws/s3/S3Client.h>
|
||||
# include <re2/re2.h>
|
||||
# include <common/logger_useful.h>
|
||||
|
||||
|
||||
namespace
|
||||
@ -57,7 +57,6 @@ private:
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int BAD_ARGUMENTS;
|
||||
@ -106,46 +105,51 @@ namespace S3
|
||||
|
||||
URI::URI(const Poco::URI & uri_)
|
||||
{
|
||||
static const std::regex bucket_key_pattern("([^/]+)/(.*)"); /// TODO std::regex is discouraged
|
||||
/// Case when bucket name represented in domain name of S3 URL.
|
||||
/// E.g. (https://bucket-name.s3.Region.amazonaws.com/key)
|
||||
/// https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html#virtual-hosted-style-access
|
||||
static const RE2 virtual_hosted_style_pattern("(.+\\.)?s3[.\\-][a-z0-9\\-.]+");
|
||||
/// Case when bucket name and key represented in path of S3 URL.
|
||||
/// E.g. (https://s3.Region.amazonaws.com/bucket-name/key)
|
||||
/// https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html#path-style-access
|
||||
static const RE2 path_style_pattern("([^/]+)/(.*)");
|
||||
|
||||
uri = uri_;
|
||||
|
||||
// s3://*
|
||||
if (uri.getScheme() == "s3" || uri.getScheme() == "S3")
|
||||
{
|
||||
bucket = uri.getAuthority();
|
||||
if (bucket.empty())
|
||||
throw Exception ("Invalid S3 URI: no bucket: " + uri.toString(), ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
const auto & path = uri.getPath();
|
||||
// s3://bucket or s3://bucket/
|
||||
if (path.length() <= 1)
|
||||
throw Exception ("Invalid S3 URI: no key: " + uri.toString(), ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
key = path.substr(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uri.getHost().empty())
|
||||
throw Exception("Invalid S3 URI: no host: " + uri.toString(), ErrorCodes::BAD_ARGUMENTS);
|
||||
throw Exception("Host is empty in S3 URI: " + uri.toString(), ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
endpoint = uri.getScheme() + "://" + uri.getAuthority();
|
||||
|
||||
// Parse bucket and key from path.
|
||||
std::smatch match;
|
||||
std::regex_search(uri.getPath(), match, bucket_key_pattern);
|
||||
if (!match.empty())
|
||||
if (re2::RE2::FullMatch(uri.getAuthority(), virtual_hosted_style_pattern, &bucket))
|
||||
{
|
||||
bucket = match.str(1);
|
||||
if (bucket.empty())
|
||||
throw Exception ("Invalid S3 URI: no bucket: " + uri.toString(), ErrorCodes::BAD_ARGUMENTS);
|
||||
if (!bucket.empty())
|
||||
bucket.pop_back(); /// Remove '.' character from the end of the bucket name.
|
||||
|
||||
key = match.str(2);
|
||||
if (key.empty())
|
||||
throw Exception ("Invalid S3 URI: no key: " + uri.toString(), ErrorCodes::BAD_ARGUMENTS);
|
||||
/// S3 specification requires at least 3 and at most 63 characters in bucket name.
|
||||
/// https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-s3-bucket-naming-requirements.html
|
||||
if (bucket.length() < 3 || bucket.length() > 63)
|
||||
throw Exception(
|
||||
"Bucket name length out of bounds in S3 URI: " + bucket + " (" + uri.toString() + ")", ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
/// Remove leading '/' from path to extract key.
|
||||
key = uri.getPath().substr(1);
|
||||
if (key.empty() || key == "/")
|
||||
throw Exception("Key name is empty in S3 URI: " + key + " (" + uri.toString() + ")", ErrorCodes::BAD_ARGUMENTS);
|
||||
}
|
||||
else if (re2::RE2::PartialMatch(uri.getPath(), path_style_pattern, &bucket, &key))
|
||||
{
|
||||
/// S3 specification requires at least 3 and at most 63 characters in bucket name.
|
||||
/// https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-s3-bucket-naming-requirements.html
|
||||
if (bucket.length() < 3 || bucket.length() > 63)
|
||||
throw Exception(
|
||||
"Bucket name length out of bounds in S3 URI: " + bucket + " (" + uri.toString() + ")", ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
if (key.empty() || key == "/")
|
||||
throw Exception("Key name is empty in S3 URI: " + key + " (" + uri.toString() + ")", ErrorCodes::BAD_ARGUMENTS);
|
||||
}
|
||||
else
|
||||
throw Exception("Invalid S3 URI: no bucket or key: " + uri.toString(), ErrorCodes::BAD_ARGUMENTS);
|
||||
throw Exception("Bucket or key name are invalid in S3 URI: " + uri.toString(), ErrorCodes::BAD_ARGUMENTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -665,12 +665,10 @@ String Context::getUserName() const
|
||||
return access->getUserName();
|
||||
}
|
||||
|
||||
UUID Context::getUserID() const
|
||||
std::optional<UUID> Context::getUserID() const
|
||||
{
|
||||
auto lock = getLock();
|
||||
if (!user_id)
|
||||
throw Exception("No current user", ErrorCodes::LOGICAL_ERROR);
|
||||
return *user_id;
|
||||
return user_id;
|
||||
}
|
||||
|
||||
|
||||
|
@ -233,7 +233,7 @@ public:
|
||||
|
||||
UserPtr getUser() const;
|
||||
String getUserName() const;
|
||||
UUID getUserID() const;
|
||||
std::optional<UUID> getUserID() const;
|
||||
|
||||
void setCurrentRoles(const std::vector<UUID> & current_roles_);
|
||||
void setCurrentRolesDefault();
|
||||
|
@ -1377,4 +1377,9 @@ BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & cont
|
||||
}
|
||||
|
||||
|
||||
BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & context)
|
||||
{
|
||||
return executeDDLQueryOnCluster(query_ptr_, context, {});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ struct DDLTask;
|
||||
|
||||
/// Pushes distributed DDL query to the queue
|
||||
BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr, const Context & context, AccessRightsElements && query_required_access);
|
||||
BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr, const Context & context);
|
||||
|
||||
|
||||
class DDLWorker
|
||||
|
@ -427,8 +427,6 @@ public:
|
||||
if (configs == new_configs)
|
||||
return;
|
||||
|
||||
LOG_TRACE(log, "Configuration of reloadable objects has changed");
|
||||
|
||||
configs = new_configs;
|
||||
|
||||
std::vector<String> removed_names;
|
||||
@ -437,7 +435,6 @@ public:
|
||||
auto new_config_it = new_configs->find(name);
|
||||
if (new_config_it == new_configs->end())
|
||||
{
|
||||
LOG_TRACE(log, "Reloadable object '" << name << "' is removed");
|
||||
removed_names.emplace_back(name);
|
||||
}
|
||||
else
|
||||
@ -448,8 +445,6 @@ public:
|
||||
if (!config_is_same)
|
||||
{
|
||||
/// Configuration has been changed.
|
||||
LOG_TRACE(log, "Configuration has changed for reloadable "
|
||||
"object '" << info.name << "'");
|
||||
info.object_config = new_config;
|
||||
|
||||
if (info.triedToLoad())
|
||||
@ -457,7 +452,7 @@ public:
|
||||
/// The object has been tried to load before, so it is currently in use or was in use
|
||||
/// and we should try to reload it with the new config.
|
||||
LOG_TRACE(log, "Will reload '" << name << "'"
|
||||
" because its configuration has changed and"
|
||||
" because its configuration has been changed and"
|
||||
" there were attempts to load it before");
|
||||
startLoading(info, true);
|
||||
}
|
||||
@ -473,7 +468,7 @@ public:
|
||||
Info & info = infos.emplace(name, Info{name, config}).first->second;
|
||||
if (always_load_everything)
|
||||
{
|
||||
LOG_TRACE(log, "Will reload new object '" << name << "'"
|
||||
LOG_TRACE(log, "Will load '" << name << "'"
|
||||
" because always_load_everything flag is set.");
|
||||
startLoading(info);
|
||||
}
|
||||
@ -482,7 +477,15 @@ public:
|
||||
|
||||
/// Remove from the map those objects which were removed from the configuration.
|
||||
for (const String & name : removed_names)
|
||||
infos.erase(name);
|
||||
{
|
||||
if (auto it = infos.find(name); it != infos.end())
|
||||
{
|
||||
const auto & info = it->second;
|
||||
if (info.loaded() || info.isLoading())
|
||||
LOG_TRACE(log, "Unloading '" << name << "' because its configuration has been removed or detached");
|
||||
infos.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
/// Maybe we have just added new objects which require to be loaded
|
||||
/// or maybe we have just removed object which were been loaded,
|
||||
|
@ -149,35 +149,35 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
{
|
||||
case ASTAlterCommand::UPDATE:
|
||||
{
|
||||
required_access.emplace_back(AccessType::UPDATE, database, table, column_names_from_update_assignments());
|
||||
required_access.emplace_back(AccessType::ALTER_UPDATE, database, table, column_names_from_update_assignments());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::DELETE:
|
||||
{
|
||||
required_access.emplace_back(AccessType::DELETE, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DELETE, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::ADD_COLUMN:
|
||||
{
|
||||
required_access.emplace_back(AccessType::ADD_COLUMN, database, table, column_name_from_col_decl());
|
||||
required_access.emplace_back(AccessType::ALTER_ADD_COLUMN, database, table, column_name_from_col_decl());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::DROP_COLUMN:
|
||||
{
|
||||
if (command.clear_column)
|
||||
required_access.emplace_back(AccessType::CLEAR_COLUMN, database, table, column_name());
|
||||
required_access.emplace_back(AccessType::ALTER_CLEAR_COLUMN, database, table, column_name());
|
||||
else
|
||||
required_access.emplace_back(AccessType::DROP_COLUMN, database, table, column_name());
|
||||
required_access.emplace_back(AccessType::ALTER_DROP_COLUMN, database, table, column_name());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_COLUMN:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MODIFY_COLUMN, database, table, column_name_from_col_decl());
|
||||
required_access.emplace_back(AccessType::ALTER_MODIFY_COLUMN, database, table, column_name_from_col_decl());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::COMMENT_COLUMN:
|
||||
{
|
||||
required_access.emplace_back(AccessType::COMMENT_COLUMN, database, table, column_name());
|
||||
required_access.emplace_back(AccessType::ALTER_COMMENT_COLUMN, database, table, column_name());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_ORDER_BY:
|
||||
@ -187,45 +187,45 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
}
|
||||
case ASTAlterCommand::ADD_INDEX:
|
||||
{
|
||||
required_access.emplace_back(AccessType::ADD_INDEX, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_ADD_INDEX, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::DROP_INDEX:
|
||||
{
|
||||
if (command.clear_index)
|
||||
required_access.emplace_back(AccessType::CLEAR_INDEX, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_CLEAR_INDEX, database, table);
|
||||
else
|
||||
required_access.emplace_back(AccessType::DROP_INDEX, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DROP_INDEX, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MATERIALIZE_INDEX:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MATERIALIZE_INDEX, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_MATERIALIZE_INDEX, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::ADD_CONSTRAINT:
|
||||
{
|
||||
required_access.emplace_back(AccessType::ADD_CONSTRAINT, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_ADD_CONSTRAINT, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::DROP_CONSTRAINT:
|
||||
{
|
||||
required_access.emplace_back(AccessType::DROP_CONSTRAINT, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DROP_CONSTRAINT, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_TTL:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MODIFY_TTL, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_TTL, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MATERIALIZE_TTL:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MATERIALIZE_TTL, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_MATERIALIZE_TTL, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_SETTING:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MODIFY_SETTING, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_SETTINGS, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::ATTACH_PARTITION:
|
||||
@ -236,7 +236,7 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
case ASTAlterCommand::DROP_PARTITION: [[fallthrough]];
|
||||
case ASTAlterCommand::DROP_DETACHED_PARTITION:
|
||||
{
|
||||
required_access.emplace_back(AccessType::DELETE, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DELETE, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MOVE_PARTITION:
|
||||
@ -244,11 +244,11 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
if ((command.move_destination_type == PartDestinationType::DISK)
|
||||
|| (command.move_destination_type == PartDestinationType::VOLUME))
|
||||
{
|
||||
required_access.emplace_back(AccessType::MOVE_PARTITION, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_MOVE_PARTITION, database, table);
|
||||
}
|
||||
else if (command.move_destination_type == PartDestinationType::TABLE)
|
||||
{
|
||||
required_access.emplace_back(AccessType::SELECT | AccessType::DELETE, database, table);
|
||||
required_access.emplace_back(AccessType::SELECT | AccessType::ALTER_DELETE, database, table);
|
||||
required_access.emplace_back(AccessType::INSERT, command.to_database, command.to_table);
|
||||
}
|
||||
break;
|
||||
@ -256,33 +256,33 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
case ASTAlterCommand::REPLACE_PARTITION:
|
||||
{
|
||||
required_access.emplace_back(AccessType::SELECT, command.from_database, command.from_table);
|
||||
required_access.emplace_back(AccessType::DELETE | AccessType::INSERT, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DELETE | AccessType::INSERT, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::FETCH_PARTITION:
|
||||
{
|
||||
required_access.emplace_back(AccessType::FETCH_PARTITION, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_FETCH_PARTITION, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::FREEZE_PARTITION: [[fallthrough]];
|
||||
case ASTAlterCommand::FREEZE_ALL:
|
||||
{
|
||||
required_access.emplace_back(AccessType::FREEZE_PARTITION, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_FREEZE_PARTITION, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_QUERY:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MODIFY_VIEW_QUERY, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_VIEW_MODIFY_QUERY, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::LIVE_VIEW_REFRESH:
|
||||
{
|
||||
required_access.emplace_back(AccessType::REFRESH_VIEW, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_VIEW_REFRESH, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::RENAME_COLUMN:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RENAME_COLUMN, database, table, column_name());
|
||||
required_access.emplace_back(AccessType::ALTER_RENAME_COLUMN, database, table, column_name());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::NO_TYPE: break;
|
||||
|
@ -765,7 +765,14 @@ AccessRightsElements InterpreterCreateQuery::getRequiredAccess() const
|
||||
}
|
||||
|
||||
if (!create.to_table.empty())
|
||||
required_access.emplace_back(AccessType::INSERT, create.to_database, create.to_table);
|
||||
required_access.emplace_back(AccessType::SELECT | AccessType::INSERT, create.to_database, create.to_table);
|
||||
|
||||
if (create.storage && create.storage->engine)
|
||||
{
|
||||
auto source_access_type = StorageFactory::instance().getSourceAccessType(create.storage->engine->name);
|
||||
if (source_access_type != AccessType::NONE)
|
||||
required_access.emplace_back(source_access_type);
|
||||
}
|
||||
|
||||
return required_access;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <Parsers/ASTCreateQuotaQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <ext/range.h>
|
||||
@ -76,10 +77,16 @@ void updateQuotaFromQueryImpl(Quota & quota, const ASTCreateQuotaQuery & query,
|
||||
|
||||
BlockIO InterpreterCreateQuotaQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateQuotaQuery &>();
|
||||
auto & query = query_ptr->as<ASTCreateQuotaQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
context.checkAccess(query.alter ? AccessType::ALTER_QUOTA : AccessType::CREATE_QUOTA);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
query.replaceCurrentUserTagWithName(context.getUserName());
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
}
|
||||
|
||||
std::optional<ExtendedRoleSet> roles_from_query;
|
||||
if (query.roles)
|
||||
roles_from_query = ExtendedRoleSet{*query.roles, access_control, context.getUserID()};
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <Interpreters/InterpreterCreateRoleQuery.h>
|
||||
#include <Parsers/ASTCreateRoleQuery.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/Role.h>
|
||||
|
||||
@ -44,6 +45,9 @@ BlockIO InterpreterCreateRoleQuery::execute()
|
||||
else
|
||||
context.checkAccess(AccessType::CREATE_ROLE);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
|
||||
std::optional<SettingsProfileElements> settings_from_query;
|
||||
if (query.settings)
|
||||
settings_from_query = SettingsProfileElements{*query.settings, access_control};
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <boost/range/algorithm/sort.hpp>
|
||||
@ -63,9 +64,15 @@ namespace
|
||||
|
||||
BlockIO InterpreterCreateRowPolicyQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateRowPolicyQuery &>();
|
||||
auto & query = query_ptr->as<ASTCreateRowPolicyQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
context.checkAccess(query.alter ? AccessType::ALTER_POLICY : AccessType::CREATE_POLICY);
|
||||
context.checkAccess(query.alter ? AccessType::ALTER_ROW_POLICY : AccessType::CREATE_ROW_POLICY);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
query.replaceCurrentUserTagWithName(context.getUserName());
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
}
|
||||
|
||||
std::optional<ExtendedRoleSet> roles_from_query;
|
||||
if (query.roles)
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <Interpreters/InterpreterCreateSettingsProfileQuery.h>
|
||||
#include <Parsers/ASTCreateSettingsProfileQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/SettingsProfile.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
@ -49,13 +51,19 @@ namespace
|
||||
|
||||
BlockIO InterpreterCreateSettingsProfileQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateSettingsProfileQuery &>();
|
||||
auto & query = query_ptr->as<ASTCreateSettingsProfileQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
if (query.alter)
|
||||
context.checkAccess(AccessType::ALTER_SETTINGS_PROFILE);
|
||||
else
|
||||
context.checkAccess(AccessType::CREATE_SETTINGS_PROFILE);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
query.replaceCurrentUserTagWithName(context.getUserName());
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
}
|
||||
|
||||
std::optional<SettingsProfileElements> settings_from_query;
|
||||
if (query.settings)
|
||||
settings_from_query = SettingsProfileElements{*query.settings, access_control};
|
||||
|
@ -1,10 +1,11 @@
|
||||
#include <Interpreters/InterpreterCreateUserQuery.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/InterpreterSetRoleQuery.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Parsers/ASTCreateUserQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/User.h>
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
@ -67,7 +68,7 @@ namespace
|
||||
|
||||
BlockIO InterpreterCreateUserQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateUserQuery &>();
|
||||
auto & query = query_ptr->as<const ASTCreateUserQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
auto access = context.getAccess();
|
||||
access->checkAccess(query.alter ? AccessType::ALTER_USER : AccessType::CREATE_USER);
|
||||
@ -83,6 +84,9 @@ BlockIO InterpreterCreateUserQuery::execute()
|
||||
}
|
||||
}
|
||||
|
||||
if (!query.cluster.empty())
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
|
||||
std::optional<SettingsProfileElements> settings_from_query;
|
||||
if (query.settings)
|
||||
settings_from_query = SettingsProfileElements{*query.settings, access_control};
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <Interpreters/InterpreterDropAccessEntityQuery.h>
|
||||
#include <Parsers/ASTDropAccessEntityQuery.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Access/User.h>
|
||||
@ -37,7 +38,7 @@ namespace
|
||||
case Kind::USER: return AccessType::DROP_USER;
|
||||
case Kind::ROLE: return AccessType::DROP_ROLE;
|
||||
case Kind::QUOTA: return AccessType::DROP_QUOTA;
|
||||
case Kind::ROW_POLICY: return AccessType::DROP_POLICY;
|
||||
case Kind::ROW_POLICY: return AccessType::DROP_ROW_POLICY;
|
||||
case Kind::SETTINGS_PROFILE: return AccessType::DROP_SETTINGS_PROFILE;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
@ -52,6 +53,9 @@ BlockIO InterpreterDropAccessEntityQuery::execute()
|
||||
std::type_index type = getType(query.kind);
|
||||
context.checkAccess(getRequiredAccessType(query.kind));
|
||||
|
||||
if (!query.cluster.empty())
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
|
||||
if (query.kind == Kind::ROW_POLICY)
|
||||
{
|
||||
Strings full_names;
|
||||
|
@ -99,7 +99,7 @@ BlockIO InterpreterDropQuery::executeToTable(
|
||||
}
|
||||
else if (kind == ASTDropQuery::Kind::Truncate)
|
||||
{
|
||||
context.checkAccess(table->isView() ? AccessType::TRUNCATE_VIEW : AccessType::TRUNCATE_TABLE, table_id);
|
||||
context.checkAccess(AccessType::TRUNCATE, table_id);
|
||||
table->checkTableCanBeDropped();
|
||||
|
||||
/// If table was already dropped by anyone, an exception will be thrown
|
||||
@ -316,7 +316,7 @@ AccessRightsElements InterpreterDropQuery::getRequiredAccessForDDLOnCluster() co
|
||||
if (drop.kind == ASTDropQuery::Kind::Drop)
|
||||
required_access.emplace_back(AccessType::DROP_TABLE | AccessType::DROP_VIEW, drop.database, drop.table);
|
||||
else if (drop.kind == ASTDropQuery::Kind::Truncate)
|
||||
required_access.emplace_back(AccessType::TRUNCATE_TABLE | AccessType::TRUNCATE_VIEW, drop.database, drop.table);
|
||||
required_access.emplace_back(AccessType::TRUNCATE, drop.database, drop.table);
|
||||
else if (drop.kind == ASTDropQuery::Kind::Detach)
|
||||
required_access.emplace_back(AccessType::DROP_TABLE | AccessType::DROP_VIEW, drop.database, drop.table);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <Interpreters/InterpreterGrantQuery.h>
|
||||
#include <Parsers/ASTGrantQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
@ -59,7 +61,7 @@ namespace
|
||||
|
||||
BlockIO InterpreterGrantQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTGrantQuery &>();
|
||||
auto & query = query_ptr->as<ASTGrantQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
auto access = context.getAccess();
|
||||
access->checkGrantOption(query.access_rights_elements);
|
||||
@ -72,6 +74,12 @@ BlockIO InterpreterGrantQuery::execute()
|
||||
access->checkAdminOption(role_from_query);
|
||||
}
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
query.replaceCurrentUserTagWithName(context.getUserName());
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
}
|
||||
|
||||
std::vector<UUID> to_roles = ExtendedRoleSet{*query.to_roles, access_control, context.getUserID()}.getMatchingIDs(access_control);
|
||||
String current_database = context.getCurrentDatabase();
|
||||
|
||||
|
@ -319,7 +319,7 @@ AccessRightsElements InterpreterKillQueryQuery::getRequiredAccessForDDLOnCluster
|
||||
if (query.type == ASTKillQueryQuery::Type::Query)
|
||||
required_access.emplace_back(AccessType::KILL_QUERY);
|
||||
else if (query.type == ASTKillQueryQuery::Type::Mutation)
|
||||
required_access.emplace_back(AccessType::UPDATE | AccessType::DELETE | AccessType::MATERIALIZE_INDEX | AccessType::MATERIALIZE_TTL);
|
||||
required_access.emplace_back(AccessType::ALTER_UPDATE | AccessType::ALTER_DELETE | AccessType::ALTER_MATERIALIZE_INDEX | AccessType::ALTER_MATERIALIZE_TTL);
|
||||
return required_access;
|
||||
}
|
||||
|
||||
|
@ -510,7 +510,7 @@ Block InterpreterSelectQuery::getSampleBlockImpl(bool try_move_to_prewhere)
|
||||
}
|
||||
|
||||
if (storage && !options.only_analyze)
|
||||
from_stage = storage->getQueryProcessingStage(*context, query_ptr);
|
||||
from_stage = storage->getQueryProcessingStage(*context, options.to_stage, query_ptr);
|
||||
|
||||
/// Do I need to perform the first part of the pipeline - running on remote servers during distributed processing.
|
||||
bool first_stage = from_stage < QueryProcessingStage::WithMergeableState
|
||||
|
@ -256,6 +256,7 @@ BlockInputStreamPtr InterpreterShowCreateAccessEntityQuery::executeImpl()
|
||||
ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(const ASTShowCreateAccessEntityQuery & show_query) const
|
||||
{
|
||||
const auto & access_control = context.getAccessControlManager();
|
||||
context.checkAccess(getRequiredAccess());
|
||||
|
||||
if (show_query.current_user)
|
||||
{
|
||||
@ -281,6 +282,22 @@ ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(const ASTShowCreat
|
||||
}
|
||||
|
||||
|
||||
AccessRightsElements InterpreterShowCreateAccessEntityQuery::getRequiredAccess() const
|
||||
{
|
||||
const auto & show_query = query_ptr->as<ASTShowCreateAccessEntityQuery &>();
|
||||
AccessRightsElements res;
|
||||
switch (show_query.kind)
|
||||
{
|
||||
case Kind::USER: res.emplace_back(AccessType::SHOW_USERS); break;
|
||||
case Kind::ROLE: res.emplace_back(AccessType::SHOW_ROLES); break;
|
||||
case Kind::ROW_POLICY: res.emplace_back(AccessType::SHOW_ROW_POLICIES); break;
|
||||
case Kind::SETTINGS_PROFILE: res.emplace_back(AccessType::SHOW_SETTINGS_PROFILES); break;
|
||||
case Kind::QUOTA: res.emplace_back(AccessType::SHOW_QUOTAS); break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ASTPtr InterpreterShowCreateAccessEntityQuery::getAttachQuery(const IAccessEntity & entity)
|
||||
{
|
||||
return getCreateQueryImpl(entity, nullptr, true);
|
||||
|
@ -9,6 +9,7 @@ namespace DB
|
||||
{
|
||||
class Context;
|
||||
class ASTShowCreateAccessEntityQuery;
|
||||
class AccessRightsElements;
|
||||
struct IAccessEntity;
|
||||
|
||||
|
||||
@ -30,6 +31,7 @@ public:
|
||||
private:
|
||||
BlockInputStreamPtr executeImpl();
|
||||
ASTPtr getCreateQuery(const ASTShowCreateAccessEntityQuery & show_query) const;
|
||||
AccessRightsElements getRequiredAccess() const;
|
||||
|
||||
ASTPtr query_ptr;
|
||||
const Context & context;
|
||||
|
@ -102,19 +102,19 @@ void executeCommandsAndThrowIfError(Callables && ... commands)
|
||||
AccessType getRequiredAccessType(StorageActionBlockType action_type)
|
||||
{
|
||||
if (action_type == ActionLocks::PartsMerge)
|
||||
return AccessType::STOP_MERGES;
|
||||
return AccessType::SYSTEM_MERGES;
|
||||
else if (action_type == ActionLocks::PartsFetch)
|
||||
return AccessType::STOP_FETCHES;
|
||||
return AccessType::SYSTEM_FETCHES;
|
||||
else if (action_type == ActionLocks::PartsSend)
|
||||
return AccessType::STOP_REPLICATED_SENDS;
|
||||
return AccessType::SYSTEM_REPLICATED_SENDS;
|
||||
else if (action_type == ActionLocks::ReplicationQueue)
|
||||
return AccessType::STOP_REPLICATION_QUEUES;
|
||||
return AccessType::SYSTEM_REPLICATION_QUEUES;
|
||||
else if (action_type == ActionLocks::DistributedSend)
|
||||
return AccessType::STOP_DISTRIBUTED_SENDS;
|
||||
return AccessType::SYSTEM_DISTRIBUTED_SENDS;
|
||||
else if (action_type == ActionLocks::PartsTTLMerge)
|
||||
return AccessType::STOP_TTL_MERGES;
|
||||
return AccessType::SYSTEM_TTL_MERGES;
|
||||
else if (action_type == ActionLocks::PartsMove)
|
||||
return AccessType::STOP_MOVES;
|
||||
return AccessType::SYSTEM_MOVES;
|
||||
else
|
||||
throw Exception("Unknown action type: " + std::to_string(action_type), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
@ -183,42 +183,42 @@ BlockIO InterpreterSystemQuery::execute()
|
||||
switch (query.type)
|
||||
{
|
||||
case Type::SHUTDOWN:
|
||||
context.checkAccess(AccessType::SHUTDOWN);
|
||||
context.checkAccess(AccessType::SYSTEM_SHUTDOWN);
|
||||
if (kill(0, SIGTERM))
|
||||
throwFromErrno("System call kill(0, SIGTERM) failed", ErrorCodes::CANNOT_KILL);
|
||||
break;
|
||||
case Type::KILL:
|
||||
context.checkAccess(AccessType::SHUTDOWN);
|
||||
context.checkAccess(AccessType::SYSTEM_SHUTDOWN);
|
||||
if (kill(0, SIGKILL))
|
||||
throwFromErrno("System call kill(0, SIGKILL) failed", ErrorCodes::CANNOT_KILL);
|
||||
break;
|
||||
case Type::DROP_DNS_CACHE:
|
||||
context.checkAccess(AccessType::DROP_CACHE);
|
||||
context.checkAccess(AccessType::SYSTEM_DROP_DNS_CACHE);
|
||||
DNSResolver::instance().dropCache();
|
||||
/// Reinitialize clusters to update their resolved_addresses
|
||||
system_context.reloadClusterConfig();
|
||||
break;
|
||||
case Type::DROP_MARK_CACHE:
|
||||
context.checkAccess(AccessType::DROP_CACHE);
|
||||
context.checkAccess(AccessType::SYSTEM_DROP_MARK_CACHE);
|
||||
system_context.dropMarkCache();
|
||||
break;
|
||||
case Type::DROP_UNCOMPRESSED_CACHE:
|
||||
context.checkAccess(AccessType::DROP_CACHE);
|
||||
context.checkAccess(AccessType::SYSTEM_DROP_UNCOMPRESSED_CACHE);
|
||||
system_context.dropUncompressedCache();
|
||||
break;
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
case Type::DROP_COMPILED_EXPRESSION_CACHE:
|
||||
context.checkAccess(AccessType::DROP_CACHE);
|
||||
context.checkAccess(AccessType::SYSTEM_DROP_COMPILED_EXPRESSION_CACHE);
|
||||
system_context.dropCompiledExpressionCache();
|
||||
break;
|
||||
#endif
|
||||
case Type::RELOAD_DICTIONARY:
|
||||
context.checkAccess(AccessType::RELOAD_DICTIONARY);
|
||||
context.checkAccess(AccessType::SYSTEM_RELOAD_DICTIONARY);
|
||||
system_context.getExternalDictionariesLoader().loadOrReload(query.target_dictionary);
|
||||
ExternalDictionariesLoader::resetAll();
|
||||
break;
|
||||
case Type::RELOAD_DICTIONARIES:
|
||||
context.checkAccess(AccessType::RELOAD_DICTIONARY);
|
||||
context.checkAccess(AccessType::SYSTEM_RELOAD_DICTIONARY);
|
||||
executeCommandsAndThrowIfError(
|
||||
[&] () { system_context.getExternalDictionariesLoader().reloadAllTriedToLoad(); },
|
||||
[&] () { system_context.getEmbeddedDictionaries().reload(); }
|
||||
@ -226,11 +226,11 @@ BlockIO InterpreterSystemQuery::execute()
|
||||
ExternalDictionariesLoader::resetAll();
|
||||
break;
|
||||
case Type::RELOAD_EMBEDDED_DICTIONARIES:
|
||||
context.checkAccess(AccessType::RELOAD_DICTIONARY);
|
||||
context.checkAccess(AccessType::SYSTEM_RELOAD_EMBEDDED_DICTIONARIES);
|
||||
system_context.getEmbeddedDictionaries().reload();
|
||||
break;
|
||||
case Type::RELOAD_CONFIG:
|
||||
context.checkAccess(AccessType::RELOAD_CONFIG);
|
||||
context.checkAccess(AccessType::SYSTEM_RELOAD_CONFIG);
|
||||
system_context.reloadConfig();
|
||||
break;
|
||||
case Type::STOP_MERGES:
|
||||
@ -290,7 +290,7 @@ BlockIO InterpreterSystemQuery::execute()
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
break;
|
||||
case Type::FLUSH_LOGS:
|
||||
context.checkAccess(AccessType::FLUSH_LOGS);
|
||||
context.checkAccess(AccessType::SYSTEM_FLUSH_LOGS);
|
||||
executeCommandsAndThrowIfError(
|
||||
[&] () { if (auto query_log = context.getQueryLog()) query_log->flush(); },
|
||||
[&] () { if (auto part_log = context.getPartLog("")) part_log->flush(); },
|
||||
@ -313,7 +313,7 @@ BlockIO InterpreterSystemQuery::execute()
|
||||
|
||||
StoragePtr InterpreterSystemQuery::tryRestartReplica(const StorageID & replica, Context & system_context, bool need_ddl_guard)
|
||||
{
|
||||
context.checkAccess(AccessType::RESTART_REPLICA, replica);
|
||||
context.checkAccess(AccessType::SYSTEM_RESTART_REPLICA, replica);
|
||||
|
||||
auto table_ddl_guard = need_ddl_guard ? DatabaseCatalog::instance().getDDLGuard(replica.getDatabaseName(), replica.getTableName()) : nullptr;
|
||||
auto [database, table] = DatabaseCatalog::instance().tryGetDatabaseAndTable(replica);
|
||||
@ -387,7 +387,7 @@ void InterpreterSystemQuery::restartReplicas(Context & system_context)
|
||||
|
||||
void InterpreterSystemQuery::syncReplica(ASTSystemQuery &)
|
||||
{
|
||||
context.checkAccess(AccessType::SYNC_REPLICA, table_id);
|
||||
context.checkAccess(AccessType::SYSTEM_SYNC_REPLICA, table_id);
|
||||
StoragePtr table = DatabaseCatalog::instance().getTable(table_id);
|
||||
|
||||
if (auto storage_replicated = dynamic_cast<StorageReplicatedMergeTree *>(table.get()))
|
||||
@ -408,7 +408,7 @@ void InterpreterSystemQuery::syncReplica(ASTSystemQuery &)
|
||||
|
||||
void InterpreterSystemQuery::flushDistributed(ASTSystemQuery &)
|
||||
{
|
||||
context.checkAccess(AccessType::FLUSH_DISTRIBUTED, table_id);
|
||||
context.checkAccess(AccessType::SYSTEM_FLUSH_DISTRIBUTED, table_id);
|
||||
|
||||
if (auto storage_distributed = dynamic_cast<StorageDistributed *>(DatabaseCatalog::instance().getTable(table_id).get()))
|
||||
storage_distributed->flushClusterNodesAllData();
|
||||
@ -427,7 +427,7 @@ AccessRightsElements InterpreterSystemQuery::getRequiredAccessForDDLOnCluster()
|
||||
case Type::SHUTDOWN: [[fallthrough]];
|
||||
case Type::KILL:
|
||||
{
|
||||
required_access.emplace_back(AccessType::SHUTDOWN);
|
||||
required_access.emplace_back(AccessType::SYSTEM_SHUTDOWN);
|
||||
break;
|
||||
}
|
||||
case Type::DROP_DNS_CACHE: [[fallthrough]];
|
||||
@ -437,107 +437,107 @@ AccessRightsElements InterpreterSystemQuery::getRequiredAccessForDDLOnCluster()
|
||||
#endif
|
||||
case Type::DROP_UNCOMPRESSED_CACHE:
|
||||
{
|
||||
required_access.emplace_back(AccessType::DROP_CACHE);
|
||||
required_access.emplace_back(AccessType::SYSTEM_DROP_CACHE);
|
||||
break;
|
||||
}
|
||||
case Type::RELOAD_DICTIONARY: [[fallthrough]];
|
||||
case Type::RELOAD_DICTIONARIES: [[fallthrough]];
|
||||
case Type::RELOAD_EMBEDDED_DICTIONARIES:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RELOAD_DICTIONARY);
|
||||
required_access.emplace_back(AccessType::SYSTEM_RELOAD_DICTIONARY);
|
||||
break;
|
||||
}
|
||||
case Type::RELOAD_CONFIG:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RELOAD_CONFIG);
|
||||
required_access.emplace_back(AccessType::SYSTEM_RELOAD_CONFIG);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_MERGES: [[fallthrough]];
|
||||
case Type::START_MERGES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_MERGES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_MERGES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_MERGES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_MERGES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_TTL_MERGES: [[fallthrough]];
|
||||
case Type::START_TTL_MERGES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_TTL_MERGES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_TTL_MERGES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_TTL_MERGES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_TTL_MERGES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_MOVES: [[fallthrough]];
|
||||
case Type::START_MOVES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_MOVES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_MOVES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_MOVES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_MOVES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_FETCHES: [[fallthrough]];
|
||||
case Type::START_FETCHES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_FETCHES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_FETCHES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_FETCHES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_FETCHES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_DISTRIBUTED_SENDS: [[fallthrough]];
|
||||
case Type::START_DISTRIBUTED_SENDS:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_DISTRIBUTED_SENDS);
|
||||
required_access.emplace_back(AccessType::SYSTEM_DISTRIBUTED_SENDS);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_DISTRIBUTED_SENDS, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_DISTRIBUTED_SENDS, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_REPLICATED_SENDS: [[fallthrough]];
|
||||
case Type::START_REPLICATED_SENDS:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_REPLICATED_SENDS);
|
||||
required_access.emplace_back(AccessType::SYSTEM_REPLICATED_SENDS);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_REPLICATED_SENDS, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_REPLICATED_SENDS, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_REPLICATION_QUEUES: [[fallthrough]];
|
||||
case Type::START_REPLICATION_QUEUES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_REPLICATION_QUEUES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_REPLICATION_QUEUES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_REPLICATION_QUEUES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_REPLICATION_QUEUES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::SYNC_REPLICA:
|
||||
{
|
||||
required_access.emplace_back(AccessType::SYNC_REPLICA, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_SYNC_REPLICA, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::RESTART_REPLICA:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RESTART_REPLICA, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_RESTART_REPLICA, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::RESTART_REPLICAS:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RESTART_REPLICA);
|
||||
required_access.emplace_back(AccessType::SYSTEM_RESTART_REPLICA);
|
||||
break;
|
||||
}
|
||||
case Type::FLUSH_DISTRIBUTED:
|
||||
{
|
||||
required_access.emplace_back(AccessType::FLUSH_DISTRIBUTED, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_FLUSH_DISTRIBUTED, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::FLUSH_LOGS:
|
||||
{
|
||||
required_access.emplace_back(AccessType::FLUSH_LOGS);
|
||||
required_access.emplace_back(AccessType::SYSTEM_FLUSH_LOGS);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_LISTEN_QUERIES: break;
|
||||
|
@ -135,6 +135,8 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat
|
||||
|
||||
settings.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatOnCluster(settings);
|
||||
|
||||
if (!new_name.empty())
|
||||
formatRenameTo(new_name, settings);
|
||||
|
||||
@ -146,4 +148,12 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat
|
||||
if (roles && (!roles->empty() || alter))
|
||||
formatToRoles(*roles, settings);
|
||||
}
|
||||
|
||||
|
||||
void ASTCreateQuotaQuery::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (roles)
|
||||
roles->replaceCurrentUserTagWithName(current_user_name);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
#include <Access/Quota.h>
|
||||
|
||||
|
||||
@ -25,7 +26,7 @@ class ASTExtendedRoleSet;
|
||||
* UNSET TRACKING} [,...]]
|
||||
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||
*/
|
||||
class ASTCreateQuotaQuery : public IAST
|
||||
class ASTCreateQuotaQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -58,5 +59,7 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateQuotaQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -54,6 +54,8 @@ void ASTCreateRoleQuery::formatImpl(const FormatSettings & format, FormatState &
|
||||
|
||||
format.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatOnCluster(format);
|
||||
|
||||
if (!new_name.empty())
|
||||
formatRenameTo(new_name, format);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -15,7 +16,7 @@ class ASTSettingsProfileElements;
|
||||
* [RENAME TO new_name]
|
||||
* [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
|
||||
*/
|
||||
class ASTCreateRoleQuery : public IAST
|
||||
class ASTCreateRoleQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -33,5 +34,6 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const override;
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateRoleQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ namespace
|
||||
|
||||
String ASTCreateRowPolicyQuery::getID(char) const
|
||||
{
|
||||
return "CREATE POLICY or ALTER POLICY query";
|
||||
return "CREATE ROW POLICY or ALTER ROW POLICY query";
|
||||
}
|
||||
|
||||
|
||||
@ -136,11 +136,11 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
|
||||
{
|
||||
if (attach)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ATTACH POLICY";
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ATTACH ROW POLICY";
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << (alter ? "ALTER POLICY" : "CREATE POLICY")
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << (alter ? "ALTER ROW POLICY" : "CREATE ROW POLICY")
|
||||
<< (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
|
||||
@ -157,6 +157,8 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
|
||||
settings.ostr << " " << backQuoteIfNeed(policy_name) << (settings.hilite ? hilite_keyword : "") << " ON "
|
||||
<< (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".") << table_name;
|
||||
|
||||
formatOnCluster(settings);
|
||||
|
||||
if (!new_policy_name.empty())
|
||||
formatRenameTo(new_policy_name, settings);
|
||||
|
||||
@ -168,4 +170,11 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
|
||||
if (roles && (!roles->empty() || alter))
|
||||
formatToRoles(*roles, settings);
|
||||
}
|
||||
|
||||
|
||||
void ASTCreateRowPolicyQuery::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (roles)
|
||||
roles->replaceCurrentUserTagWithName(current_user_name);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
#include <Access/RowPolicy.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@ -25,7 +26,7 @@ class ASTExtendedRoleSet;
|
||||
* [WITH CHECK {condition | NONE}] [,...]
|
||||
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||
*/
|
||||
class ASTCreateRowPolicyQuery : public IAST
|
||||
class ASTCreateRowPolicyQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -47,5 +48,7 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateRowPolicyQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ void ASTCreateSettingsProfileQuery::formatImpl(const FormatSettings & format, Fo
|
||||
|
||||
format.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatOnCluster(format);
|
||||
|
||||
if (!new_name.empty())
|
||||
formatRenameTo(new_name, format);
|
||||
|
||||
@ -71,4 +73,10 @@ void ASTCreateSettingsProfileQuery::formatImpl(const FormatSettings & format, Fo
|
||||
formatToRoles(*to_roles, format);
|
||||
}
|
||||
|
||||
|
||||
void ASTCreateSettingsProfileQuery::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (to_roles)
|
||||
to_roles->replaceCurrentUserTagWithName(current_user_name);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -16,7 +17,7 @@ class ASTExtendedRoleSet;
|
||||
* [RENAME TO new_name]
|
||||
* [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
|
||||
*/
|
||||
class ASTCreateSettingsProfileQuery : public IAST
|
||||
class ASTCreateSettingsProfileQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -36,5 +37,7 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const override;
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateSettingsProfileQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -184,6 +184,8 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & format, FormatState &
|
||||
|
||||
format.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatOnCluster(format);
|
||||
|
||||
if (!new_name.empty())
|
||||
formatRenameTo(new_name, format);
|
||||
|
||||
@ -195,7 +197,7 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & format, FormatState &
|
||||
if (add_hosts)
|
||||
formatHosts("ADD", *add_hosts, format);
|
||||
if (remove_hosts)
|
||||
formatHosts("REMOVE", *remove_hosts, format);
|
||||
formatHosts("DROP", *remove_hosts, format);
|
||||
|
||||
if (default_roles)
|
||||
formatDefaultRoles(*default_roles, format);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
#include <Access/Authentication.h>
|
||||
#include <Access/AllowedClientHosts.h>
|
||||
|
||||
@ -19,11 +20,11 @@ class ASTSettingsProfileElements;
|
||||
* ALTER USER [IF EXISTS] name
|
||||
* [RENAME TO new_name]
|
||||
* [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}]
|
||||
* [[ADD|REMOVE] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
|
||||
* [[ADD|DROP] HOST {LOCAL | NAME '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'] [,...]
|
||||
*/
|
||||
class ASTCreateUserQuery : public IAST
|
||||
class ASTCreateUserQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -49,5 +50,6 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const override;
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateUserQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ void ASTDictionaryRange::formatImpl(const FormatSettings & settings,
|
||||
<< "("
|
||||
<< (settings.hilite ? hilite_keyword : "")
|
||||
<< "MIN "
|
||||
<< (settings.hilite ? hilite_none : "")
|
||||
<< min_attr_name << " "
|
||||
<< (settings.hilite ? hilite_keyword : "")
|
||||
<< "MAX "
|
||||
@ -52,6 +53,7 @@ void ASTDictionaryLifetime::formatImpl(const FormatSettings & settings,
|
||||
<< "("
|
||||
<< (settings.hilite ? hilite_keyword : "")
|
||||
<< "MIN "
|
||||
<< (settings.hilite ? hilite_none : "")
|
||||
<< min_sec << " "
|
||||
<< (settings.hilite ? hilite_keyword : "")
|
||||
<< "MAX "
|
||||
@ -86,7 +88,9 @@ void ASTDictionaryLayout::formatImpl(const FormatSettings & settings,
|
||||
<< Poco::toUpper(layout_type)
|
||||
<< (settings.hilite ? hilite_none : "");
|
||||
|
||||
settings.ostr << "(";
|
||||
if (has_brackets)
|
||||
settings.ostr << "(";
|
||||
|
||||
if (parameter)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "")
|
||||
@ -96,7 +100,10 @@ void ASTDictionaryLayout::formatImpl(const FormatSettings & settings,
|
||||
|
||||
parameter->second->formatImpl(settings, state, frame);
|
||||
}
|
||||
settings.ostr << ")";
|
||||
|
||||
if (has_brackets)
|
||||
settings.ostr << ")";
|
||||
|
||||
settings.ostr << ")";
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,8 @@ public:
|
||||
String layout_type;
|
||||
/// optional parameter (size_in_cells)
|
||||
std::optional<KeyValue> parameter;
|
||||
/// has brackets after layout type
|
||||
bool has_brackets = true;
|
||||
|
||||
String getID(char) const override { return "Dictionary layout"; }
|
||||
|
||||
|
@ -75,5 +75,7 @@ void ASTDropAccessEntityQuery::formatImpl(const FormatSettings & settings, Forma
|
||||
settings.ostr << ' ' << backQuoteIfNeed(name);
|
||||
}
|
||||
}
|
||||
|
||||
formatOnCluster(settings);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Access/RowPolicy.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -13,7 +14,7 @@ namespace DB
|
||||
* DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...]
|
||||
* DROP [SETTINGS] PROFILE [IF EXISTS] name [,...]
|
||||
*/
|
||||
class ASTDropAccessEntityQuery : public IAST
|
||||
class ASTDropAccessEntityQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
enum class Kind
|
||||
@ -34,5 +35,6 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTDropAccessEntityQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -72,4 +72,21 @@ void ASTExtendedRoleSet::formatImpl(const FormatSettings & settings, FormatState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ASTExtendedRoleSet::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (current_user)
|
||||
{
|
||||
names.push_back(current_user_name);
|
||||
current_user = false;
|
||||
}
|
||||
|
||||
if (except_current_user)
|
||||
{
|
||||
except_names.push_back(current_user_name);
|
||||
except_current_user = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ public:
|
||||
bool id_mode = false; /// If true then `names` and `except_names` keeps UUIDs, not names.
|
||||
|
||||
bool empty() const { return names.empty() && !current_user && !all; }
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
|
||||
String getID(char) const override { return "ExtendedRoleSet"; }
|
||||
ASTPtr clone() const override { return std::make_shared<ASTExtendedRoleSet>(*this); }
|
||||
|
@ -64,9 +64,9 @@ ASTPtr ASTFunctionWithKeyValueArguments::clone() const
|
||||
|
||||
void ASTFunctionWithKeyValueArguments::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << Poco::toUpper(name) << (settings.hilite ? hilite_none : "") << "(";
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << Poco::toUpper(name) << (settings.hilite ? hilite_none : "") << (has_brackets ? "(" : "");
|
||||
elements->formatImpl(settings, state, frame);
|
||||
settings.ostr << ")";
|
||||
settings.ostr << (has_brackets ? ")" : "");
|
||||
settings.ostr << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,13 @@ public:
|
||||
String name;
|
||||
/// Expression list
|
||||
ASTPtr elements;
|
||||
/// Has brackets around arguments
|
||||
bool has_brackets;
|
||||
|
||||
ASTFunctionWithKeyValueArguments(bool has_brackets_ = true)
|
||||
: has_brackets(has_brackets_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
String getID(char delim) const override;
|
||||
|
@ -122,19 +122,22 @@ ASTPtr ASTGrantQuery::clone() const
|
||||
void ASTGrantQuery::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << (attach ? "ATTACH " : "") << ((kind == Kind::GRANT) ? "GRANT" : "REVOKE")
|
||||
<< (settings.hilite ? IAST::hilite_none : "") << " ";
|
||||
<< (settings.hilite ? IAST::hilite_none : "");
|
||||
|
||||
formatOnCluster(settings);
|
||||
|
||||
if (kind == Kind::REVOKE)
|
||||
{
|
||||
if (grant_option)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "GRANT OPTION FOR " << (settings.hilite ? hilite_none : "");
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " GRANT OPTION FOR" << (settings.hilite ? hilite_none : "");
|
||||
else if (admin_option)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ADMIN OPTION FOR " << (settings.hilite ? hilite_none : "");
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " ADMIN OPTION FOR" << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
|
||||
if ((!!roles + !access_rights_elements.empty()) != 1)
|
||||
throw Exception("Either roles or access rights elements should be set", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
settings.ostr << " ";
|
||||
if (roles)
|
||||
roles->format(settings);
|
||||
else
|
||||
@ -150,4 +153,11 @@ void ASTGrantQuery::formatImpl(const FormatSettings & settings, FormatState &, F
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH ADMIN OPTION" << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ASTGrantQuery::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (to_roles)
|
||||
to_roles->replaceCurrentUserTagWithName(current_user_name);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Access/AccessRightsElement.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -15,7 +16,7 @@ class ASTExtendedRoleSet;
|
||||
* GRANT role [,...] TO {user_name | role_name | CURRENT_USER} [,...] [WITH ADMIN OPTION]
|
||||
* REVOKE [ADMIN OPTION FOR] role [,...] FROM {user_name | role_name | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...]
|
||||
*/
|
||||
class ASTGrantQuery : public IAST
|
||||
class ASTGrantQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
enum class Kind
|
||||
@ -34,5 +35,7 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTGrantQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -1400,18 +1400,30 @@ bool ParserFunctionWithKeyValueArguments::parseImpl(Pos & pos, ASTPtr & node, Ex
|
||||
if (!id_parser.parse(pos, identifier, expected))
|
||||
return false;
|
||||
|
||||
if (pos.get().type != TokenType::OpeningRoundBracket)
|
||||
return false;
|
||||
|
||||
++pos;
|
||||
bool left_bracket_found = false;
|
||||
if (pos.get().type != TokenType::OpeningRoundBracket)
|
||||
{
|
||||
if (!brackets_can_be_omitted)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++pos;
|
||||
left_bracket_found = true;
|
||||
}
|
||||
|
||||
if (!pairs_list_parser.parse(pos, expr_list_args, expected))
|
||||
return false;
|
||||
|
||||
if (pos.get().type != TokenType::ClosingRoundBracket)
|
||||
return false;
|
||||
if (left_bracket_found)
|
||||
{
|
||||
if (pos.get().type != TokenType::ClosingRoundBracket)
|
||||
return false;
|
||||
++pos;
|
||||
}
|
||||
|
||||
++pos;
|
||||
auto function = std::make_shared<ASTFunctionWithKeyValueArguments>();
|
||||
auto function = std::make_shared<ASTFunctionWithKeyValueArguments>(left_bracket_found);
|
||||
function->name = Poco::toLower(typeid_cast<ASTIdentifier &>(*identifier.get()).name);
|
||||
function->elements = expr_list_args;
|
||||
function->children.push_back(function->elements);
|
||||
|
@ -346,9 +346,16 @@ protected:
|
||||
*/
|
||||
class ParserFunctionWithKeyValueArguments : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserFunctionWithKeyValueArguments(bool brackets_can_be_omitted_ = false)
|
||||
: brackets_can_be_omitted(brackets_can_be_omitted_) {}
|
||||
protected:
|
||||
|
||||
const char * getName() const override { return "function with key-value arguments"; }
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||
|
||||
/// brackets for function arguments can be omitted
|
||||
bool brackets_can_be_omitted;
|
||||
};
|
||||
|
||||
/** Data type or table engine, possibly with parameters. For example, UInt8 or see examples from ParserIdentifierWithParameters
|
||||
|
@ -238,6 +238,13 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_name;
|
||||
std::optional<KeyType> key_type;
|
||||
std::vector<ASTCreateQuotaQuery::Limits> all_limits;
|
||||
@ -266,6 +273,7 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->new_name = std::move(new_name);
|
||||
query->key_type = key_type;
|
||||
|
@ -80,6 +80,13 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
if (!parseRoleName(pos, expected, name))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_name;
|
||||
std::shared_ptr<ASTSettingsProfileElements> settings;
|
||||
while (true)
|
||||
@ -101,6 +108,7 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->new_name = std::move(new_name);
|
||||
query->settings = std::move(settings);
|
||||
|
@ -243,6 +243,13 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
|| !parseDatabaseAndTableName(pos, expected, database, table_name))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_policy_name;
|
||||
std::optional<bool> is_restrictive;
|
||||
std::vector<std::pair<ConditionType, ASTPtr>> conditions;
|
||||
@ -272,6 +279,7 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name_parts = std::move(name_parts);
|
||||
query->new_policy_name = std::move(new_policy_name);
|
||||
query->is_restrictive = is_restrictive;
|
||||
|
@ -96,6 +96,13 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_name;
|
||||
std::shared_ptr<ASTSettingsProfileElements> settings;
|
||||
while (true)
|
||||
@ -120,6 +127,7 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->new_name = std::move(new_name);
|
||||
query->settings = std::move(settings);
|
||||
|
@ -23,7 +23,7 @@ namespace ErrorCodes
|
||||
|
||||
namespace
|
||||
{
|
||||
bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name, String & new_host_pattern)
|
||||
bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name, std::optional<String> & new_host_pattern)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
@ -286,12 +286,19 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
}
|
||||
|
||||
String name;
|
||||
String host_pattern;
|
||||
std::optional<String> host_pattern;
|
||||
if (!parseUserName(pos, expected, name, host_pattern))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_name;
|
||||
String new_host_pattern;
|
||||
std::optional<String> new_host_pattern;
|
||||
std::optional<Authentication> authentication;
|
||||
std::optional<AllowedClientHosts> hosts;
|
||||
std::optional<AllowedClientHosts> add_hosts;
|
||||
@ -318,7 +325,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
if (new_name.empty() && parseRenameTo(pos, expected, new_name, new_host_pattern))
|
||||
continue;
|
||||
|
||||
if (parseHosts(pos, expected, "ADD", add_hosts) || parseHosts(pos, expected, "REMOVE", remove_hosts))
|
||||
if (parseHosts(pos, expected, "ADD", add_hosts) || parseHosts(pos, expected, "DROP", remove_hosts))
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -327,10 +334,10 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
|
||||
if (!hosts)
|
||||
{
|
||||
if (!alter)
|
||||
hosts.emplace().addLikePattern(host_pattern);
|
||||
else if (alter && !new_name.empty())
|
||||
hosts.emplace().addLikePattern(new_host_pattern);
|
||||
if (!alter && host_pattern)
|
||||
hosts.emplace().addLikePattern(*host_pattern);
|
||||
else if (alter && new_host_pattern)
|
||||
hosts.emplace().addLikePattern(*new_host_pattern);
|
||||
}
|
||||
|
||||
auto query = std::make_shared<ASTCreateUserQuery>();
|
||||
@ -341,6 +348,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->new_name = std::move(new_name);
|
||||
query->authentication = std::move(authentication);
|
||||
|
@ -14,7 +14,7 @@ namespace DB
|
||||
* ALTER USER [IF EXISTS] name
|
||||
* [RENAME TO new_name]
|
||||
* [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}]
|
||||
* [[ADD|REMOVE] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
|
||||
* [[ADD|DROP] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
|
||||
* [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
|
||||
*/
|
||||
class ParserCreateUserQuery : public IParserBase
|
||||
|
@ -109,7 +109,7 @@ bool ParserDictionaryRange::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
|
||||
bool ParserDictionaryLayout::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
ParserFunctionWithKeyValueArguments key_value_func_p;
|
||||
ParserFunctionWithKeyValueArguments key_value_func_p(/* brackets_can_be_omitted = */ true);
|
||||
ASTPtr ast_func;
|
||||
if (!key_value_func_p.parse(pos, ast_func, expected))
|
||||
return false;
|
||||
@ -121,12 +121,17 @@ bool ParserDictionaryLayout::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
|
||||
return false;
|
||||
|
||||
res->layout_type = func.name;
|
||||
res->has_brackets = func.has_brackets;
|
||||
const ASTExpressionList & type_expr_list = func.elements->as<const ASTExpressionList &>();
|
||||
|
||||
/// there are no layout with more than 1 parameter
|
||||
if (type_expr_list.children.size() > 1)
|
||||
return false;
|
||||
|
||||
/// if layout has params than brackets must be specified
|
||||
if (!type_expr_list.children.empty() && !res->has_brackets)
|
||||
return false;
|
||||
|
||||
if (type_expr_list.children.size() == 1)
|
||||
{
|
||||
const ASTPair * pair = dynamic_cast<const ASTPair *>(type_expr_list.children.at(0).get());
|
||||
|
@ -117,10 +117,18 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
return false;
|
||||
}
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
auto query = std::make_shared<ASTDropAccessEntityQuery>(kind);
|
||||
node = query;
|
||||
|
||||
query->if_exists = if_exists;
|
||||
query->cluster = std::move(cluster);
|
||||
query->names = std::move(names);
|
||||
query->row_policies_names = std::move(row_policies_names);
|
||||
|
||||
|
@ -17,15 +17,6 @@ namespace ErrorCodes
|
||||
|
||||
namespace
|
||||
{
|
||||
bool parseRoundBrackets(IParser::Pos & pos, Expected & expected)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
return ParserToken{TokenType::OpeningRoundBracket}.ignore(pos, expected)
|
||||
&& ParserToken{TokenType::ClosingRoundBracket}.ignore(pos, expected);
|
||||
});
|
||||
}
|
||||
|
||||
bool parseAccessFlags(IParser::Pos & pos, Expected & expected, AccessFlags & access_flags)
|
||||
{
|
||||
static constexpr auto is_one_of_access_type_words = [](IParser::Pos & pos_)
|
||||
@ -63,7 +54,6 @@ namespace
|
||||
return false;
|
||||
}
|
||||
|
||||
parseRoundBrackets(pos, expected);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -269,6 +259,13 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
else
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
bool grant_option = false;
|
||||
bool admin_option = false;
|
||||
if (kind == Kind::REVOKE)
|
||||
@ -306,6 +303,7 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
|
||||
query->kind = kind;
|
||||
query->attach = attach;
|
||||
query->cluster = std::move(cluster);
|
||||
query->access_rights_elements = std::move(elements);
|
||||
query->roles = std::move(roles);
|
||||
query->to_roles = std::move(to_roles);
|
||||
|
@ -3,48 +3,39 @@
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, std::optional<String> & host_like_pattern)
|
||||
{
|
||||
bool parseUserNameImpl(IParser::Pos & pos, Expected & expected, String & user_name, String * host_like_pattern)
|
||||
String name;
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
return false;
|
||||
|
||||
boost::algorithm::trim(name);
|
||||
|
||||
std::optional<String> pattern;
|
||||
if (ParserToken{TokenType::At}.ignore(pos, expected))
|
||||
{
|
||||
String name;
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, pattern.emplace()))
|
||||
return false;
|
||||
|
||||
boost::algorithm::trim(name);
|
||||
|
||||
String pattern = "@";
|
||||
|
||||
if (ParserToken{TokenType::At}.ignore(pos, expected))
|
||||
{
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, pattern))
|
||||
return false;
|
||||
|
||||
boost::algorithm::trim(pattern);
|
||||
}
|
||||
|
||||
if (pattern != "@")
|
||||
name += '@' + pattern;
|
||||
|
||||
user_name = std::move(name);
|
||||
if (host_like_pattern)
|
||||
*host_like_pattern = std::move(pattern);
|
||||
return true;
|
||||
boost::algorithm::trim(*pattern);
|
||||
}
|
||||
|
||||
if (pattern && (pattern != "%"))
|
||||
name += '@' + *pattern;
|
||||
|
||||
user_name = std::move(name);
|
||||
host_like_pattern = std::move(pattern);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name)
|
||||
{
|
||||
return parseUserNameImpl(pos, expected, user_name, nullptr);
|
||||
}
|
||||
|
||||
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, String & host_like_pattern)
|
||||
{
|
||||
return parseUserNameImpl(pos, expected, user_name, &host_like_pattern);
|
||||
std::optional<String> unused_pattern;
|
||||
return parseUserName(pos, expected, user_name, unused_pattern);
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@ namespace DB
|
||||
/// The `host` can be an ip address, ip subnet, or a host name.
|
||||
/// The % and _ wildcard characters are permitted in `host`.
|
||||
/// These have the same meaning as for pattern-matching operations performed with the LIKE operator.
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, String & host_like_pattern);
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, std::optional<String> & host_like_pattern);
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name);
|
||||
|
||||
/// Parses either a user name or the 'CURRENT_USER' keyword (or some of the aliases).
|
||||
|
@ -96,7 +96,7 @@ bool PipelineExecutor::addEdges(UInt64 node)
|
||||
{
|
||||
const IProcessor * proc = &it->getOutputPort().getProcessor();
|
||||
auto output_port_number = proc->getOutputPortNumber(&it->getOutputPort());
|
||||
add_edge(*it, proc, graph[node].backEdges, true, from_input, output_port_number, &graph[node].post_updated_input_ports);
|
||||
add_edge(*it, proc, graph[node].backEdges, true, from_input, output_port_number, graph[node].post_updated_input_ports.get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ bool PipelineExecutor::addEdges(UInt64 node)
|
||||
{
|
||||
const IProcessor * proc = &it->getInputPort().getProcessor();
|
||||
auto input_port_number = proc->getInputPortNumber(&it->getInputPort());
|
||||
add_edge(*it, proc, graph[node].directEdges, false, input_port_number, from_output, &graph[node].post_updated_output_ports);
|
||||
add_edge(*it, proc, graph[node].directEdges, false, input_port_number, from_output, graph[node].post_updated_output_ports.get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ bool PipelineExecutor::expandPipeline(Stack & stack, UInt64 pid)
|
||||
|
||||
if (addEdges(node))
|
||||
{
|
||||
std::lock_guard guard(graph[node].status_mutex);
|
||||
std::lock_guard guard(*graph[node].status_mutex);
|
||||
|
||||
for (; num_back_edges < graph[node].backEdges.size(); ++num_back_edges)
|
||||
graph[node].updated_input_ports.emplace_back(num_back_edges);
|
||||
@ -246,7 +246,7 @@ bool PipelineExecutor::tryAddProcessorToStackIfUpdated(Edge & edge, Queue & queu
|
||||
|
||||
auto & node = graph[edge.to];
|
||||
|
||||
std::unique_lock lock(node.status_mutex);
|
||||
std::unique_lock lock(*node.status_mutex);
|
||||
|
||||
ExecStatus status = node.status;
|
||||
|
||||
@ -340,22 +340,22 @@ bool PipelineExecutor::prepareProcessor(UInt64 pid, size_t thread_number, Queue
|
||||
}
|
||||
|
||||
{
|
||||
for (auto & edge_id : node.post_updated_input_ports)
|
||||
for (auto & edge_id : *node.post_updated_input_ports)
|
||||
{
|
||||
auto edge = static_cast<Edge *>(edge_id);
|
||||
updated_back_edges.emplace_back(edge);
|
||||
edge->update_info.trigger();
|
||||
}
|
||||
|
||||
for (auto & edge_id : node.post_updated_output_ports)
|
||||
for (auto & edge_id : *node.post_updated_output_ports)
|
||||
{
|
||||
auto edge = static_cast<Edge *>(edge_id);
|
||||
updated_direct_edges.emplace_back(edge);
|
||||
edge->update_info.trigger();
|
||||
}
|
||||
|
||||
node.post_updated_input_ports.clear();
|
||||
node.post_updated_output_ports.clear();
|
||||
node.post_updated_input_ports->clear();
|
||||
node.post_updated_output_ports->clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,7 +402,7 @@ bool PipelineExecutor::prepareProcessor(UInt64 pid, size_t thread_number, Queue
|
||||
while (!stack.empty())
|
||||
{
|
||||
auto item = stack.top();
|
||||
if (!prepareProcessor(item, thread_number, queue, std::unique_lock<std::mutex>(graph[item].status_mutex)))
|
||||
if (!prepareProcessor(item, thread_number, queue, std::unique_lock<std::mutex>(*graph[item].status_mutex)))
|
||||
return false;
|
||||
|
||||
stack.pop();
|
||||
@ -519,7 +519,7 @@ void PipelineExecutor::executeSingleThread(size_t thread_num, size_t num_threads
|
||||
|
||||
auto prepare_processor = [&](UInt64 pid, Queue & queue)
|
||||
{
|
||||
if (!prepareProcessor(pid, thread_num, queue, std::unique_lock<std::mutex>(graph[pid].status_mutex)))
|
||||
if (!prepareProcessor(pid, thread_num, queue, std::unique_lock<std::mutex>(*graph[pid].status_mutex)))
|
||||
finish();
|
||||
};
|
||||
|
||||
@ -729,7 +729,7 @@ void PipelineExecutor::executeImpl(size_t num_threads)
|
||||
UInt64 proc = stack.top();
|
||||
stack.pop();
|
||||
|
||||
prepareProcessor(proc, 0, queue, std::unique_lock<std::mutex>(graph[proc].status_mutex));
|
||||
prepareProcessor(proc, 0, queue, std::unique_lock<std::mutex>(*graph[proc].status_mutex));
|
||||
|
||||
while (!queue.empty())
|
||||
{
|
||||
|
@ -104,10 +104,10 @@ private:
|
||||
Edges backEdges;
|
||||
|
||||
ExecStatus status;
|
||||
std::mutex status_mutex;
|
||||
std::unique_ptr<std::mutex> status_mutex;
|
||||
|
||||
std::vector<void *> post_updated_input_ports;
|
||||
std::vector<void *> post_updated_output_ports;
|
||||
std::unique_ptr<Port::UpdateInfo::UpdateList> post_updated_input_ports;
|
||||
std::unique_ptr<Port::UpdateInfo::UpdateList> post_updated_output_ports;
|
||||
|
||||
/// Last state for profiling.
|
||||
IProcessor::Status last_processor_status = IProcessor::Status::NeedData;
|
||||
@ -124,12 +124,10 @@ private:
|
||||
execution_state->processor = processor;
|
||||
execution_state->processors_id = processor_id;
|
||||
execution_state->has_quota = processor->hasQuota();
|
||||
}
|
||||
|
||||
Node(Node && other) noexcept
|
||||
: processor(other.processor), status(other.status)
|
||||
, execution_state(std::move(other.execution_state))
|
||||
{
|
||||
status_mutex = std::make_unique<std::mutex>();
|
||||
post_updated_input_ports = std::make_unique<Port::UpdateInfo::UpdateList>();
|
||||
post_updated_output_ports = std::make_unique<Port::UpdateInfo::UpdateList>();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -30,7 +30,9 @@ class Port
|
||||
public:
|
||||
struct UpdateInfo
|
||||
{
|
||||
std::vector<void *> * update_list = nullptr;
|
||||
using UpdateList = std::vector<void *>;
|
||||
|
||||
UpdateList * update_list = nullptr;
|
||||
void * id = nullptr;
|
||||
UInt64 version = 0;
|
||||
UInt64 prev_version = 0;
|
||||
|
@ -305,7 +305,9 @@ ThreadPool::Job DistributedBlockOutputStream::runWritingJob(DistributedBlockOutp
|
||||
job.local_context = std::make_unique<Context>(context);
|
||||
|
||||
InterpreterInsertQuery interp(query_ast, *job.local_context);
|
||||
job.stream = interp.execute().out;
|
||||
auto block_io = interp.execute();
|
||||
assertBlocksHaveEqualStructure(block_io.out->getHeader(), shard_block, "flushing shard block for " + storage.getStorageID().getNameForLogs());
|
||||
job.stream = block_io.out;
|
||||
job.stream->writePrefix();
|
||||
}
|
||||
|
||||
@ -544,6 +546,9 @@ void DistributedBlockOutputStream::writeToLocal(const Block & block, const size_
|
||||
InterpreterInsertQuery interp(query_ast, context);
|
||||
|
||||
auto block_io = interp.execute();
|
||||
|
||||
assertBlocksHaveEqualStructure(block_io.out->getHeader(), block, "flushing " + storage.getStorageID().getNameForLogs());
|
||||
|
||||
block_io.out->writePrefix();
|
||||
|
||||
for (size_t i = 0; i < repeats; ++i)
|
||||
|
@ -218,9 +218,18 @@ public:
|
||||
*
|
||||
* SelectQueryInfo is required since the stage can depends on the query
|
||||
* (see Distributed() engine and optimize_skip_unused_shards).
|
||||
*
|
||||
* QueryProcessingStage::Enum required for Distributed over Distributed,
|
||||
* since it cannot return Complete for intermediate queries never.
|
||||
*/
|
||||
QueryProcessingStage::Enum getQueryProcessingStage(const Context & context) const { return getQueryProcessingStage(context, {}); }
|
||||
virtual QueryProcessingStage::Enum getQueryProcessingStage(const Context &, const ASTPtr &) const { return QueryProcessingStage::FetchColumns; }
|
||||
QueryProcessingStage::Enum getQueryProcessingStage(const Context & context) const
|
||||
{
|
||||
return getQueryProcessingStage(context, QueryProcessingStage::Complete, {});
|
||||
}
|
||||
virtual QueryProcessingStage::Enum getQueryProcessingStage(const Context &, QueryProcessingStage::Enum /*to_stage*/, const ASTPtr &) const
|
||||
{
|
||||
return QueryProcessingStage::FetchColumns;
|
||||
}
|
||||
|
||||
/** Watch live changes to the table.
|
||||
* Accepts a list of columns to read, as well as a description of the query,
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
return std::make_shared<StorageBlocks>(table_id, columns, std::move(pipes), to_stage);
|
||||
}
|
||||
std::string getName() const override { return "Blocks"; }
|
||||
QueryProcessingStage::Enum getQueryProcessingStage(const Context &, const ASTPtr &) const override { return to_stage; }
|
||||
QueryProcessingStage::Enum getQueryProcessingStage(const Context &, QueryProcessingStage::Enum /*to_stage*/, const ASTPtr &) const override { return to_stage; }
|
||||
|
||||
Pipes read(
|
||||
const Names & /*column_names*/,
|
||||
|
@ -63,6 +63,7 @@ IMergeTreeDataPart::Checksums checkDataPart(
|
||||
/// Real checksums based on contents of data. Must correspond to checksums.txt. If not - it means the data is broken.
|
||||
IMergeTreeDataPart::Checksums checksums_data;
|
||||
|
||||
/// This function calculates checksum for both compressed and decompressed contents of compressed file.
|
||||
auto checksum_compressed_file = [](const DiskPtr & disk_, const String & file_path)
|
||||
{
|
||||
auto file_buf = disk_->readFile(file_path);
|
||||
@ -78,6 +79,7 @@ IMergeTreeDataPart::Checksums checkDataPart(
|
||||
};
|
||||
};
|
||||
|
||||
/// First calculate checksums for columns data
|
||||
if (part_type == MergeTreeDataPartType::COMPACT)
|
||||
{
|
||||
const auto & file_name = MergeTreeDataPartCompact::DATA_FILE_NAME_WITH_EXTENSION;
|
||||
@ -99,20 +101,7 @@ IMergeTreeDataPart::Checksums checkDataPart(
|
||||
throw Exception("Unknown type in part " + path, ErrorCodes::UNKNOWN_PART_TYPE);
|
||||
}
|
||||
|
||||
for (auto it = disk->iterateDirectory(path); it->isValid(); it->next())
|
||||
{
|
||||
const String & file_name = it->name();
|
||||
auto checksum_it = checksums_data.files.find(file_name);
|
||||
if (checksum_it == checksums_data.files.end() && file_name != "checksums.txt" && file_name != "columns.txt")
|
||||
{
|
||||
auto file_buf = disk->readFile(it->path());
|
||||
HashingReadBuffer hashing_buf(*file_buf);
|
||||
hashing_buf.tryIgnore(std::numeric_limits<size_t>::max());
|
||||
checksums_data.files[file_name] = IMergeTreeDataPart::Checksums::Checksum(hashing_buf.count(), hashing_buf.getHash());
|
||||
}
|
||||
}
|
||||
|
||||
/// Checksums from file checksums.txt. May be absent. If present, they are subsequently compared with the actual data checksums.
|
||||
/// Checksums from the rest files listed in checksums.txt. May be absent. If present, they are subsequently compared with the actual data checksums.
|
||||
IMergeTreeDataPart::Checksums checksums_txt;
|
||||
|
||||
if (require_checksums || disk->exists(path + "checksums.txt"))
|
||||
@ -122,6 +111,31 @@ IMergeTreeDataPart::Checksums checkDataPart(
|
||||
assertEOF(*buf);
|
||||
}
|
||||
|
||||
const auto & checksum_files_txt = checksums_txt.files;
|
||||
for (auto it = disk->iterateDirectory(path); it->isValid(); it->next())
|
||||
{
|
||||
const String & file_name = it->name();
|
||||
auto checksum_it = checksums_data.files.find(file_name);
|
||||
|
||||
/// Skip files that we already calculated. Also skip metadata files that are not checksummed.
|
||||
if (checksum_it == checksums_data.files.end() && file_name != "checksums.txt" && file_name != "columns.txt")
|
||||
{
|
||||
auto txt_checksum_it = checksum_files_txt.find(file_name);
|
||||
if (txt_checksum_it == checksum_files_txt.end() || txt_checksum_it->second.uncompressed_size == 0)
|
||||
{
|
||||
/// The file is not compressed.
|
||||
auto file_buf = disk->readFile(it->path());
|
||||
HashingReadBuffer hashing_buf(*file_buf);
|
||||
hashing_buf.tryIgnore(std::numeric_limits<size_t>::max());
|
||||
checksums_data.files[file_name] = IMergeTreeDataPart::Checksums::Checksum(hashing_buf.count(), hashing_buf.getHash());
|
||||
}
|
||||
else /// If we have both compressed and uncompressed in txt, than calculate them
|
||||
{
|
||||
checksums_data.files[file_name] = checksum_compressed_file(disk, it->path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_cancelled())
|
||||
return {};
|
||||
|
||||
|
@ -135,7 +135,7 @@ private:
|
||||
};
|
||||
|
||||
|
||||
QueryProcessingStage::Enum StorageBuffer::getQueryProcessingStage(const Context & context, const ASTPtr & query_ptr) const
|
||||
QueryProcessingStage::Enum StorageBuffer::getQueryProcessingStage(const Context & context, QueryProcessingStage::Enum to_stage, const ASTPtr & query_ptr) const
|
||||
{
|
||||
if (destination_id)
|
||||
{
|
||||
@ -144,7 +144,7 @@ QueryProcessingStage::Enum StorageBuffer::getQueryProcessingStage(const Context
|
||||
if (destination.get() == this)
|
||||
throw Exception("Destination table is myself. Read will cause infinite loop.", ErrorCodes::INFINITE_LOOP);
|
||||
|
||||
return destination->getQueryProcessingStage(context, query_ptr);
|
||||
return destination->getQueryProcessingStage(context, to_stage, query_ptr);
|
||||
}
|
||||
|
||||
return QueryProcessingStage::FetchColumns;
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
|
||||
std::string getName() const override { return "Buffer"; }
|
||||
|
||||
QueryProcessingStage::Enum getQueryProcessingStage(const Context & context, const ASTPtr &) const override;
|
||||
QueryProcessingStage::Enum getQueryProcessingStage(const Context &, QueryProcessingStage::Enum /*to_stage*/, const ASTPtr &) const override;
|
||||
|
||||
Pipes read(
|
||||
const Names & column_names,
|
||||
|
@ -242,6 +242,24 @@ void replaceConstantExpressions(ASTPtr & node, const Context & context, const Na
|
||||
visitor.visit(node);
|
||||
}
|
||||
|
||||
QueryProcessingStage::Enum getQueryProcessingStageImpl(const Context & context, QueryProcessingStage::Enum to_stage, const ClusterPtr & cluster)
|
||||
{
|
||||
const Settings & settings = context.getSettingsRef();
|
||||
|
||||
size_t num_local_shards = cluster->getLocalShardCount();
|
||||
size_t num_remote_shards = cluster->getRemoteShardCount();
|
||||
size_t result_size = (num_remote_shards * settings.max_parallel_replicas) + num_local_shards;
|
||||
|
||||
if (settings.distributed_group_by_no_merge)
|
||||
return QueryProcessingStage::Complete;
|
||||
/// Nested distributed query cannot return Complete stage,
|
||||
/// since the parent query need to aggregate the results after.
|
||||
if (to_stage == QueryProcessingStage::WithMergeableState)
|
||||
return QueryProcessingStage::WithMergeableState;
|
||||
return result_size == 1 ? QueryProcessingStage::Complete
|
||||
: QueryProcessingStage::WithMergeableState;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -360,25 +378,10 @@ StoragePtr StorageDistributed::createWithOwnCluster(
|
||||
}
|
||||
|
||||
|
||||
static QueryProcessingStage::Enum getQueryProcessingStageImpl(const Context & context, const ClusterPtr & cluster)
|
||||
{
|
||||
const Settings & settings = context.getSettingsRef();
|
||||
|
||||
size_t num_local_shards = cluster->getLocalShardCount();
|
||||
size_t num_remote_shards = cluster->getRemoteShardCount();
|
||||
size_t result_size = (num_remote_shards * settings.max_parallel_replicas) + num_local_shards;
|
||||
|
||||
if (settings.distributed_group_by_no_merge)
|
||||
return QueryProcessingStage::Complete;
|
||||
else /// Normal mode.
|
||||
return result_size == 1 ? QueryProcessingStage::Complete
|
||||
: QueryProcessingStage::WithMergeableState;
|
||||
}
|
||||
|
||||
QueryProcessingStage::Enum StorageDistributed::getQueryProcessingStage(const Context & context, const ASTPtr & query_ptr) const
|
||||
QueryProcessingStage::Enum StorageDistributed::getQueryProcessingStage(const Context &context, QueryProcessingStage::Enum to_stage, const ASTPtr &query_ptr) const
|
||||
{
|
||||
auto cluster = getOptimizedCluster(context, query_ptr);
|
||||
return getQueryProcessingStageImpl(context, cluster);
|
||||
return getQueryProcessingStageImpl(context, to_stage, cluster);
|
||||
}
|
||||
|
||||
Pipes StorageDistributed::read(
|
||||
@ -807,6 +810,9 @@ void registerStorageDistributed(StorageFactory & factory)
|
||||
storage_policy,
|
||||
args.relative_data_path,
|
||||
args.attach);
|
||||
},
|
||||
{
|
||||
.source_access_type = AccessType::REMOTE,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ public:
|
||||
|
||||
bool isRemote() const override { return true; }
|
||||
|
||||
QueryProcessingStage::Enum getQueryProcessingStage(const Context & context, const ASTPtr &) const override;
|
||||
QueryProcessingStage::Enum getQueryProcessingStage(const Context &, QueryProcessingStage::Enum /*to_stage*/, const ASTPtr &) const override;
|
||||
|
||||
Pipes read(
|
||||
const Names & column_names,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user