mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-04 21:42:39 +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: ";
|
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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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>;
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user