2022-02-27 16:43:56 +00:00
|
|
|
#include <Interpreters/ConvertFunctionOrLikeVisitor.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
#include <Parsers/ASTIdentifier.h>
|
|
|
|
#include <Parsers/ASTLiteral.h>
|
|
|
|
#include <Parsers/IAST.h>
|
2023-02-27 16:41:15 +00:00
|
|
|
#include <Common/likePatternToRegexp.h>
|
2022-02-27 16:43:56 +00:00
|
|
|
#include <Common/typeid_cast.h>
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
void ConvertFunctionOrLikeData::visit(ASTFunction & function, ASTPtr &)
|
|
|
|
{
|
|
|
|
if (function.name != "or")
|
|
|
|
return;
|
2022-05-07 11:11:06 +00:00
|
|
|
|
2022-11-02 18:35:22 +00:00
|
|
|
std::unordered_map<String, std::shared_ptr<ASTLiteral>> identifier_to_literals;
|
2022-02-27 16:43:56 +00:00
|
|
|
for (auto & child : function.children)
|
|
|
|
{
|
2022-05-16 08:13:18 +00:00
|
|
|
if (auto * expr_list_fn = child->as<ASTExpressionList>())
|
2022-02-27 16:43:56 +00:00
|
|
|
{
|
|
|
|
ASTs unique_elems;
|
2022-05-09 03:16:10 +00:00
|
|
|
for (const auto & child_expr_fn : expr_list_fn->children)
|
2022-02-27 16:43:56 +00:00
|
|
|
{
|
|
|
|
unique_elems.push_back(child_expr_fn);
|
2022-05-07 11:11:06 +00:00
|
|
|
if (const auto * child_fn = child_expr_fn->as<ASTFunction>())
|
2022-02-27 16:43:56 +00:00
|
|
|
{
|
|
|
|
const bool is_like = child_fn->name == "like";
|
|
|
|
const bool is_ilike = child_fn->name == "ilike";
|
2022-05-07 11:11:06 +00:00
|
|
|
|
|
|
|
/// Not {i}like -> bail out.
|
2022-02-27 16:43:56 +00:00
|
|
|
if (!is_like && !is_ilike)
|
|
|
|
continue;
|
2022-05-07 11:11:06 +00:00
|
|
|
|
2022-02-27 16:43:56 +00:00
|
|
|
const auto & arguments = child_fn->arguments->children;
|
2022-05-07 11:11:06 +00:00
|
|
|
|
|
|
|
/// They should have 2 arguments.
|
2022-02-27 16:43:56 +00:00
|
|
|
if (arguments.size() != 2)
|
|
|
|
continue;
|
2022-05-07 11:11:06 +00:00
|
|
|
|
|
|
|
/// Second one is string literal.
|
2022-02-27 16:43:56 +00:00
|
|
|
auto identifier = arguments[0];
|
2022-05-16 08:13:18 +00:00
|
|
|
auto * literal = arguments[1]->as<ASTLiteral>();
|
2022-02-27 16:43:56 +00:00
|
|
|
if (!identifier || !literal || literal->value.getType() != Field::Types::String)
|
|
|
|
continue;
|
2022-05-07 11:11:06 +00:00
|
|
|
|
2022-02-27 16:43:56 +00:00
|
|
|
String regexp = likePatternToRegexp(literal->value.get<String>());
|
2022-05-07 11:11:06 +00:00
|
|
|
/// Case insensitive. Works with UTF-8 as well.
|
2022-02-27 16:43:56 +00:00
|
|
|
if (is_ilike)
|
|
|
|
regexp = "(?i)" + regexp;
|
2022-05-07 11:11:06 +00:00
|
|
|
|
2022-02-27 16:43:56 +00:00
|
|
|
unique_elems.pop_back();
|
2022-11-02 18:35:22 +00:00
|
|
|
auto it = identifier_to_literals.find(identifier->getAliasOrColumnName());
|
|
|
|
|
2022-02-27 16:43:56 +00:00
|
|
|
if (it == identifier_to_literals.end())
|
|
|
|
{
|
2022-11-02 18:35:22 +00:00
|
|
|
it = identifier_to_literals.insert({identifier->getAliasOrColumnName(), std::make_shared<ASTLiteral>(Field{Array{}})}).first;
|
2022-02-27 16:43:56 +00:00
|
|
|
auto match = makeASTFunction("multiMatchAny");
|
2022-05-09 23:23:24 +00:00
|
|
|
match->arguments->children.push_back(arguments[0]);
|
2022-02-27 16:43:56 +00:00
|
|
|
match->arguments->children.push_back(it->second);
|
|
|
|
unique_elems.push_back(std::move(match));
|
|
|
|
}
|
|
|
|
it->second->value.get<Array>().push_back(regexp);
|
|
|
|
}
|
|
|
|
}
|
2022-05-07 11:11:06 +00:00
|
|
|
|
|
|
|
/// OR must have at least two arguments.
|
2022-02-27 16:43:56 +00:00
|
|
|
if (unique_elems.size() == 1)
|
|
|
|
unique_elems.push_back(std::make_shared<ASTLiteral>(Field(false)));
|
2022-05-07 11:11:06 +00:00
|
|
|
|
2022-02-27 16:43:56 +00:00
|
|
|
expr_list_fn->children = std::move(unique_elems);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|