2020-09-02 12:39:34 +00:00
|
|
|
#include <map>
|
2020-08-29 05:33:46 +00:00
|
|
|
#include "ASTColumnsTransformers.h"
|
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
#include <Parsers/ASTIdentifier.h>
|
|
|
|
#include <Common/SipHash.h>
|
|
|
|
#include <Common/quoteString.h>
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
2020-10-20 07:38:56 +00:00
|
|
|
extern const int NO_SUCH_COLUMN_IN_TABLE;
|
2020-08-29 05:33:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void IASTColumnsTransformer::transform(const ASTPtr & transformer, ASTs & nodes)
|
|
|
|
{
|
|
|
|
if (const auto * apply = transformer->as<ASTColumnsApplyTransformer>())
|
|
|
|
{
|
|
|
|
apply->transform(nodes);
|
|
|
|
}
|
|
|
|
else if (const auto * except = transformer->as<ASTColumnsExceptTransformer>())
|
|
|
|
{
|
|
|
|
except->transform(nodes);
|
|
|
|
}
|
|
|
|
else if (const auto * replace = transformer->as<ASTColumnsReplaceTransformer>())
|
|
|
|
{
|
|
|
|
replace->transform(nodes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTColumnsApplyTransformer::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
|
|
|
|
{
|
|
|
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << "APPLY" << (settings.hilite ? hilite_none : "") << "(" << func_name << ")";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTColumnsApplyTransformer::transform(ASTs & nodes) const
|
|
|
|
{
|
|
|
|
for (auto & column : nodes)
|
|
|
|
{
|
|
|
|
column = makeASTFunction(func_name, column);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTColumnsExceptTransformer::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
|
|
|
{
|
2020-10-22 04:40:50 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << "EXCEPT" << (is_strict ? " STRICT " : "") << (settings.hilite ? hilite_none : "") << "(";
|
2020-08-29 05:33:46 +00:00
|
|
|
|
|
|
|
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
{
|
|
|
|
if (it != children.begin())
|
|
|
|
{
|
|
|
|
settings.ostr << ", ";
|
|
|
|
}
|
|
|
|
(*it)->formatImpl(settings, state, frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
settings.ostr << ")";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTColumnsExceptTransformer::transform(ASTs & nodes) const
|
|
|
|
{
|
2020-10-22 04:40:50 +00:00
|
|
|
ASTs expected_columns(children);
|
|
|
|
|
2020-08-29 05:33:46 +00:00
|
|
|
nodes.erase(
|
|
|
|
std::remove_if(
|
|
|
|
nodes.begin(),
|
|
|
|
nodes.end(),
|
2020-10-21 07:54:13 +00:00
|
|
|
[&](const ASTPtr & node_child)
|
2020-08-29 05:33:46 +00:00
|
|
|
{
|
|
|
|
if (const auto * id = node_child->as<ASTIdentifier>())
|
|
|
|
{
|
2020-10-22 04:40:50 +00:00
|
|
|
for (int i = children.size() - 1; i >= 0; --i)
|
2020-08-29 05:33:46 +00:00
|
|
|
{
|
2020-10-21 07:54:13 +00:00
|
|
|
if (children[i]->as<const ASTIdentifier &>().name == id->shortName())
|
|
|
|
{
|
2020-10-22 04:40:50 +00:00
|
|
|
expected_columns.erase(expected_columns.begin() + i);
|
2020-08-29 05:33:46 +00:00
|
|
|
return true;
|
2020-10-21 07:54:13 +00:00
|
|
|
}
|
2020-08-29 05:33:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}),
|
|
|
|
nodes.end());
|
2020-10-21 07:54:13 +00:00
|
|
|
|
2020-10-22 04:40:50 +00:00
|
|
|
if (is_strict && !expected_columns.empty())
|
2020-10-21 07:54:13 +00:00
|
|
|
{
|
2020-10-22 04:40:50 +00:00
|
|
|
String expected_columns_str;
|
|
|
|
for (size_t i = 0; i < expected_columns.size(); ++i)
|
2020-10-21 07:54:13 +00:00
|
|
|
{
|
|
|
|
if (i > 0)
|
2020-10-22 04:40:50 +00:00
|
|
|
expected_columns_str += ", ";
|
|
|
|
expected_columns_str += expected_columns[i]->as<const ASTIdentifier &>().name;
|
2020-10-21 07:54:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
throw Exception(
|
2020-10-22 04:40:50 +00:00
|
|
|
"Columns transformer EXCEPT expects following column(s) : " + expected_columns_str,
|
2020-10-21 07:54:13 +00:00
|
|
|
ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
|
|
|
|
}
|
2020-08-29 05:33:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASTColumnsReplaceTransformer::Replacement::formatImpl(
|
|
|
|
const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
|
|
|
{
|
|
|
|
expr->formatImpl(settings, state, frame);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << " AS " << (settings.hilite ? hilite_none : "") << name;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTColumnsReplaceTransformer::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
|
|
|
{
|
2020-10-22 04:40:50 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << "REPLACE" << (is_strict ? " STRICT " : "") << (settings.hilite ? hilite_none : "") << "(";
|
2020-08-29 05:33:46 +00:00
|
|
|
|
|
|
|
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
{
|
|
|
|
if (it != children.begin())
|
|
|
|
{
|
|
|
|
settings.ostr << ", ";
|
|
|
|
}
|
|
|
|
(*it)->formatImpl(settings, state, frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
settings.ostr << ")";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTColumnsReplaceTransformer::replaceChildren(ASTPtr & node, const ASTPtr & replacement, const String & name)
|
|
|
|
{
|
|
|
|
for (auto & child : node->children)
|
|
|
|
{
|
|
|
|
if (const auto * id = child->as<ASTIdentifier>())
|
|
|
|
{
|
|
|
|
if (id->shortName() == name)
|
2020-09-11 07:46:14 +00:00
|
|
|
child = replacement->clone();
|
2020-08-29 05:33:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
replaceChildren(child, replacement, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTColumnsReplaceTransformer::transform(ASTs & nodes) const
|
|
|
|
{
|
|
|
|
std::map<String, ASTPtr> replace_map;
|
|
|
|
for (const auto & replace_child : children)
|
|
|
|
{
|
|
|
|
auto & replacement = replace_child->as<Replacement &>();
|
|
|
|
if (replace_map.find(replacement.name) != replace_map.end())
|
|
|
|
throw Exception(
|
|
|
|
"Expressions in columns transformer REPLACE should not contain the same replacement more than once",
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
replace_map.emplace(replacement.name, replacement.expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto & column : nodes)
|
|
|
|
{
|
|
|
|
if (const auto * id = column->as<ASTIdentifier>())
|
|
|
|
{
|
|
|
|
auto replace_it = replace_map.find(id->shortName());
|
|
|
|
if (replace_it != replace_map.end())
|
|
|
|
{
|
|
|
|
column = replace_it->second;
|
|
|
|
column->setAlias(replace_it->first);
|
2020-10-21 07:54:13 +00:00
|
|
|
replace_map.erase(replace_it);
|
2020-08-29 05:33:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (auto * ast_with_alias = dynamic_cast<ASTWithAlias *>(column.get()))
|
|
|
|
{
|
|
|
|
auto replace_it = replace_map.find(ast_with_alias->alias);
|
|
|
|
if (replace_it != replace_map.end())
|
|
|
|
{
|
|
|
|
auto new_ast = replace_it->second->clone();
|
|
|
|
ast_with_alias->alias = ""; // remove the old alias as it's useless after replace transformation
|
|
|
|
replaceChildren(new_ast, column, replace_it->first);
|
|
|
|
column = new_ast;
|
|
|
|
column->setAlias(replace_it->first);
|
2020-10-21 07:54:13 +00:00
|
|
|
replace_map.erase(replace_it);
|
2020-08-29 05:33:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-20 07:38:56 +00:00
|
|
|
|
2020-10-21 07:54:13 +00:00
|
|
|
if (is_strict && !replace_map.empty())
|
|
|
|
{
|
2020-10-22 04:40:50 +00:00
|
|
|
String expected_columns = "";
|
2020-10-21 07:54:13 +00:00
|
|
|
for (auto it = replace_map.begin(); it != replace_map.end(); ++it)
|
|
|
|
{
|
2020-10-22 04:40:50 +00:00
|
|
|
if (expected_columns != "")
|
|
|
|
expected_columns += ", ";
|
|
|
|
expected_columns += it->first;
|
2020-10-21 07:54:13 +00:00
|
|
|
}
|
2020-10-20 07:38:56 +00:00
|
|
|
throw Exception(
|
2020-10-22 04:40:50 +00:00
|
|
|
"Columns transformer REPLACE expects following column(s) : " + expected_columns,
|
2020-10-20 07:38:56 +00:00
|
|
|
ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
|
2020-10-21 07:54:13 +00:00
|
|
|
}
|
|
|
|
|
2020-08-29 05:33:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|