#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int NOT_IMPLEMENTED; } namespace { ASTPtr getCreateQueryImpl( const User & user, const AccessControlManager * manager /* not used if attach_mode == true */, bool attach_mode) { auto query = std::make_shared(); query->names = std::make_shared(); query->names->push_back(user.getName()); query->attach = attach_mode; if (user.allowed_client_hosts != AllowedClientHosts::AnyHostTag{}) query->hosts = user.allowed_client_hosts; if (user.default_roles != RolesOrUsersSet::AllTag{}) { if (attach_mode) query->default_roles = user.default_roles.toAST(); else query->default_roles = user.default_roles.toASTWithNames(*manager); } if (user.authentication.getType() != Authentication::NO_PASSWORD) { query->authentication = user.authentication; query->show_password = attach_mode; /// We don't show password unless it's an ATTACH statement. } if (!user.settings.empty()) { if (attach_mode) query->settings = user.settings.toAST(); else query->settings = user.settings.toASTWithNames(*manager); } if (user.grantees != RolesOrUsersSet::AllTag{}) { if (attach_mode) query->grantees = user.grantees.toAST(); else query->grantees = user.grantees.toASTWithNames(*manager); query->grantees->use_keyword_any = true; } return query; } ASTPtr getCreateQueryImpl(const Role & role, const AccessControlManager * manager, bool attach_mode) { auto query = std::make_shared(); query->names.emplace_back(role.getName()); query->attach = attach_mode; if (!role.settings.empty()) { if (attach_mode) query->settings = role.settings.toAST(); else query->settings = role.settings.toASTWithNames(*manager); } return query; } ASTPtr getCreateQueryImpl(const SettingsProfile & profile, const AccessControlManager * manager, bool attach_mode) { auto query = std::make_shared(); query->names.emplace_back(profile.getName()); query->attach = attach_mode; if (!profile.elements.empty()) { if (attach_mode) query->settings = profile.elements.toAST(); else query->settings = profile.elements.toASTWithNames(*manager); if (query->settings) query->settings->setUseInheritKeyword(true); } if (!profile.to_roles.empty()) { if (attach_mode) query->to_roles = profile.to_roles.toAST(); else query->to_roles = profile.to_roles.toASTWithNames(*manager); } return query; } ASTPtr getCreateQueryImpl( const Quota & quota, const AccessControlManager * manager /* not used if attach_mode == true */, bool attach_mode) { auto query = std::make_shared(); query->names.emplace_back(quota.getName()); query->attach = attach_mode; if (quota.key_type != Quota::KeyType::NONE) query->key_type = quota.key_type; query->all_limits.reserve(quota.all_limits.size()); for (const auto & limits : quota.all_limits) { ASTCreateQuotaQuery::Limits create_query_limits; create_query_limits.duration = limits.duration; create_query_limits.randomize_interval = limits.randomize_interval; for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE)) create_query_limits.max[resource_type] = limits.max[resource_type]; query->all_limits.push_back(create_query_limits); } if (!quota.to_roles.empty()) { if (attach_mode) query->roles = quota.to_roles.toAST(); else query->roles = quota.to_roles.toASTWithNames(*manager); } return query; } ASTPtr getCreateQueryImpl( const RowPolicy & policy, const AccessControlManager * manager /* not used if attach_mode == true */, bool attach_mode) { auto query = std::make_shared(); query->names = std::make_shared(); query->names->name_parts.emplace_back(policy.getNameParts()); query->attach = attach_mode; if (policy.isRestrictive()) query->is_restrictive = policy.isRestrictive(); for (auto type : ext::range(RowPolicy::MAX_CONDITION_TYPE)) { const auto & condition = policy.conditions[static_cast(type)]; if (!condition.empty()) { ParserExpression parser; ASTPtr expr = parseQuery(parser, condition, 0, DBMS_DEFAULT_MAX_PARSER_DEPTH); query->conditions.emplace_back(type, std::move(expr)); } } if (!policy.to_roles.empty()) { if (attach_mode) query->roles = policy.to_roles.toAST(); else query->roles = policy.to_roles.toASTWithNames(*manager); } return query; } ASTPtr getCreateQueryImpl( const IAccessEntity & entity, const AccessControlManager * manager /* not used if attach_mode == true */, bool attach_mode) { if (const User * user = typeid_cast(&entity)) return getCreateQueryImpl(*user, manager, attach_mode); if (const Role * role = typeid_cast(&entity)) return getCreateQueryImpl(*role, manager, attach_mode); if (const RowPolicy * policy = typeid_cast(&entity)) return getCreateQueryImpl(*policy, manager, attach_mode); if (const Quota * quota = typeid_cast(&entity)) return getCreateQueryImpl(*quota, manager, attach_mode); if (const SettingsProfile * profile = typeid_cast(&entity)) return getCreateQueryImpl(*profile, manager, attach_mode); throw Exception(entity.outputTypeAndName() + ": type is not supported by SHOW CREATE query", ErrorCodes::NOT_IMPLEMENTED); } using EntityType = IAccessEntity::Type; } InterpreterShowCreateAccessEntityQuery::InterpreterShowCreateAccessEntityQuery(const ASTPtr & query_ptr_, const Context & context_) : query_ptr(query_ptr_), context(context_) { } BlockIO InterpreterShowCreateAccessEntityQuery::execute() { BlockIO res; res.in = executeImpl(); return res; } BlockInputStreamPtr InterpreterShowCreateAccessEntityQuery::executeImpl() { /// Build a create queries. ASTs create_queries = getCreateQueries(); /// Build the result column. MutableColumnPtr column = ColumnString::create(); WriteBufferFromOwnString create_query_buf; for (const auto & create_query : create_queries) { formatAST(*create_query, create_query_buf, false, true); column->insert(create_query_buf.str()); create_query_buf.restart(); } /// Prepare description of the result column. WriteBufferFromOwnString desc_buf; const auto & show_query = query_ptr->as(); formatAST(show_query, desc_buf, false, true); String desc = desc_buf.str(); String prefix = "SHOW "; if (startsWith(desc, prefix)) desc = desc.substr(prefix.length()); /// `desc` always starts with "SHOW ", so we can trim this prefix. return std::make_shared(Block{{std::move(column), std::make_shared(), desc}}); } std::vector InterpreterShowCreateAccessEntityQuery::getEntities() const { auto & show_query = query_ptr->as(); const auto & access_control = context.getAccessControlManager(); context.checkAccess(getRequiredAccess()); show_query.replaceEmptyDatabase(context.getCurrentDatabase()); std::vector entities; if (show_query.all) { auto ids = access_control.findAll(show_query.type); for (const auto & id : ids) { if (auto entity = access_control.tryRead(id)) entities.push_back(entity); } } else if (show_query.current_user) { if (auto user = context.getUser()) entities.push_back(user); } else if (show_query.current_quota) { auto usage = context.getQuotaUsage(); if (usage) entities.push_back(access_control.read(usage->quota_id)); } else if (show_query.type == EntityType::ROW_POLICY) { auto ids = access_control.findAll(); if (show_query.row_policy_names) { for (const String & name : show_query.row_policy_names->toStrings()) entities.push_back(access_control.read(name)); } else { for (const auto & id : ids) { auto policy = access_control.tryRead(id); if (!policy) continue; if (!show_query.short_name.empty() && (policy->getShortName() != show_query.short_name)) continue; if (show_query.database_and_table_name) { const String & database = show_query.database_and_table_name->first; const String & table_name = show_query.database_and_table_name->second; if (!database.empty() && (policy->getDatabase() != database)) continue; if (!table_name.empty() && (policy->getTableName() != table_name)) continue; } entities.push_back(policy); } } } else { for (const String & name : show_query.names) entities.push_back(access_control.read(access_control.getID(show_query.type, name))); } boost::range::sort(entities, IAccessEntity::LessByName{}); return entities; } ASTs InterpreterShowCreateAccessEntityQuery::getCreateQueries() const { auto entities = getEntities(); ASTs list; const auto & access_control = context.getAccessControlManager(); for (const auto & entity : entities) list.push_back(getCreateQuery(*entity, access_control)); return list; } ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(const IAccessEntity & entity, const AccessControlManager & access_control) { return getCreateQueryImpl(entity, &access_control, false); } ASTPtr InterpreterShowCreateAccessEntityQuery::getAttachQuery(const IAccessEntity & entity) { return getCreateQueryImpl(entity, nullptr, true); } AccessRightsElements InterpreterShowCreateAccessEntityQuery::getRequiredAccess() const { const auto & show_query = query_ptr->as(); AccessRightsElements res; switch (show_query.type) { case EntityType::USER: res.emplace_back(AccessType::SHOW_USERS); return res; case EntityType::ROLE: res.emplace_back(AccessType::SHOW_ROLES); return res; case EntityType::SETTINGS_PROFILE: res.emplace_back(AccessType::SHOW_SETTINGS_PROFILES); return res; case EntityType::ROW_POLICY: res.emplace_back(AccessType::SHOW_ROW_POLICIES); return res; case EntityType::QUOTA: res.emplace_back(AccessType::SHOW_QUOTAS); return res; case EntityType::MAX: break; } throw Exception(toString(show_query.type) + ": type is not supported by SHOW CREATE query", ErrorCodes::NOT_IMPLEMENTED); } }