2018-10-09 14:32:11 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <common/logger_useful.h>
|
|
|
|
#include <Poco/Util/Application.h>
|
2020-11-09 16:05:40 +00:00
|
|
|
#include <IO/Operators.h>
|
2018-10-09 14:32:11 +00:00
|
|
|
|
|
|
|
#include <Parsers/IAST.h>
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
/// If output stream set dumps node with indents and some additional info. Do nothing otherwise.
|
2020-06-27 19:05:00 +00:00
|
|
|
/// Allow to print key-value pairs inside of tree dump.
|
2018-10-09 14:32:11 +00:00
|
|
|
class DumpASTNode
|
|
|
|
{
|
|
|
|
public:
|
2020-11-09 16:05:40 +00:00
|
|
|
DumpASTNode(const IAST & ast_, WriteBuffer * ostr_, size_t & depth, const char * label_ = nullptr)
|
2018-10-09 14:32:11 +00:00
|
|
|
: ast(ast_),
|
|
|
|
ostr(ostr_),
|
|
|
|
indent(depth),
|
|
|
|
visit_depth(depth),
|
|
|
|
label(label_)
|
|
|
|
{
|
|
|
|
if (!ostr)
|
|
|
|
return;
|
|
|
|
if (label && visit_depth == 0)
|
2020-11-09 16:05:40 +00:00
|
|
|
(*ostr) << "-- " << label << '\n';
|
2018-10-09 14:32:11 +00:00
|
|
|
++visit_depth;
|
|
|
|
|
|
|
|
(*ostr) << String(indent, ' ');
|
|
|
|
printNode();
|
2020-11-09 16:05:40 +00:00
|
|
|
(*ostr) << '\n';
|
2018-10-09 14:32:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~DumpASTNode()
|
|
|
|
{
|
|
|
|
if (!ostr)
|
|
|
|
return;
|
|
|
|
--visit_depth;
|
|
|
|
if (label && visit_depth == 0)
|
2020-11-09 16:05:40 +00:00
|
|
|
(*ostr) << "--\n";
|
2018-10-09 14:32:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename U>
|
|
|
|
void print(const T & name, const U & value, const char * str_indent = nullptr) const
|
|
|
|
{
|
|
|
|
if (!ostr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
(*ostr) << (str_indent ? String(str_indent) : String(indent, ' '));
|
|
|
|
(*ostr) << '(' << name << ' ' << value << ')';
|
|
|
|
if (!str_indent)
|
2020-11-09 16:05:40 +00:00
|
|
|
(*ostr) << '\n';
|
2018-10-09 14:32:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t & getDepth() { return visit_depth; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
const IAST & ast;
|
2020-11-09 16:05:40 +00:00
|
|
|
WriteBuffer * ostr;
|
2018-10-09 14:32:11 +00:00
|
|
|
size_t indent;
|
|
|
|
size_t & visit_depth; /// shared with children
|
|
|
|
const char * label;
|
|
|
|
|
2018-12-07 14:24:47 +00:00
|
|
|
String nodeId() const { return ast.getID(' '); }
|
2018-10-09 14:32:11 +00:00
|
|
|
|
|
|
|
void printNode() const
|
|
|
|
{
|
|
|
|
(*ostr) << nodeId();
|
|
|
|
|
2019-02-11 19:53:55 +00:00
|
|
|
String alias = ast.tryGetAlias();
|
|
|
|
if (!alias.empty())
|
|
|
|
print("alias", alias, " ");
|
2018-10-09 14:32:11 +00:00
|
|
|
|
|
|
|
if (!ast.children.empty())
|
2018-12-07 14:24:47 +00:00
|
|
|
print("children", ast.children.size(), " ");
|
2018-10-09 14:32:11 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-09 16:05:40 +00:00
|
|
|
inline void dumpAST(const IAST & ast, WriteBuffer & ostr, DumpASTNode * parent = nullptr)
|
2018-10-09 14:32:11 +00:00
|
|
|
{
|
|
|
|
size_t depth = 0;
|
|
|
|
DumpASTNode dump(ast, &ostr, (parent ? parent->getDepth() : depth));
|
|
|
|
|
|
|
|
for (const auto & child : ast.children)
|
|
|
|
dumpAST(*child, ostr, &dump);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// String stream dumped in dtor
|
|
|
|
template <bool _enable>
|
|
|
|
class DebugASTLog
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DebugASTLog()
|
|
|
|
: log(nullptr)
|
|
|
|
{
|
|
|
|
if constexpr (_enable)
|
|
|
|
log = &Poco::Logger::get("AST");
|
|
|
|
}
|
|
|
|
|
|
|
|
~DebugASTLog()
|
|
|
|
{
|
|
|
|
if constexpr (_enable)
|
2020-11-09 16:05:40 +00:00
|
|
|
LOG_DEBUG(log, buf.str());
|
2018-10-09 14:32:11 +00:00
|
|
|
}
|
|
|
|
|
2020-11-09 16:05:40 +00:00
|
|
|
WriteBuffer * stream() { return (_enable ? &buf : nullptr); }
|
2018-10-09 14:32:11 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
Poco::Logger * log;
|
2020-11-09 16:05:40 +00:00
|
|
|
WriteBufferFromOwnString buf;
|
2018-10-09 14:32:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
}
|