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: ";
if (mask_id)
buffer << "[HIDDEN id: " << 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();

View File

@ -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;
}

View File

@ -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>;
}

View File

@ -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;