2019-01-25 15:42:24 +00:00
|
|
|
#include <Common/typeid_cast.h>
|
|
|
|
|
|
|
|
#include <Interpreters/IdentifierSemantic.h>
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2019-10-16 17:33:53 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
const DatabaseAndTableWithAlias & extractTable(const DatabaseAndTableWithAlias & table)
|
|
|
|
{
|
|
|
|
return table;
|
|
|
|
}
|
|
|
|
|
|
|
|
const DatabaseAndTableWithAlias & extractTable(const TableWithColumnNames & table)
|
|
|
|
{
|
|
|
|
return table.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool tryChooseTable(const ASTIdentifier & identifier, const std::vector<T> & tables, size_t & best_table_pos)
|
|
|
|
{
|
|
|
|
best_table_pos = 0;
|
|
|
|
size_t best_match = 0;
|
|
|
|
for (size_t i = 0; i < tables.size(); ++i)
|
|
|
|
if (size_t match = IdentifierSemantic::canReferColumnToTable(identifier, extractTable(tables[i])))
|
|
|
|
if (match > best_match)
|
|
|
|
{
|
|
|
|
best_match = match;
|
|
|
|
best_table_pos = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return best_match;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-25 15:42:24 +00:00
|
|
|
std::optional<String> IdentifierSemantic::getColumnName(const ASTIdentifier & node)
|
|
|
|
{
|
|
|
|
if (!node.semantic->special)
|
|
|
|
return node.name;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<String> IdentifierSemantic::getColumnName(const ASTPtr & ast)
|
|
|
|
{
|
|
|
|
if (ast)
|
2019-03-11 13:22:51 +00:00
|
|
|
if (const auto * id = ast->as<ASTIdentifier>())
|
2019-01-25 15:42:24 +00:00
|
|
|
if (!id->semantic->special)
|
|
|
|
return id->name;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<String> IdentifierSemantic::getTableName(const ASTIdentifier & node)
|
|
|
|
{
|
|
|
|
if (node.semantic->special)
|
|
|
|
return node.name;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<String> IdentifierSemantic::getTableName(const ASTPtr & ast)
|
|
|
|
{
|
|
|
|
if (ast)
|
2019-03-11 13:22:51 +00:00
|
|
|
if (const auto * id = ast->as<ASTIdentifier>())
|
2019-01-25 15:42:24 +00:00
|
|
|
if (id->semantic->special)
|
|
|
|
return id->name;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2019-02-07 19:18:40 +00:00
|
|
|
void IdentifierSemantic::setNeedLongName(ASTIdentifier & identifier, bool value)
|
|
|
|
{
|
|
|
|
identifier.semantic->need_long_name = value;
|
|
|
|
}
|
|
|
|
|
2019-02-11 19:14:57 +00:00
|
|
|
bool IdentifierSemantic::canBeAlias(const ASTIdentifier & identifier)
|
|
|
|
{
|
|
|
|
return identifier.semantic->can_be_alias;
|
|
|
|
}
|
|
|
|
|
2019-02-13 15:18:02 +00:00
|
|
|
void IdentifierSemantic::setMembership(ASTIdentifier & identifier, size_t table_no)
|
|
|
|
{
|
|
|
|
identifier.semantic->membership = table_no;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t IdentifierSemantic::getMembership(const ASTIdentifier & identifier)
|
|
|
|
{
|
|
|
|
return identifier.semantic->membership;
|
|
|
|
}
|
2019-02-11 19:14:57 +00:00
|
|
|
|
2019-10-16 17:33:53 +00:00
|
|
|
bool IdentifierSemantic::chooseTable(const ASTIdentifier & identifier, const std::vector<DatabaseAndTableWithAlias> & tables,
|
|
|
|
size_t & best_table_pos)
|
2019-10-16 14:47:58 +00:00
|
|
|
{
|
2019-10-16 17:33:53 +00:00
|
|
|
return tryChooseTable<DatabaseAndTableWithAlias>(identifier, tables, best_table_pos);
|
|
|
|
}
|
2019-10-16 14:47:58 +00:00
|
|
|
|
2019-10-16 17:33:53 +00:00
|
|
|
bool IdentifierSemantic::chooseTable(const ASTIdentifier & identifier, const std::vector<TableWithColumnNames> & tables,
|
|
|
|
size_t & best_table_pos)
|
|
|
|
{
|
|
|
|
return tryChooseTable<TableWithColumnNames>(identifier, tables, best_table_pos);
|
2019-10-16 14:47:58 +00:00
|
|
|
}
|
|
|
|
|
2019-01-25 15:42:24 +00:00
|
|
|
std::pair<String, String> IdentifierSemantic::extractDatabaseAndTable(const ASTIdentifier & identifier)
|
|
|
|
{
|
|
|
|
if (identifier.name_parts.size() > 2)
|
|
|
|
throw Exception("Logical error: more than two components in table expression", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
if (identifier.name_parts.size() == 2)
|
|
|
|
return { identifier.name_parts[0], identifier.name_parts[1] };
|
|
|
|
return { "", identifier.name };
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IdentifierSemantic::doesIdentifierBelongTo(const ASTIdentifier & identifier, const String & database, const String & table)
|
|
|
|
{
|
|
|
|
size_t num_components = identifier.name_parts.size();
|
|
|
|
if (num_components >= 3)
|
|
|
|
return identifier.name_parts[0] == database &&
|
|
|
|
identifier.name_parts[1] == table;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IdentifierSemantic::doesIdentifierBelongTo(const ASTIdentifier & identifier, const String & table)
|
|
|
|
{
|
|
|
|
size_t num_components = identifier.name_parts.size();
|
|
|
|
if (num_components >= 2)
|
|
|
|
return identifier.name_parts[0] == table;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t IdentifierSemantic::canReferColumnToTable(const ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table)
|
|
|
|
{
|
|
|
|
/// database.table.column
|
|
|
|
if (doesIdentifierBelongTo(identifier, db_and_table.database, db_and_table.table))
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
/// table.column or alias.column.
|
|
|
|
if (doesIdentifierBelongTo(identifier, db_and_table.table) ||
|
|
|
|
doesIdentifierBelongTo(identifier, db_and_table.alias))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks that ast is ASTIdentifier and remove num_qualifiers_to_strip components from left.
|
|
|
|
/// Example: 'database.table.name' -> (num_qualifiers_to_strip = 2) -> 'name'.
|
|
|
|
void IdentifierSemantic::setColumnShortName(ASTIdentifier & identifier, size_t to_strip)
|
|
|
|
{
|
|
|
|
if (!to_strip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::vector<String> stripped(identifier.name_parts.begin() + to_strip, identifier.name_parts.end());
|
|
|
|
|
|
|
|
DB::String new_name;
|
|
|
|
for (const auto & part : stripped)
|
|
|
|
{
|
|
|
|
if (!new_name.empty())
|
|
|
|
new_name += '.';
|
|
|
|
new_name += part;
|
|
|
|
}
|
|
|
|
identifier.name.swap(new_name);
|
|
|
|
}
|
|
|
|
|
2019-02-07 19:18:40 +00:00
|
|
|
void IdentifierSemantic::setColumnNormalName(ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table)
|
2019-01-25 15:42:24 +00:00
|
|
|
{
|
2019-02-07 19:18:40 +00:00
|
|
|
size_t match = IdentifierSemantic::canReferColumnToTable(identifier, db_and_table);
|
|
|
|
|
|
|
|
setColumnShortName(identifier, match);
|
2019-02-11 19:14:57 +00:00
|
|
|
if (match)
|
|
|
|
identifier.semantic->can_be_alias = false;
|
2019-02-07 19:18:40 +00:00
|
|
|
|
|
|
|
if (identifier.semantic->need_long_name)
|
2019-02-20 12:12:36 +00:00
|
|
|
setColumnLongName(identifier, db_and_table);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IdentifierSemantic::setColumnLongName(ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table)
|
|
|
|
{
|
|
|
|
String prefix = db_and_table.getQualifiedNamePrefix();
|
|
|
|
if (!prefix.empty())
|
2019-02-07 19:18:40 +00:00
|
|
|
{
|
2019-02-20 12:12:36 +00:00
|
|
|
String short_name = identifier.shortName();
|
|
|
|
identifier.name = prefix + short_name;
|
|
|
|
prefix.resize(prefix.size() - 1); /// crop dot
|
|
|
|
identifier.name_parts = {prefix, short_name};
|
2019-02-07 19:18:40 +00:00
|
|
|
}
|
2019-01-25 15:42:24 +00:00
|
|
|
}
|
|
|
|
|
2019-02-08 15:37:43 +00:00
|
|
|
String IdentifierSemantic::columnNormalName(const ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table)
|
|
|
|
{
|
|
|
|
ASTPtr copy = identifier.clone();
|
2019-03-15 16:14:13 +00:00
|
|
|
setColumnNormalName(copy->as<ASTIdentifier &>(), db_and_table);
|
2019-02-08 15:37:43 +00:00
|
|
|
return copy->getAliasOrColumnName();
|
|
|
|
}
|
|
|
|
|
2019-02-20 12:12:36 +00:00
|
|
|
String IdentifierSemantic::columnLongName(const ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table)
|
|
|
|
{
|
|
|
|
return db_and_table.getQualifiedNamePrefix() + identifier.shortName();
|
|
|
|
}
|
|
|
|
|
2019-01-25 15:42:24 +00:00
|
|
|
}
|