2020-02-28 15:23:32 +00:00
|
|
|
#include <Interpreters/JoinedTables.h>
|
|
|
|
#include <Interpreters/Context.h>
|
|
|
|
#include <Interpreters/getTableExpressions.h>
|
|
|
|
#include <Storages/IStorage.h>
|
|
|
|
#include <Storages/ColumnsDescription.h>
|
2020-03-02 19:39:39 +00:00
|
|
|
#include <Storages/StorageValues.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
#include <Parsers/ASTSelectWithUnionQuery.h>
|
2020-03-08 11:07:05 +00:00
|
|
|
#include <Parsers/ASTTablesInSelectQuery.h>
|
2020-02-28 15:23:32 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int ALIAS_REQUIRED;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
2020-03-02 19:39:39 +00:00
|
|
|
template <typename T>
|
|
|
|
void checkTablesWithColumns(const std::vector<T> & tables_with_columns, const Context & context)
|
2020-02-28 15:23:32 +00:00
|
|
|
{
|
|
|
|
auto & settings = context.getSettingsRef();
|
|
|
|
if (settings.joined_subquery_requires_alias && tables_with_columns.size() > 1)
|
|
|
|
{
|
2020-03-02 19:39:39 +00:00
|
|
|
for (auto & t : tables_with_columns)
|
|
|
|
if (t.table.table.empty() && t.table.alias.empty())
|
2020-02-28 15:23:32 +00:00
|
|
|
throw Exception("No alias for subquery or table function in JOIN (set joined_subquery_requires_alias=0 to disable restriction).",
|
|
|
|
ErrorCodes::ALIAS_REQUIRED);
|
|
|
|
}
|
2020-03-02 19:39:39 +00:00
|
|
|
}
|
2020-02-28 15:23:32 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-03-08 11:07:05 +00:00
|
|
|
JoinedTables::JoinedTables(Context && context_, const ASTSelectQuery & select_query)
|
|
|
|
: context(context_)
|
|
|
|
, table_expressions(getTableExpressions(select_query))
|
2020-03-02 19:39:39 +00:00
|
|
|
, left_table_expression(extractTableExpression(select_query, 0))
|
|
|
|
, left_db_and_table(getDatabaseAndTable(select_query, 0))
|
|
|
|
{}
|
|
|
|
|
|
|
|
bool JoinedTables::isLeftTableSubquery() const
|
|
|
|
{
|
|
|
|
return left_table_expression && left_table_expression->as<ASTSelectWithUnionQuery>();
|
2020-02-28 15:23:32 +00:00
|
|
|
}
|
|
|
|
|
2020-03-02 19:39:39 +00:00
|
|
|
bool JoinedTables::isLeftTableFunction() const
|
|
|
|
{
|
|
|
|
return left_table_expression && left_table_expression->as<ASTFunction>();
|
|
|
|
}
|
2020-02-28 15:23:32 +00:00
|
|
|
|
2020-03-08 11:07:05 +00:00
|
|
|
std::unique_ptr<InterpreterSelectWithUnionQuery> JoinedTables::makeLeftTableSubquery(const SelectQueryOptions & select_options)
|
2020-02-28 15:23:32 +00:00
|
|
|
{
|
2020-03-08 11:07:05 +00:00
|
|
|
if (!isLeftTableSubquery())
|
|
|
|
return {};
|
|
|
|
return std::make_unique<InterpreterSelectWithUnionQuery>(left_table_expression, context, select_options);
|
|
|
|
}
|
|
|
|
|
|
|
|
StoragePtr JoinedTables::getLeftTableStorage()
|
|
|
|
{
|
|
|
|
if (isLeftTableSubquery())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
if (isLeftTableFunction())
|
|
|
|
return context.executeTableFunction(left_table_expression);
|
2020-03-02 19:39:39 +00:00
|
|
|
|
|
|
|
if (left_db_and_table)
|
|
|
|
{
|
|
|
|
database_name = left_db_and_table->database;
|
|
|
|
table_name = left_db_and_table->table;
|
|
|
|
|
|
|
|
/// If the database is not specified - use the current database.
|
|
|
|
if (database_name.empty() && !context.isExternalTableExist(table_name))
|
|
|
|
database_name = context.getCurrentDatabase();
|
|
|
|
}
|
|
|
|
else /// If the table is not specified - use the table `system.one`.
|
|
|
|
{
|
|
|
|
database_name = "system";
|
|
|
|
table_name = "one";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto view_source = context.getViewSource())
|
|
|
|
{
|
|
|
|
auto & storage_values = static_cast<const StorageValues &>(*view_source);
|
|
|
|
auto tmp_table_id = storage_values.getStorageID();
|
|
|
|
if (tmp_table_id.database_name == database_name && tmp_table_id.table_name == table_name)
|
|
|
|
{
|
|
|
|
/// Read from view source.
|
2020-03-08 11:07:05 +00:00
|
|
|
return context.getViewSource();
|
2020-03-02 19:39:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 11:07:05 +00:00
|
|
|
/// Read from table. Even without table expression (implicit SELECT ... FROM system.one).
|
2020-03-10 10:15:27 +00:00
|
|
|
auto table_id = context.resolveStorageID({database_name, table_name});
|
|
|
|
return DatabaseCatalog::instance().getTable(table_id);
|
2020-03-02 19:39:39 +00:00
|
|
|
}
|
|
|
|
|
2020-03-08 11:07:05 +00:00
|
|
|
bool JoinedTables::resolveTables()
|
2020-03-02 19:39:39 +00:00
|
|
|
{
|
|
|
|
tables_with_columns = getDatabaseAndTablesWithColumns(table_expressions, context);
|
|
|
|
checkTablesWithColumns(tables_with_columns, context);
|
2020-02-28 15:23:32 +00:00
|
|
|
|
2020-03-08 11:07:05 +00:00
|
|
|
return !tables_with_columns.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JoinedTables::makeFakeTable(StoragePtr storage, const Block & source_header)
|
|
|
|
{
|
|
|
|
if (storage)
|
2020-02-28 15:23:32 +00:00
|
|
|
{
|
2020-03-02 19:39:39 +00:00
|
|
|
const ColumnsDescription & storage_columns = storage->getColumns();
|
|
|
|
tables_with_columns.emplace_back(DatabaseAndTableWithAlias{}, storage_columns.getOrdinary());
|
2020-03-08 11:07:05 +00:00
|
|
|
|
2020-03-02 19:39:39 +00:00
|
|
|
auto & table = tables_with_columns.back();
|
|
|
|
table.addHiddenColumns(storage_columns.getMaterialized());
|
|
|
|
table.addHiddenColumns(storage_columns.getAliases());
|
|
|
|
table.addHiddenColumns(storage_columns.getVirtuals());
|
2020-02-28 15:23:32 +00:00
|
|
|
}
|
2020-03-08 11:07:05 +00:00
|
|
|
else
|
|
|
|
tables_with_columns.emplace_back(DatabaseAndTableWithAlias{}, source_header.getNamesAndTypesList());
|
2020-02-28 15:23:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|