Fix GLOBAL IN evaluation

This commit is contained in:
Ivan Lezhankin 2020-11-13 17:13:27 +03:00
parent 9250d5c4e9
commit d69b6307b5
6 changed files with 33 additions and 17 deletions

View File

@ -526,6 +526,7 @@ bool ActionsMatcher::needChildVisit(const ASTPtr & node, const ASTPtr & child)
{ {
/// Visit children themself /// Visit children themself
if (node->as<ASTIdentifier>() || if (node->as<ASTIdentifier>() ||
node->as<ASTTableIdentifier>() ||
node->as<ASTFunction>() || node->as<ASTFunction>() ||
node->as<ASTLiteral>() || node->as<ASTLiteral>() ||
node->as<ASTExpressionList>()) node->as<ASTExpressionList>())
@ -543,6 +544,8 @@ void ActionsMatcher::visit(const ASTPtr & ast, Data & data)
{ {
if (const auto * identifier = ast->as<ASTIdentifier>()) if (const auto * identifier = ast->as<ASTIdentifier>())
visit(*identifier, ast, data); visit(*identifier, ast, data);
else if (const auto * table = ast->as<ASTTableIdentifier>())
visit(*table, ast, data);
else if (const auto * node = ast->as<ASTFunction>()) else if (const auto * node = ast->as<ASTFunction>())
visit(*node, ast, data); visit(*node, ast, data);
else if (const auto * literal = ast->as<ASTLiteral>()) else if (const auto * literal = ast->as<ASTLiteral>())
@ -659,9 +662,9 @@ void ActionsMatcher::visit(ASTExpressionList & expression_list, const ASTPtr &,
} }
} }
void ActionsMatcher::visit(const ASTIdentifier & identifier, const ASTPtr & ast, Data & data) void ActionsMatcher::visit(const ASTIdentifier & identifier, const ASTPtr &, Data & data)
{ {
auto column_name = ast->getColumnName(); auto column_name = identifier.getColumnName();
if (data.hasColumn(column_name)) if (data.hasColumn(column_name))
return; return;
@ -1004,7 +1007,7 @@ SetPtr ActionsMatcher::makeSet(const ASTFunction & node, Data & data, bool no_su
const ASTPtr & right_in_operand = args.children.at(1); const ASTPtr & right_in_operand = args.children.at(1);
/// If the subquery or table name for SELECT. /// If the subquery or table name for SELECT.
const auto * identifier = right_in_operand->as<ASTIdentifier>(); const auto * identifier = right_in_operand->as<ASTTableIdentifier>();
if (right_in_operand->as<ASTSubquery>() || identifier) if (right_in_operand->as<ASTSubquery>() || identifier)
{ {
if (no_subqueries) if (no_subqueries)

View File

@ -158,9 +158,7 @@ public:
static bool needChildVisit(ASTPtr &, const ASTPtr & child) static bool needChildVisit(ASTPtr &, const ASTPtr & child)
{ {
/// We do not go into subqueries. /// We do not go into subqueries.
if (child->as<ASTSelectQuery>()) return !child->as<ASTSelectQuery>();
return false;
return true;
} }
private: private:

View File

@ -1,4 +1,5 @@
#include <Poco/String.h> #include <Poco/String.h>
#include <IO/WriteBufferFromOStream.h>
#include <Interpreters/misc.h> #include <Interpreters/misc.h>
#include <Interpreters/MarkTableIdentifiersVisitor.h> #include <Interpreters/MarkTableIdentifiersVisitor.h>
#include <Interpreters/IdentifierSemantic.h> #include <Interpreters/IdentifierSemantic.h>
@ -24,29 +25,35 @@ void MarkTableIdentifiersMatcher::visit(ASTPtr & ast, Data & data)
visit(*node_func, ast, data); visit(*node_func, ast, data);
} }
void MarkTableIdentifiersMatcher::visit(const ASTFunction & func, ASTPtr &, Data & data) void MarkTableIdentifiersMatcher::visit(const ASTFunction & func, ASTPtr & ptr, Data & data)
{ {
/// `IN t` can be specified, where t is a table, which is equivalent to `IN (SELECT * FROM t)`. /// `IN t` can be specified, where t is a table, which is equivalent to `IN (SELECT * FROM t)`.
if (checkFunctionIsInOrGlobalInOperator(func)) if (checkFunctionIsInOrGlobalInOperator(func))
{ {
auto & ast = func.arguments->children.at(1); auto ast = func.arguments->children.at(1);
auto opt_name = tryGetIdentifierName(ast); auto opt_name = tryGetIdentifierName(ast);
if (opt_name && !data.aliases.count(*opt_name)) if (opt_name && !data.aliases.count(*opt_name))
setIdentifierSpecial(ast); {
ptr = func.clone();
ptr->as<ASTFunction>()->arguments->children[1] = ast->as<ASTIdentifier>()->createTable();
assert(ptr->as<ASTFunction>()->arguments->children[1]);
}
} }
// First argument of joinGet can be a table name, perhaps with a database. // First argument of joinGet can be a table name, perhaps with a database.
// First argument of dictGet can be a dictionary name, perhaps with a database. // First argument of dictGet can be a dictionary name, perhaps with a database.
if (functionIsJoinGet(func.name) || functionIsDictGet(func.name)) else if (functionIsJoinGet(func.name) || functionIsDictGet(func.name))
{ {
if (func.arguments->children.empty()) if (func.arguments->children.empty())
{
return; return;
}
auto & ast = func.arguments->children.at(0); auto & ast = func.arguments->children.at(0);
auto opt_name = tryGetIdentifierName(ast); auto opt_name = tryGetIdentifierName(ast);
if (opt_name && !data.aliases.count(*opt_name)) if (opt_name && !data.aliases.count(*opt_name))
setIdentifierSpecial(ast); {
ptr = func.clone();
ptr->as<ASTFunction>()->arguments->children[0] = ast->as<ASTIdentifier>()->createTable();
assert(ptr->as<ASTFunction>()->arguments->children[0]);
}
} }
} }

View File

@ -142,6 +142,13 @@ void ASTIdentifier::restoreTable()
} }
} }
std::shared_ptr<ASTTableIdentifier> ASTIdentifier::createTable() const
{
if (name_parts.size() == 1) return std::make_shared<ASTTableIdentifier>(name_parts[0]);
if (name_parts.size() == 2) return std::make_shared<ASTTableIdentifier>(name_parts[0], name_parts[1]);
return nullptr;
}
void ASTIdentifier::resetFullName() void ASTIdentifier::resetFullName()
{ {
full_name = name_parts[0]; full_name = name_parts[0];

View File

@ -14,10 +14,11 @@ struct IdentifierSemantic;
struct IdentifierSemanticImpl; struct IdentifierSemanticImpl;
struct StorageID; struct StorageID;
class ASTTableIdentifier;
/// Generic identifier. ASTTableIdentifier - for table identifier. /// Generic identifier. ASTTableIdentifier - for table identifier.
class ASTIdentifier : public ASTWithAlias class ASTIdentifier : public ASTWithAlias
{ {
friend class ReplaceQueryParameterVisitor;
public: public:
explicit ASTIdentifier(const String & short_name, ASTPtr && name_param = {}); explicit ASTIdentifier(const String & short_name, ASTPtr && name_param = {});
explicit ASTIdentifier(std::vector<String> && name_parts, bool special = false, std::vector<ASTPtr> && name_params = {}); explicit ASTIdentifier(std::vector<String> && name_parts, bool special = false, std::vector<ASTPtr> && name_params = {});
@ -44,6 +45,7 @@ public:
const String & name() const; const String & name() const;
void restoreTable(); // TODO(ilezhankin): get rid of this void restoreTable(); // TODO(ilezhankin): get rid of this
std::shared_ptr<ASTTableIdentifier> createTable() const; // return |nullptr| if identifier is not table.
protected: protected:
String full_name; String full_name;
@ -56,10 +58,9 @@ protected:
private: private:
using ASTWithAlias::children; /// ASTIdentifier is child free using ASTWithAlias::children; /// ASTIdentifier is child free
friend class ReplaceQueryParameterVisitor;
friend struct IdentifierSemantic; friend struct IdentifierSemantic;
friend ASTPtr createTableIdentifier(const StorageID & table_id);
friend void setIdentifierSpecial(ASTPtr & ast); friend void setIdentifierSpecial(ASTPtr & ast);
friend StorageID getTableIdentifier(const ASTPtr & ast);
void resetFullName(); void resetFullName();
}; };

View File

@ -1,4 +1,4 @@
#!/usr/bin/python3.8 #!/usr/bin/python3
import argparse import argparse
import collections import collections