dbms: get rid of columns inside Context [#METR-15553].

This commit is contained in:
Alexey Milovidov 2015-07-15 04:26:35 +03:00
parent e948f1d1c1
commit 226731128b
19 changed files with 53 additions and 65 deletions

View File

@ -92,7 +92,6 @@ private:
std::shared_ptr<QuotaForIntervals> quota; /// Текущая квота. По-умолчанию - пустая квота, которая ничего не ограничивает.
String current_database; /// Текущая БД.
String current_query_id; /// Id текущего запроса.
NamesAndTypesList columns; /// Столбцы текущей обрабатываемой таблицы.
Settings settings; /// Настройки выполнения запроса.
using ProgressCallback = std::function<void(const Progress & progress)>;
ProgressCallback progress_callback; /// Колбек для отслеживания прогресса выполнения запроса.
@ -207,11 +206,6 @@ public:
const Databases & getDatabases() const;
Databases & getDatabases();
/// При работе со списком столбцов, используйте локальный контекст, чтобы никто больше его не менял.
const NamesAndTypesList & getColumns() const { return columns; }
NamesAndTypesList & getColumns() { return columns; }
void setColumns(const NamesAndTypesList & columns_) { columns = columns_; }
Context & getSessionContext();
Context & getGlobalContext();

View File

@ -46,17 +46,18 @@ typedef std::unordered_map<String, SubqueryForSet> SubqueriesForSets;
class ExpressionAnalyzer : private boost::noncopyable
{
public:
ExpressionAnalyzer(const ASTPtr & ast_, const Context & context_, StoragePtr storage_, size_t subquery_depth_ = 0, bool do_global_ = false)
: ast(ast_), context(context_), settings(context.getSettings()),
subquery_depth(subquery_depth_), columns(context.getColumns()), storage(storage_ ? storage_ : getTable()), do_global(do_global_)
{
init();
}
/// columns - список известных столбцов (которых можно достать из таблицы).
ExpressionAnalyzer(const ASTPtr & ast_, const Context & context_, const NamesAndTypesList & columns_, size_t subquery_depth_ = 0, bool do_global_ = false)
: ast(ast_), context(context_), settings(context.getSettings()),
subquery_depth(subquery_depth_), columns(columns_), storage(getTable()), do_global(do_global_)
ExpressionAnalyzer(
const ASTPtr & ast_,
const Context & context_,
StoragePtr storage_,
const NamesAndTypesList & columns_,
size_t subquery_depth_ = 0,
bool do_global_ = false)
:
ast(ast_), context(context_), settings(context.getSettings()),
subquery_depth(subquery_depth_), columns(columns_),
storage(storage_ ? storage_ : getTable()),
do_global(do_global_)
{
init();
}

View File

@ -33,7 +33,7 @@ public:
* - удалить из запроса все столбцы кроме указанных - используется для удаления ненужных столбцов из подзапросов.
*
* table_column_names
* - поместить в контекст в качестве известных столбцов только указанные столбцы, а не все столбцы таблицы.
* - список доступных столбцов таблицы.
* Используется, например, совместно с указанием input.
*/
@ -56,7 +56,7 @@ public:
ASTPtr query_ptr_,
const Context & context_,
const Names & required_column_names,
const NamesAndTypesList & table_column_names,
const NamesAndTypesList & table_column_names_,
QueryProcessingStage::Enum to_stage_ = QueryProcessingStage::Complete,
size_t subquery_depth_ = 0,
BlockInputStreamPtr input = nullptr);
@ -84,7 +84,7 @@ public:
private:
/**
* ignore_union_all_tail
* - Оптимизация, если объект создаётся только, чтобы вызвать getSampleBlock(): учитываем только первый SELECT цепочки UNION ALL, потом что
* - Оптимизация, если объект создаётся только, чтобы вызвать getSampleBlock(): учитываем только первый SELECT цепочки UNION ALL, потому что
* первый SELECT достаточен для определения нужных столбцов.
*/
InterpreterSelectQuery(
@ -95,8 +95,8 @@ private:
size_t subquery_depth_ = 0,
BlockInputStreamPtr input = nullptr);
void init(BlockInputStreamPtr input, const Names & required_column_names = Names(), const NamesAndTypesList & table_column_names = NamesAndTypesList());
void basicInit(BlockInputStreamPtr input, const NamesAndTypesList & table_column_names);
void init(BlockInputStreamPtr input, const Names & required_column_names = Names{});
void basicInit(BlockInputStreamPtr input);
void initQueryAnalyzer();
/// Выполнить один запрос SELECT из цепочки UNION ALL.
@ -162,11 +162,12 @@ private:
size_t subquery_depth;
std::unique_ptr<ExpressionAnalyzer> query_analyzer;
BlockInputStreams streams;
NamesAndTypesList table_column_names;
/// Являемся ли мы первым запросом SELECT цепочки UNION ALL?
bool is_first_select_inside_union_all;
/// Следующий запрос SELECT в цепочке UNION ALL.
/// Следующий запрос SELECT в цепочке UNION ALL, если есть.
std::unique_ptr<InterpreterSelectQuery> next_select_in_union_all;
/// Таблица, откуда читать данные, если не подзапрос.

View File

@ -39,7 +39,7 @@ inline void evaluateMissingDefaults(Block & block,
* we are going to operate on a copy instead of the original block */
Block copy_block{block};
/// evaluate default values for defaulted columns
ExpressionAnalyzer{default_expr_list, context, required_columns}.getActions(true)->execute(copy_block);
ExpressionAnalyzer{default_expr_list, context, {}, required_columns}.getActions(true)->execute(copy_block);
/// move evaluated columns to the original block
for (auto & column_name_type : copy_block.getColumns())

View File

@ -22,7 +22,7 @@ namespace DB
/** pass a dummy column name because ExpressionAnalyzer
* does not work with no columns so far. */
ExpressionAnalyzer{
expr, context,
expr, context, {},
{ { "", new DataTypeString } }
}.getActions(false)->execute(block);

View File

@ -152,7 +152,7 @@ bool filterBlockWithQuery(ASTPtr query, Block & block, const Context & context)
return false;
/// Распарсим и вычислим выражение.
ExpressionAnalyzer analyzer(expression_ast, context, block.getColumnsList());
ExpressionAnalyzer analyzer(expression_ast, context, {}, block.getColumnsList());
ExpressionActionsPtr actions = analyzer.getActions(false);
actions->execute(block);

View File

@ -38,9 +38,8 @@ int main(int argc, char ** argv)
ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "");
Context context;
context.getColumns().push_back(NameAndTypePair("number", new DataTypeUInt64));
ExpressionAnalyzer analyzer(ast, context, context.getColumns());
ExpressionAnalyzer analyzer(ast, context, {}, {NameAndTypePair("number", new DataTypeUInt64)});
ExpressionActionsChain chain;
analyzer.appendSelect(chain, false);
analyzer.appendProjectResult(chain, false);

View File

@ -44,9 +44,8 @@ int main(int argc, char ** argv)
std::cerr << ast->getTreeID() << std::endl;
Context context;
context.getColumns().push_back(NameAndTypePair("number", new DataTypeUInt64));
ExpressionAnalyzer analyzer(ast, context, context.getColumns());
ExpressionAnalyzer analyzer(ast, context, {}, {NameAndTypePair("number", new DataTypeUInt64)});
ExpressionActionsChain chain;
analyzer.appendSelect(chain, false);
analyzer.appendProjectResult(chain, false);

View File

@ -98,8 +98,6 @@ int main(int argc, char ** argv)
Context context;
context.getColumns() = *names_and_types_list;
std::string input = "SELECT UniqID, URL, CounterID, IsLink WHERE URL = 'http://mail.yandex.ru/neo2/#inbox'";
ParserSelectQuery parser;
ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "");
@ -114,7 +112,7 @@ int main(int argc, char ** argv)
/// читаем из неё, применяем выражение, фильтруем, и пишем в tsv виде в консоль
ExpressionAnalyzer analyzer(ast, context, context.getColumns());
ExpressionAnalyzer analyzer(ast, context, nullptr, *names_and_types_list);
ExpressionActionsChain chain;
analyzer.appendSelect(chain, false);
analyzer.appendWhere(chain, false);

View File

@ -62,9 +62,8 @@ int main(int argc, char ** argv)
std::cerr << std::endl;
Context context;
context.getColumns().push_back(NameAndTypePair("number", new DataTypeUInt64));
ExpressionAnalyzer analyzer(ast, context, context.getColumns());
ExpressionAnalyzer analyzer(ast, context, {}, {NameAndTypePair("number", new DataTypeUInt64)});
ExpressionActionsChain chain;
analyzer.appendSelect(chain, false);
analyzer.appendProjectResult(chain, false);

View File

@ -336,7 +336,7 @@ InterpreterCreateQuery::ColumnsAndDefaults InterpreterCreateQuery::parseColumns(
/// set missing types and wrap default_expression's in a conversion-function if necessary
if (!defaulted_columns.empty())
{
const auto actions = ExpressionAnalyzer{default_expr_list, context, columns}.getActions(true);
const auto actions = ExpressionAnalyzer{default_expr_list, context, {}, columns}.getActions(true);
const auto block = actions->getSampleBlock();
for (auto & column : defaulted_columns)

View File

@ -38,7 +38,7 @@ namespace DB
InterpreterSelectQuery::~InterpreterSelectQuery() = default;
void InterpreterSelectQuery::init(BlockInputStreamPtr input, const Names & required_column_names, const NamesAndTypesList & table_column_names)
void InterpreterSelectQuery::init(BlockInputStreamPtr input, const Names & required_column_names)
{
ProfileEvents::increment(ProfileEvents::SelectQuery);
@ -70,14 +70,14 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input, const Names & requi
if (is_first_select_inside_union_all && hasAsterisk())
{
basicInit(input, table_column_names);
basicInit(input);
// Мы выполняем этот код именно здесь, потому что в противном случае следующего рода запрос бы не срабатывал:
// SELECT X FROM (SELECT * FROM (SELECT 1 AS X, 2 AS Y) UNION ALL SELECT 3, 4)
// из-за того, что астериски заменены столбцами только при создании объектов query_analyzer в basicInit().
renameColumns();
if (!required_column_names.empty() && (context.getColumns().size() != required_column_names.size()))
if (!required_column_names.empty() && (table_column_names.size() != required_column_names.size()))
{
rewriteExpressionList(required_column_names);
/// Теперь имеется устаревшая информация для выполнения запроса. Обновляем эту информацию.
@ -90,16 +90,16 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input, const Names & requi
if (!required_column_names.empty())
rewriteExpressionList(required_column_names);
basicInit(input, table_column_names);
basicInit(input);
}
}
void InterpreterSelectQuery::basicInit(BlockInputStreamPtr input_, const NamesAndTypesList & table_column_names)
void InterpreterSelectQuery::basicInit(BlockInputStreamPtr input_)
{
if (query.table && typeid_cast<ASTSelectQuery *>(&*query.table))
{
if (table_column_names.empty())
context.setColumns(InterpreterSelectQuery::getSampleBlock(query.table, context, to_stage, subquery_depth).getColumnsList());
table_column_names = InterpreterSelectQuery::getSampleBlock(query.table, context, to_stage, subquery_depth).getColumnsList();
}
else
{
@ -127,16 +127,13 @@ void InterpreterSelectQuery::basicInit(BlockInputStreamPtr input_, const NamesAn
table_lock = storage->lockStructure(false);
if (table_column_names.empty())
context.setColumns(storage->getColumnsListNonMaterialized());
table_column_names = storage->getColumnsListNonMaterialized();
}
if (!table_column_names.empty())
context.setColumns(table_column_names);
if (context.getColumns().empty())
if (table_column_names.empty())
throw Exception("There are no available columns", ErrorCodes::THERE_IS_NO_COLUMN);
query_analyzer.reset(new ExpressionAnalyzer(query_ptr, context, storage, subquery_depth, true));
query_analyzer.reset(new ExpressionAnalyzer(query_ptr, context, storage, table_column_names, subquery_depth, true));
/// Сохраняем в query context новые временные таблицы
for (auto & it : query_analyzer->getExternalTables())
@ -163,9 +160,10 @@ void InterpreterSelectQuery::basicInit(BlockInputStreamPtr input_, const NamesAn
void InterpreterSelectQuery::initQueryAnalyzer()
{
query_analyzer.reset(new ExpressionAnalyzer(query_ptr, context, storage, subquery_depth, true));
query_analyzer.reset(new ExpressionAnalyzer(query_ptr, context, storage, table_column_names, subquery_depth, true));
for (auto p = next_select_in_union_all.get(); p != nullptr; p = p->next_select_in_union_all.get())
p->query_analyzer.reset(new ExpressionAnalyzer(p->query_ptr, p->context, p->storage, p->subquery_depth, true));
p->query_analyzer.reset(new ExpressionAnalyzer(p->query_ptr, p->context, p->storage, p->table_column_names, p->subquery_depth, true));
}
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, QueryProcessingStage::Enum to_stage_,
@ -198,13 +196,13 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_,
const Names & required_column_names_,
const NamesAndTypesList & table_column_names, QueryProcessingStage::Enum to_stage_, size_t subquery_depth_, BlockInputStreamPtr input_)
const NamesAndTypesList & table_column_names_, QueryProcessingStage::Enum to_stage_, size_t subquery_depth_, BlockInputStreamPtr input_)
: query_ptr(query_ptr_), query(typeid_cast<ASTSelectQuery &>(*query_ptr)),
context(context_), to_stage(to_stage_), subquery_depth(subquery_depth_),
context(context_), to_stage(to_stage_), subquery_depth(subquery_depth_), table_column_names(table_column_names_),
is_first_select_inside_union_all(query.isUnionAllHead()),
log(&Logger::get("InterpreterSelectQuery"))
{
init(input_, required_column_names_, table_column_names);
init(input_, required_column_names_);
}
bool InterpreterSelectQuery::hasAsterisk() const

View File

@ -392,7 +392,7 @@ static Field convertToType(const Field & src, const IDataType & type)
static Field evaluateConstantExpression(ASTPtr & node, const Context & context)
{
ExpressionActionsPtr expr_for_constant_folding = ExpressionAnalyzer(
node, context, NamesAndTypesList{{ "_dummy", new DataTypeUInt8 }}).getConstActions();
node, context, nullptr, NamesAndTypesList{{ "_dummy", new DataTypeUInt8 }}).getConstActions();
/// В блоке должен быть хотя бы один столбец, чтобы у него было известно число строк.
Block block_with_constants{{ new ColumnConstUInt8(1, 0), new DataTypeUInt8, "_dummy" }};

View File

@ -52,9 +52,8 @@ int main(int argc, char ** argv)
{"s1", new DataTypeString},
{"s2", new DataTypeString}
};
context.setColumns(columns);
ExpressionAnalyzer analyzer(ast, context, context.getColumns());
ExpressionAnalyzer analyzer(ast, context, {}, columns);
ExpressionActionsChain chain;
analyzer.appendSelect(chain, false);
analyzer.appendProjectResult(chain, false);

View File

@ -296,7 +296,7 @@ namespace DB
defaulted_columns.emplace_back(column_name, nullptr);
}
const auto actions = ExpressionAnalyzer{default_expr_list, context, columns}.getActions(true);
const auto actions = ExpressionAnalyzer{default_expr_list, context, {}, columns}.getActions(true);
const auto block = actions->getSampleBlock();
/// set deduced types, modify default expression if necessary

View File

@ -103,9 +103,9 @@ MergeTreeData::MergeTreeData(
sort_descr.push_back(SortColumnDescription(name, 1));
}
primary_expr = ExpressionAnalyzer(primary_expr_ast, context, getColumnsList()).getActions(false);
primary_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumnsList()).getActions(false);
ExpressionActionsPtr projected_expr = ExpressionAnalyzer(primary_expr_ast, context, getColumnsList()).getActions(true);
ExpressionActionsPtr projected_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumnsList()).getActions(true);
primary_key_sample = projected_expr->getSampleBlock();
}
else if (mode != Unsorted)

View File

@ -230,7 +230,7 @@ BlockInputStreams MergeTreeDataSelectExecutor::read(
filter_function = upper_filter_function;
}
filter_expression = ExpressionAnalyzer(filter_function, data.context, data.getColumnsList()).getActions(false);
filter_expression = ExpressionAnalyzer(filter_function, data.context, nullptr, data.getColumnsList()).getActions(false);
/// Добавим столбцы, нужные для sampling_expression.
std::vector<String> add_columns = filter_expression->getRequiredColumns();
@ -247,7 +247,7 @@ BlockInputStreams MergeTreeDataSelectExecutor::read(
String prewhere_column;
if (select.prewhere_expression)
{
ExpressionAnalyzer analyzer(select.prewhere_expression, data.context, data.getColumnsList());
ExpressionAnalyzer analyzer(select.prewhere_expression, data.context, nullptr, data.getColumnsList());
prewhere_actions = analyzer.getActions(false);
prewhere_column = select.prewhere_expression->getColumnName();
SubqueriesForSets prewhere_subqueries = analyzer.getSubqueriesForSets();
@ -576,7 +576,7 @@ void MergeTreeDataSelectExecutor::createPositiveSignCondition(ExpressionActionsP
one->type = new DataTypeInt8;
one->value = Field(static_cast<Int64>(1));
out_expression = ExpressionAnalyzer(function_ptr, data.context, data.getColumnsList()).getActions(false);
out_expression = ExpressionAnalyzer(function_ptr, data.context, {}, data.getColumnsList()).getActions(false);
out_column = function->getColumnName();
}

View File

@ -151,7 +151,7 @@ PKCondition::PKCondition(ASTPtr query, const Context & context_, const NamesAndT
/** Вычисление выражений, зависящих только от констант.
* Чтобы индекс мог использоваться, если написано, например WHERE Date = toDate(now()).
*/
ExpressionActionsPtr expr_for_constant_folding = ExpressionAnalyzer(query, context_, all_columns).getConstActions();
ExpressionActionsPtr expr_for_constant_folding = ExpressionAnalyzer(query, context_, nullptr, all_columns).getConstActions();
Block block_with_constants;
/// В блоке должен быть хотя бы один столбец, чтобы у него было известно число строк.

View File

@ -64,7 +64,7 @@ StorageDistributed::StorageDistributed(
: name(name_), columns(columns_),
remote_database(remote_database_), remote_table(remote_table_),
context(context_), cluster(cluster_),
sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, *columns).getActions(false) : nullptr),
sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, *columns).getActions(false) : nullptr),
sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}),
write_enabled(!data_path_.empty() && (cluster.getLocalNodesNum() + cluster.pools.size() < 2 || sharding_key_)),
path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(name) + '/'))
@ -88,7 +88,7 @@ StorageDistributed::StorageDistributed(
name(name_), columns(columns_),
remote_database(remote_database_), remote_table(remote_table_),
context(context_), cluster(cluster_),
sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, *columns).getActions(false) : nullptr),
sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, *columns).getActions(false) : nullptr),
sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}),
write_enabled(!data_path_.empty() && (cluster.getLocalNodesNum() + cluster.pools.size() < 2 || sharding_key_)),
path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(name) + '/'))