add hiding secrets in EXPLAIN for table functions

This commit is contained in:
Yakov Olkhovskiy 2024-11-18 09:38:08 +00:00
parent 49e41f23ee
commit a8e98df97a
4 changed files with 94 additions and 22 deletions

View File

@ -114,7 +114,12 @@ void ConstantNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state
buffer << ", constant_value: "; buffer << ", constant_value: ";
if (mask_id) if (mask_id)
{
if (mask_id == std::numeric_limits<decltype(mask_id)>::max())
buffer << "[HIDDEN]";
else
buffer << "[HIDDEN id: " << mask_id << "]"; buffer << "[HIDDEN id: " << mask_id << "]";
}
else else
buffer << constant_value->getValue().dump(); buffer << constant_value->getValue().dump();

View File

@ -82,7 +82,7 @@ public:
/// Check if constant is a result of _CAST function constant folding. /// Check if constant is a result of _CAST function constant folding.
bool receivedFromInitiatorServer() const; bool receivedFromInitiatorServer() const;
void setMaskId(size_t id) void setMaskId(size_t id = std::numeric_limits<decltype(mask_id)>::max())
{ {
mask_id = id; mask_id = id;
} }

View File

@ -3,31 +3,48 @@
#include <Parsers/FunctionSecretArgumentsFinder.h> #include <Parsers/FunctionSecretArgumentsFinder.h>
#include <Analyzer/ConstantNode.h> #include <Analyzer/ConstantNode.h>
#include <Analyzer/FunctionNode.h> #include <Analyzer/FunctionNode.h>
#include <Analyzer/TableFunctionNode.h>
#include <Analyzer/IdentifierNode.h> #include <Analyzer/IdentifierNode.h>
namespace DB namespace
{ {
class FunctionTreeNode : public AbstractFunction template <typename FunctionNodeType>
String getFunctionNameImpl(const FunctionNodeType *);
template <>
[[maybe_unused]] String getFunctionNameImpl<DB::FunctionNode>(const DB::FunctionNode * function)
{
return function->getFunctionName();
}
template <>
[[maybe_unused]] String getFunctionNameImpl<DB::TableFunctionNode>(const DB::TableFunctionNode * function)
{
return function->getTableFunctionName();
}
template <typename FunctionNodeType>
class FunctionTreeNodeImpl : public DB::AbstractFunction
{ {
public: public:
class ArgumentTreeNode : public Argument class ArgumentTreeNode : public Argument
{ {
public: public:
explicit ArgumentTreeNode(const IQueryTreeNode * argument_) : argument(argument_) {} explicit ArgumentTreeNode(const DB::IQueryTreeNode * argument_) : argument(argument_) {}
std::unique_ptr<AbstractFunction> getFunction() const override std::unique_ptr<AbstractFunction> getFunction() const override
{ {
if (const auto * f = argument->as<FunctionNode>()) if (const auto * f = argument->as<FunctionNodeType>())
return std::make_unique<FunctionTreeNode>(*f); return std::make_unique<FunctionTreeNodeImpl>(*f);
return nullptr; return nullptr;
} }
bool isIdentifier() const override { return argument->as<IdentifierNode>(); } bool isIdentifier() const override { return argument->as<DB::IdentifierNode>(); }
bool tryGetString(String * res, bool allow_identifier) const override bool tryGetString(String * res, bool allow_identifier) const override
{ {
if (const auto * literal = argument->as<ConstantNode>()) if (const auto * literal = argument->as<DB::ConstantNode>())
{ {
if (literal->getValue().getType() != Field::Types::String) if (literal->getValue().getType() != DB::Field::Types::String)
return false; return false;
if (res) if (res)
*res = literal->getValue().safeGet<String>(); *res = literal->getValue().safeGet<String>();
@ -36,7 +53,7 @@ public:
if (allow_identifier) if (allow_identifier)
{ {
if (const auto * id = argument->as<IdentifierNode>()) if (const auto * id = argument->as<DB::IdentifierNode>())
{ {
if (res) if (res)
*res = id->getIdentifier().getFullName(); *res = id->getIdentifier().getFullName();
@ -47,37 +64,37 @@ public:
return false; return false;
} }
private: private:
const IQueryTreeNode * argument = nullptr; const DB::IQueryTreeNode * argument = nullptr;
}; };
class ArgumentsTreeNode : public Arguments class ArgumentsTreeNode : public Arguments
{ {
public: public:
explicit ArgumentsTreeNode(const QueryTreeNodes * arguments_) : arguments(arguments_) {} explicit ArgumentsTreeNode(const DB::QueryTreeNodes * arguments_) : arguments(arguments_) {}
size_t size() const override { return arguments ? arguments->size() : 0; } size_t size() const override { return arguments ? arguments->size() : 0; }
std::unique_ptr<Argument> at(size_t n) const override { return std::make_unique<ArgumentTreeNode>(arguments->at(n).get()); } std::unique_ptr<Argument> at(size_t n) const override { return std::make_unique<ArgumentTreeNode>(arguments->at(n).get()); }
private: private:
const QueryTreeNodes * arguments = nullptr; const DB::QueryTreeNodes * arguments = nullptr;
}; };
explicit FunctionTreeNode(const FunctionNode & function_) : function(&function_) explicit FunctionTreeNodeImpl(const FunctionNodeType & function_) : function(&function_)
{ {
if (const auto & nodes = function->getArguments().getNodes(); !nodes.empty()) if (const auto & nodes = function->getArguments().getNodes(); !nodes.empty())
arguments = std::make_unique<ArgumentsTreeNode>(&nodes); arguments = std::make_unique<ArgumentsTreeNode>(&nodes);
} }
String name() const override { return function->getFunctionName(); } String name() const override { return getFunctionNameImpl(function); }
private: private:
const FunctionNode * function = nullptr; const FunctionNodeType * function = nullptr;
}; };
/// Finds arguments of a specified function which should not be displayed for most users for security reasons. /// Finds arguments of a specified function which should not be displayed for most users for security reasons.
/// That involves passwords and secret keys. /// That involves passwords and secret keys.
class FunctionSecretArgumentsFinderTreeNode : public FunctionSecretArgumentsFinder template <typename FunctionNodeType>
class FunctionSecretArgumentsFinderTreeNodeImpl : public DB::FunctionSecretArgumentsFinder
{ {
public: public:
explicit FunctionSecretArgumentsFinderTreeNode(const FunctionNode & function_) explicit FunctionSecretArgumentsFinderTreeNodeImpl(const FunctionNodeType & function_)
: FunctionSecretArgumentsFinder(std::make_unique<FunctionTreeNode>(function_)) : FunctionSecretArgumentsFinder(std::make_unique<FunctionTreeNodeImpl<FunctionNodeType>>(function_))
{ {
if (!function->hasArguments()) if (!function->hasArguments())
return; return;
@ -89,3 +106,12 @@ public:
}; };
} }
namespace DB
{
using FunctionSecretArgumentsFinderTreeNode = FunctionSecretArgumentsFinderTreeNodeImpl<FunctionNode>;
using TableFunctionSecretArgumentsFinderTreeNode = FunctionSecretArgumentsFinderTreeNodeImpl<TableFunctionNode>;
}

View File

@ -1,3 +1,4 @@
#include "Analyzer/FunctionNode.h"
#include <Interpreters/InterpreterFactory.h> #include <Interpreters/InterpreterFactory.h>
#include <Interpreters/InterpreterExplainQuery.h> #include <Interpreters/InterpreterExplainQuery.h>
@ -21,6 +22,7 @@
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTSelectWithUnionQuery.h> #include <Parsers/ASTSelectWithUnionQuery.h>
#include <Parsers/ASTSetQuery.h> #include <Parsers/ASTSetQuery.h>
#include <Parsers/FunctionSecretArgumentsFinder.h>
#include <Storages/StorageView.h> #include <Storages/StorageView.h>
#include <Processors/QueryPlan/QueryPlan.h> #include <Processors/QueryPlan/QueryPlan.h>
@ -33,6 +35,9 @@
#include <Analyzer/QueryTreeBuilder.h> #include <Analyzer/QueryTreeBuilder.h>
#include <Analyzer/QueryTreePassManager.h> #include <Analyzer/QueryTreePassManager.h>
#include <Analyzer/InDepthQueryTreeVisitor.h>
#include <Analyzer/FunctionSecretArgumentsFinderTreeNode.h>
namespace DB namespace DB
{ {
@ -40,6 +45,7 @@ namespace Setting
{ {
extern const SettingsBool allow_experimental_analyzer; extern const SettingsBool allow_experimental_analyzer;
extern const SettingsBool allow_statistics_optimize; extern const SettingsBool allow_statistics_optimize;
extern const SettingsBool format_display_secrets_in_show_and_select;
} }
namespace ErrorCodes namespace ErrorCodes
@ -90,6 +96,32 @@ namespace
using ExplainAnalyzedSyntaxVisitor = InDepthNodeVisitor<ExplainAnalyzedSyntaxMatcher, true>; using ExplainAnalyzedSyntaxVisitor = InDepthNodeVisitor<ExplainAnalyzedSyntaxMatcher, true>;
class TableFunctionSecretsVisitor : public InDepthQueryTreeVisitor<TableFunctionSecretsVisitor>
{
friend class InDepthQueryTreeVisitor;
bool needChildVisit(VisitQueryTreeNodeType & parent [[maybe_unused]], VisitQueryTreeNodeType & child [[maybe_unused]])
{
QueryTreeNodeType type = parent->getNodeType();
return type == QueryTreeNodeType::QUERY || type == QueryTreeNodeType::JOIN || type == QueryTreeNodeType::TABLE_FUNCTION;
}
void visitImpl(VisitQueryTreeNodeType & query_tree_node)
{
auto * table_function_node_ptr = query_tree_node->as<TableFunctionNode>();
if (!table_function_node_ptr)
return;
if (FunctionSecretArgumentsFinder::Result secret_arguments = TableFunctionSecretArgumentsFinderTreeNode(*table_function_node_ptr).getResult(); secret_arguments.count)
{
auto & argument_nodes = table_function_node_ptr->getArgumentsNode()->as<ListNode &>().getNodes();
for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n)
if (auto * constant = argument_nodes[n]->as<ConstantNode>())
constant->setMaskId();
}
}
};
} }
BlockIO InterpreterExplainQuery::execute() BlockIO InterpreterExplainQuery::execute()
@ -411,6 +443,12 @@ QueryPipeline InterpreterExplainQuery::executeImpl()
auto query_tree = buildQueryTree(ast.getExplainedQuery(), getContext()); auto query_tree = buildQueryTree(ast.getExplainedQuery(), getContext());
bool need_newline = false; bool need_newline = false;
if (!getContext()->getSettingsRef()[Setting::format_display_secrets_in_show_and_select])
{
TableFunctionSecretsVisitor visitor;
visitor.visit(query_tree);
}
if (settings.run_passes) if (settings.run_passes)
{ {
auto query_tree_pass_manager = QueryTreePassManager(getContext()); auto query_tree_pass_manager = QueryTreePassManager(getContext());
@ -441,7 +479,10 @@ QueryPipeline InterpreterExplainQuery::executeImpl()
if (need_newline) if (need_newline)
buf << "\n\n"; buf << "\n\n";
query_tree->toAST()->format(IAST::FormatSettings(buf, false)); IAST::FormatSettings format_settings(buf, false);
if (!getContext()->getSettingsRef()[Setting::format_display_secrets_in_show_and_select])
format_settings.show_secrets = false;
query_tree->toAST()->format(format_settings);
} }
break; break;