Merge pull request #7758 from 4ertus2/ast

Check if table has qualified column
This commit is contained in:
alexey-milovidov 2019-11-18 01:37:48 +03:00 committed by GitHub
commit 3735a7e210
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 43 additions and 1 deletions

View File

@ -132,6 +132,15 @@ std::pair<String, String> IdentifierSemantic::extractDatabaseAndTable(const ASTI
return { "", identifier.name };
}
std::optional<String> IdentifierSemantic::extractNestedName(const ASTIdentifier & identifier, const String & table_name)
{
if (identifier.name_parts.size() == 3 && table_name == identifier.name_parts[0])
return identifier.name_parts[1] + '.' + identifier.name_parts[2];
else if (identifier.name_parts.size() == 2)
return identifier.name_parts[0] + '.' + identifier.name_parts[1];
return {};
}
bool IdentifierSemantic::doesIdentifierBelongTo(const ASTIdentifier & identifier, const String & database, const String & table)
{
size_t num_components = identifier.name_parts.size();

View File

@ -36,6 +36,7 @@ struct IdentifierSemantic
static std::optional<String> getTableName(const ASTIdentifier & node);
static std::optional<String> getTableName(const ASTPtr & ast);
static std::pair<String, String> extractDatabaseAndTable(const ASTIdentifier & identifier);
static std::optional<String> extractNestedName(const ASTIdentifier & identifier, const String & table_name);
static ColumnMatch canReferColumnToTable(const ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table);
static void setColumnShortName(ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table);

View File

@ -29,6 +29,26 @@ namespace ErrorCodes
extern const int LOGICAL_ERROR;
}
bool TranslateQualifiedNamesMatcher::Data::unknownColumn(size_t table_pos, const ASTIdentifier & identifier) const
{
const auto & table = tables[table_pos].first;
auto nested1 = IdentifierSemantic::extractNestedName(identifier, table.table);
auto nested2 = IdentifierSemantic::extractNestedName(identifier, table.alias);
String short_name = identifier.shortName();
const Names & column_names = tables[table_pos].second;
for (auto & known_name : column_names)
{
if (short_name == known_name)
return false;
if (nested1 && *nested1 == known_name)
return false;
if (nested2 && *nested2 == known_name)
return false;
}
return !column_names.empty();
}
bool TranslateQualifiedNamesMatcher::needChildVisit(ASTPtr & node, const ASTPtr & child)
{
/// Do not go to FROM, JOIN, subqueries.
@ -66,6 +86,13 @@ void TranslateQualifiedNamesMatcher::visit(ASTIdentifier & identifier, ASTPtr &,
bool allow_ambiguous = data.join_using_columns.count(short_name);
if (IdentifierSemantic::chooseTable(identifier, data.tables, table_pos, allow_ambiguous))
{
if (data.unknownColumn(table_pos, identifier))
{
String table_name = data.tables[table_pos].first.getQualifiedNamePrefix(false);
throw Exception("There's no column '" + identifier.name + "' in table '" + table_name + "'",
ErrorCodes::UNKNOWN_IDENTIFIER);
}
IdentifierSemantic::setMembership(identifier, table_pos);
/// In case if column from the joined table are in source columns, change it's name to qualified.

View File

@ -38,6 +38,7 @@ public:
bool hasColumn(const String & name) const { return source_columns.count(name); }
bool hasTable() const { return !tables.empty(); }
bool processAsterisks() const { return hasTable() && has_columns; }
bool unknownColumn(size_t table_pos, const ASTIdentifier & node) const;
static std::vector<TableWithColumnNames> tablesOnly(const std::vector<DatabaseAndTableWithAlias> & tables)
{

View File

@ -1,7 +1,7 @@
SELECT
q0.dt,
q0.cnt,
q0.cnt2
q1.cnt2
FROM
(
SELECT

View File

@ -0,0 +1,3 @@
SELECT l.c FROM (SELECT 1 AS a, 2 AS b) AS l join (SELECT 2 AS b, 3 AS c) AS r USING b; -- { serverError 47 }
SELECT r.a FROM (SELECT 1 AS a, 2 AS b) AS l join (SELECT 2 AS b, 3 AS c) AS r USING b; -- { serverError 47 }
SELECT l.a, r.c FROM (SELECT 1 AS a, 2 AS b) AS l join (SELECT 2 AS b, 3 AS c) AS r USING b;