mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-04 13:32:13 +00:00
add hiding secrets in EXPLAIN for table functions
This commit is contained in:
parent
49e41f23ee
commit
a8e98df97a
@ -114,7 +114,12 @@ void ConstantNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state
|
||||
|
||||
buffer << ", constant_value: ";
|
||||
if (mask_id)
|
||||
{
|
||||
if (mask_id == std::numeric_limits<decltype(mask_id)>::max())
|
||||
buffer << "[HIDDEN]";
|
||||
else
|
||||
buffer << "[HIDDEN id: " << mask_id << "]";
|
||||
}
|
||||
else
|
||||
buffer << constant_value->getValue().dump();
|
||||
|
||||
|
@ -82,7 +82,7 @@ public:
|
||||
/// Check if constant is a result of _CAST function constant folding.
|
||||
bool receivedFromInitiatorServer() const;
|
||||
|
||||
void setMaskId(size_t id)
|
||||
void setMaskId(size_t id = std::numeric_limits<decltype(mask_id)>::max())
|
||||
{
|
||||
mask_id = id;
|
||||
}
|
||||
|
@ -3,31 +3,48 @@
|
||||
#include <Parsers/FunctionSecretArgumentsFinder.h>
|
||||
#include <Analyzer/ConstantNode.h>
|
||||
#include <Analyzer/FunctionNode.h>
|
||||
#include <Analyzer/TableFunctionNode.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:
|
||||
class ArgumentTreeNode : public Argument
|
||||
{
|
||||
public:
|
||||
explicit ArgumentTreeNode(const IQueryTreeNode * argument_) : argument(argument_) {}
|
||||
explicit ArgumentTreeNode(const DB::IQueryTreeNode * argument_) : argument(argument_) {}
|
||||
std::unique_ptr<AbstractFunction> getFunction() const override
|
||||
{
|
||||
if (const auto * f = argument->as<FunctionNode>())
|
||||
return std::make_unique<FunctionTreeNode>(*f);
|
||||
if (const auto * f = argument->as<FunctionNodeType>())
|
||||
return std::make_unique<FunctionTreeNodeImpl>(*f);
|
||||
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
|
||||
{
|
||||
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;
|
||||
if (res)
|
||||
*res = literal->getValue().safeGet<String>();
|
||||
@ -36,7 +53,7 @@ public:
|
||||
|
||||
if (allow_identifier)
|
||||
{
|
||||
if (const auto * id = argument->as<IdentifierNode>())
|
||||
if (const auto * id = argument->as<DB::IdentifierNode>())
|
||||
{
|
||||
if (res)
|
||||
*res = id->getIdentifier().getFullName();
|
||||
@ -47,37 +64,37 @@ public:
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
const IQueryTreeNode * argument = nullptr;
|
||||
const DB::IQueryTreeNode * argument = nullptr;
|
||||
};
|
||||
|
||||
class ArgumentsTreeNode : public Arguments
|
||||
{
|
||||
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; }
|
||||
std::unique_ptr<Argument> at(size_t n) const override { return std::make_unique<ArgumentTreeNode>(arguments->at(n).get()); }
|
||||
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())
|
||||
arguments = std::make_unique<ArgumentsTreeNode>(&nodes);
|
||||
}
|
||||
String name() const override { return function->getFunctionName(); }
|
||||
String name() const override { return getFunctionNameImpl(function); }
|
||||
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.
|
||||
/// That involves passwords and secret keys.
|
||||
class FunctionSecretArgumentsFinderTreeNode : public FunctionSecretArgumentsFinder
|
||||
template <typename FunctionNodeType>
|
||||
class FunctionSecretArgumentsFinderTreeNodeImpl : public DB::FunctionSecretArgumentsFinder
|
||||
{
|
||||
public:
|
||||
explicit FunctionSecretArgumentsFinderTreeNode(const FunctionNode & function_)
|
||||
: FunctionSecretArgumentsFinder(std::make_unique<FunctionTreeNode>(function_))
|
||||
explicit FunctionSecretArgumentsFinderTreeNodeImpl(const FunctionNodeType & function_)
|
||||
: FunctionSecretArgumentsFinder(std::make_unique<FunctionTreeNodeImpl<FunctionNodeType>>(function_))
|
||||
{
|
||||
if (!function->hasArguments())
|
||||
return;
|
||||
@ -89,3 +106,12 @@ public:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
using FunctionSecretArgumentsFinderTreeNode = FunctionSecretArgumentsFinderTreeNodeImpl<FunctionNode>;
|
||||
using TableFunctionSecretArgumentsFinderTreeNode = FunctionSecretArgumentsFinderTreeNodeImpl<TableFunctionNode>;
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "Analyzer/FunctionNode.h"
|
||||
#include <Interpreters/InterpreterFactory.h>
|
||||
#include <Interpreters/InterpreterExplainQuery.h>
|
||||
|
||||
@ -21,6 +22,7 @@
|
||||
#include <Parsers/ASTSelectQuery.h>
|
||||
#include <Parsers/ASTSelectWithUnionQuery.h>
|
||||
#include <Parsers/ASTSetQuery.h>
|
||||
#include <Parsers/FunctionSecretArgumentsFinder.h>
|
||||
|
||||
#include <Storages/StorageView.h>
|
||||
#include <Processors/QueryPlan/QueryPlan.h>
|
||||
@ -33,6 +35,9 @@
|
||||
|
||||
#include <Analyzer/QueryTreeBuilder.h>
|
||||
#include <Analyzer/QueryTreePassManager.h>
|
||||
#include <Analyzer/InDepthQueryTreeVisitor.h>
|
||||
#include <Analyzer/FunctionSecretArgumentsFinderTreeNode.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -40,6 +45,7 @@ namespace Setting
|
||||
{
|
||||
extern const SettingsBool allow_experimental_analyzer;
|
||||
extern const SettingsBool allow_statistics_optimize;
|
||||
extern const SettingsBool format_display_secrets_in_show_and_select;
|
||||
}
|
||||
|
||||
namespace ErrorCodes
|
||||
@ -90,6 +96,32 @@ namespace
|
||||
|
||||
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()
|
||||
@ -411,6 +443,12 @@ QueryPipeline InterpreterExplainQuery::executeImpl()
|
||||
auto query_tree = buildQueryTree(ast.getExplainedQuery(), getContext());
|
||||
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)
|
||||
{
|
||||
auto query_tree_pass_manager = QueryTreePassManager(getContext());
|
||||
@ -441,7 +479,10 @@ QueryPipeline InterpreterExplainQuery::executeImpl()
|
||||
if (need_newline)
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user