dbms: development [#CONV-2944].

This commit is contained in:
Alexey Milovidov 2012-08-27 05:13:14 +00:00
parent 312b007e6f
commit 44aa02f806
19 changed files with 403 additions and 22 deletions

View File

@ -24,8 +24,6 @@ class ColumnArray : public IColumn
{ {
public: public:
/** По индексу i находится смещение до начала i + 1 -го элемента. */ /** По индексу i находится смещение до начала i + 1 -го элемента. */
typedef UInt32 Offset_t;
typedef std::vector<Offset_t> Offsets_t;
typedef ColumnVector<Offset_t> ColumnOffsets_t; typedef ColumnVector<Offset_t> ColumnOffsets_t;
/** Создать пустой столбец массивов, с типом значений, как в столбце nested_column */ /** Создать пустой столбец массивов, с типом значений, как в столбце nested_column */
@ -136,6 +134,11 @@ public:
tmp.swap(getOffsets()); tmp.swap(getOffsets());
} }
void replicate(const Offsets_t & offsets)
{
throw Exception("Replication of column Array is not implemented.", ErrorCodes::NOT_IMPLEMENTED);
}
void permute(const Permutation & perm) void permute(const Permutation & perm)
{ {
size_t size = getOffsets().size(); size_t size = getOffsets().size();

View File

@ -51,6 +51,9 @@ public:
void filter(const Filter & filt) void filter(const Filter & filt)
{ {
if (s != filt.size())
throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
size_t new_size = 0; size_t new_size = 0;
for (Filter::const_iterator it = filt.begin(); it != filt.end(); ++it) for (Filter::const_iterator it = filt.begin(); it != filt.end(); ++it)
if (*it) if (*it)
@ -58,6 +61,14 @@ public:
s = new_size; s = new_size;
} }
void replicate(const Offsets_t & offsets)
{
if (s != offsets.size())
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
s = offsets.back();
}
size_t byteSize() const { return sizeof(data) + sizeof(s); } size_t byteSize() const { return sizeof(data) + sizeof(s); }
void permute(const Permutation & perm) void permute(const Permutation & perm)

View File

@ -96,6 +96,11 @@ public:
data->filter(nested_filt); data->filter(nested_filt);
} }
void replicate(const Offsets_t & offsets)
{
throw Exception("Replication of column FixedArray is not implemented.", ErrorCodes::NOT_IMPLEMENTED);
}
void permute(const Permutation & perm) void permute(const Permutation & perm)
{ {
size_t size = this->size(); size_t size = this->size();

View File

@ -77,6 +77,29 @@ public:
std::sort(res.begin(), res.end(), less(*this)); std::sort(res.begin(), res.end(), less(*this));
return res; return res;
} }
void replicate(const Offsets_t & offsets)
{
size_t col_size = size();
if (col_size != offsets.size())
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
ColumnUInt8::Container_t tmp;
tmp.reserve(n * offsets.back());
Offset_t prev_offset = 0;
for (size_t i = 0; i < col_size; ++i)
{
size_t size_to_replicate = offsets[i] - prev_offset;
prev_offset = offsets[i];
for (size_t j = 0; j < size_to_replicate; ++j)
for (size_t k = 0; k < n; ++k)
tmp.push_back(char_data[i * n + k]);
}
tmp.swap(char_data);
}
}; };

View File

@ -50,6 +50,12 @@ public:
return res; return res;
} }
void replicate(const Offsets_t & offsets)
{
if (s != offsets.size())
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
}
SetPtr & getData() { return data; } SetPtr & getData() { return data; }
const SetPtr & getData() const { return data; } const SetPtr & getData() const { return data; }

View File

@ -91,6 +91,43 @@ public:
std::sort(res.begin(), res.end(), less(*this)); std::sort(res.begin(), res.end(), less(*this));
return res; return res;
} }
void replicate(const Offsets_t & replicate_offsets)
{
size_t col_size = size();
if (col_size != replicate_offsets.size())
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
ColumnUInt8::Container_t tmp_chars;
Offsets_t tmp_offsets;
tmp_chars.reserve(char_data.size() / col_size * replicate_offsets.back());
tmp_offsets.reserve(replicate_offsets.back());
Offset_t prev_replicate_offset = 0;
Offset_t prev_string_offset = 0;
Offset_t current_new_offset = 0;
for (size_t i = 0; i < col_size; ++i)
{
size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset;
size_t string_size = getOffsets()[i] - prev_string_offset;
for (size_t j = 0; j < size_to_replicate; ++j)
{
current_new_offset += string_size;
tmp_offsets.push_back(current_new_offset);
for (size_t k = 0; k < string_size; ++k)
tmp_chars.push_back(char_data[prev_string_offset + k]);
}
prev_replicate_offset = replicate_offsets[i];
prev_string_offset = getOffsets()[i];
}
tmp_chars.swap(char_data);
tmp_offsets.swap(getOffsets());
}
}; };

View File

@ -69,12 +69,13 @@ public:
} }
/** В следующих трёх функциях ничего не делаем, так как столбцы - элементы tuple обычно содержатся в блоке вместе с tuple, /** В следующих функциях ничего не делаем, так как столбцы - элементы tuple обычно содержатся в блоке вместе с tuple,
* и соответствующие операции применяются к ним также. То есть, операции будут применены к tuple автоматически. * и соответствующие операции применяются к ним также. То есть, операции будут применены к tuple автоматически.
*/ */
void cut(size_t start, size_t length) {} void cut(size_t start, size_t length) {}
void filter(const Filter & filt) {} void filter(const Filter & filt) {}
void permute(const Permutation & perm) {} void permute(const Permutation & perm) {}
void replicate(const Offsets_t & offsets) {}
int compareAt(size_t n, size_t m, const IColumn & rhs) const int compareAt(size_t n, size_t m, const IColumn & rhs) const
{ {

View File

@ -145,6 +145,28 @@ public:
return res; return res;
} }
void replicate(const Offsets_t & offsets)
{
size_t size = data.size();
if (size != offsets.size())
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
Container_t tmp;
tmp.reserve(offsets.back());
Offset_t prev_offset = 0;
for (size_t i = 0; i < size; ++i)
{
size_t size_to_replicate = offsets[i] - prev_offset;
prev_offset = offsets[i];
for (size_t j = 0; j < size_to_replicate; ++j)
tmp.push_back(data[i]);
}
tmp.swap(data);
}
/** Более эффективные методы манипуляции */ /** Более эффективные методы манипуляции */
Container_t & getData() Container_t & getData()
{ {

View File

@ -97,6 +97,13 @@ public:
*/ */
virtual Permutation getPermutation() const = 0; virtual Permutation getPermutation() const = 0;
/** Размножить все значения столько раз, сколько прописано в offsets.
* (i-е значение размножается в offsets[i] - offsets[i - 1] значений.)
*/
typedef UInt32 Offset_t;
typedef std::vector<Offset_t> Offsets_t;
virtual void replicate(const Offsets_t & offsets) = 0;
/** Очистить */ /** Очистить */
virtual void clear() = 0; virtual void clear() = 0;

View File

@ -133,6 +133,7 @@ namespace ErrorCodes
CANNOT_GET_RETURN_TYPE, CANNOT_GET_RETURN_TYPE,
ILLEGAL_INDEX, ILLEGAL_INDEX,
TOO_LARGE_ARRAY_SIZE, TOO_LARGE_ARRAY_SIZE,
FUNCTION_IS_SPECIAL,
POCO_EXCEPTION = 1000, POCO_EXCEPTION = 1000,
STD_EXCEPTION, STD_EXCEPTION,

View File

@ -0,0 +1,98 @@
#pragma once
#include <Poco/SharedPtr.h>
#include <DB/Columns/ColumnConst.h>
#include <DB/Columns/ColumnArray.h>
#include <DB/DataTypes/DataTypeArray.h>
#include <DB/DataStreams/IProfilingBlockInputStream.h>
namespace DB
{
/** Реализует операцию ARRAY JOIN.
* (Для удобства, эта операция записывается, как функция arrayJoin, применённая к массиву.)
* Эта операция размножает все строки столько раз, сколько элементов в массиве.
* Результат функции arrayJoin - столбец единичных значений соответствующих элементов.
*
* Например,
*
* name arr
* ------ ------
* 'вася' [1, 2]
* 'петя' []
*
* преобразуется в
*
* name arrayJoin(arr)
* ------ --------------
* 'вася' 1
* 'вася' 2
*/
class ArrayJoiningBlockInputStream : public IProfilingBlockInputStream
{
public:
ArrayJoiningBlockInputStream(BlockInputStreamPtr input_, ssize_t array_column_)
: input(input_), array_column(array_column_)
{
children.push_back(input);
}
ArrayJoiningBlockInputStream(BlockInputStreamPtr input_, const String & array_column_name_)
: input(input_), array_column(-1), array_column_name(array_column_name_)
{
children.push_back(input);
}
Block readImpl()
{
Block block = input->read();
if (!block)
return block;
if (-1 == array_column)
array_column = block.getPositionByName(array_column_name);
ColumnPtr & array = block.getByPosition(array_column).column;
if (array->isConst())
array = dynamic_cast<const IColumnConst &>(*array).convertToFullColumn();
size_t columns = block.columns();
for (size_t i = 0; i < columns; ++i)
{
ColumnWithNameAndType & current = block.getByPosition(i);
if (static_cast<ssize_t>(i) == array_column)
{
ColumnWithNameAndType result;
result.column = dynamic_cast<const ColumnArray &>(*current.column).getDataPtr();
result.type = dynamic_cast<const DataTypeArray &>(*current.type).getNestedType();
result.name = "arrayJoin(" + current.name + ")";
block.erase(i);
block.insert(result);
}
else
current.column->replicate(dynamic_cast<const ColumnArray &>(*array).getOffsets());
}
return block;
}
String getName() const { return "ArrayJoiningBlockInputStream"; }
BlockInputStreamPtr clone() { return new ArrayJoiningBlockInputStream(input, array_column); }
private:
BlockInputStreamPtr input;
ssize_t array_column;
String array_column_name;
};
}

View File

@ -43,18 +43,26 @@ public:
void deserializeTextQuoted(Field & field, ReadBuffer & istr) const; void deserializeTextQuoted(Field & field, ReadBuffer & istr) const;
/** Потоковая сериализация массивов устроена по-особенному: /** Потоковая сериализация массивов устроена по-особенному:
* - запиваются/читаются элементы, уложенные подряд, без смещений; * - запиваются/читаются элементы, уложенные подряд, без размеров массивов;
* - смещения записываются/читаются в отдельный столбец, * - размеры записываются/читаются в отдельный столбец,
* и о записи/чтении смещений должна позаботиться вызывающая сторона. * и о записи/чтении размеров должна позаботиться вызывающая сторона.
* Это нужно, так как при реализации вложенных структур, несколько массивов могут иметь общие смещения. * Это нужно, так как при реализации вложенных структур, несколько массивов могут иметь общие размеры.
*/ */
/** Записать только значения, без смещений. Вызывающая сторона также должна куда-нибудь записать смещения. */ /** Записать только значения, без размеров. Вызывающая сторона также должна куда-нибудь записать смещения. */
void serializeBinary(const IColumn & column, WriteBuffer & ostr, WriteCallback callback = WriteCallback()) const; void serializeBinary(const IColumn & column, WriteBuffer & ostr, WriteCallback callback = WriteCallback()) const;
/** Прочитать только значения, без смещений. При этом, в column уже заранее должны быть считаны все смещения. */ /** Прочитать только значения, без размеров.
* При этом, в column уже заранее должны быть считаны все размеры.
*/
void deserializeBinary(IColumn & column, ReadBuffer & istr, size_t limit) const; void deserializeBinary(IColumn & column, ReadBuffer & istr, size_t limit) const;
/** Записать размеры. */
void serializeOffsets(const IColumn & column, WriteBuffer & ostr, WriteCallback callback = WriteCallback()) const;
/** Прочитать размеры. Вызывайте этот метод перед чтением значений. */
void deserializeOffsets(IColumn & column, ReadBuffer & istr, size_t limit) const;
ColumnPtr createColumn() const; ColumnPtr createColumn() const;
ColumnPtr createConstColumn(size_t size, const Field & field) const; ColumnPtr createConstColumn(size_t size, const Field & field) const;

View File

@ -38,6 +38,9 @@ namespace DB
* *
* tuple(x, y, ...) - функция, позволяющая сгруппировать несколько столбцов * tuple(x, y, ...) - функция, позволяющая сгруппировать несколько столбцов
* tupleElement(tuple, n) - функция, позволяющая достать столбец из tuple. * tupleElement(tuple, n) - функция, позволяющая достать столбец из tuple.
*
* arrayJoin(arr) - особая функция - выполнить её напрямую нельзя;
* используется только чтобы получить тип результата соответствующего выражения.
*/ */
@ -561,4 +564,34 @@ public:
} }
}; };
class FunctionArrayJoin : public IFunction
{
public:
/// Получить имя функции.
String getName() const
{
return "arrayJoin";
}
/// Получить тип результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение.
DataTypePtr getReturnType(const DataTypes & arguments) const
{
if (arguments.size() != 1)
throw Exception("Function arrayJoin requires exactly one argument.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
const DataTypeArray * arr = dynamic_cast<const DataTypeArray *>(&*arguments[0]);
if (!arr)
throw Exception("Argument for function arrayJoin must be Array.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
return arr->getNestedType()->clone();
}
/// Выполнить функцию над блоком.
void execute(Block & block, const ColumnNumbers & arguments, size_t result)
{
throw Exception("Function arrayJoin must not be executed directly.", ErrorCodes::FUNCTION_IS_SPECIAL);
}
};
} }

View File

@ -75,7 +75,16 @@ public:
/** Пометить то, что должно быть вычислено до агрегирования одним part_id, /** Пометить то, что должно быть вычислено до агрегирования одним part_id,
* а то, что должно быть вычислено после агрегирования, а также сами агрегатные функции - другим part_id. * а то, что должно быть вычислено после агрегирования, а также сами агрегатные функции - другим part_id.
*/ */
void markBeforeAndAfterAggregation(unsigned before_part_id, unsigned after_part_id); void markBeforeAggregation(unsigned before_part_id);
/** Получить информацию об операции arrayJoin, если она есть.
* Если есть - в column_name будет записано имя столбца, находящегося внутри arrayJoin.
*/
bool getArrayJoinInfo(String & column_name);
/** Пометить то, что должно быть вычислено до применения операции arrayJoin.
*/
void markBeforeArrayJoin(unsigned part_id);
private: private:
ASTPtr ast; ASTPtr ast;
@ -125,12 +134,16 @@ private:
bool hasAggregatesImpl(ASTPtr ast); bool hasAggregatesImpl(ASTPtr ast);
void markBeforeAndAfterAggregationImpl(ASTPtr ast, unsigned before_part_id, unsigned after_part_id, bool below = false); void markBeforeAggregationImpl(ASTPtr ast, unsigned before_part_id, bool below = false);
void makeSetsImpl(ASTPtr ast); void makeSetsImpl(ASTPtr ast);
void resolveScalarSubqueriesImpl(ASTPtr & ast); void resolveScalarSubqueriesImpl(ASTPtr & ast);
bool getArrayJoinInfoImpl(ASTPtr ast, String & column_name);
void markBeforeArrayJoinImpl(ASTPtr ast, unsigned part_id, bool below = false);
/// Получить тип у функции, идентификатора или литерала. /// Получить тип у функции, идентификатора или литерала.
DataTypePtr getType(ASTPtr ast); DataTypePtr getType(ASTPtr ast);
}; };

View File

@ -59,8 +59,8 @@ private:
PART_GROUP = 8, PART_GROUP = 8,
PART_HAVING = 16, PART_HAVING = 16,
PART_ORDER = 32, PART_ORDER = 32,
PART_BEFORE_AGGREGATING = 64, /// Под агрегатной функцией, или в ветке, не содержащей агрегатных функций PART_BEFORE_AGGREGATING = 64, /// Под агрегатной функцией
PART_AFTER_AGGREGATING = 128, PART_BEFORE_ARRAY_JOIN = 128, /// Под функцией arrayJoin
}; };
@ -69,6 +69,7 @@ private:
/// Вынимает данные из таблицы. Возвращает стадию, до которой запрос был обработан в Storage. /// Вынимает данные из таблицы. Возвращает стадию, до которой запрос был обработан в Storage.
QueryProcessingStage::Enum executeFetchColumns(BlockInputStreams & streams, ExpressionPtr & expression); QueryProcessingStage::Enum executeFetchColumns(BlockInputStreams & streams, ExpressionPtr & expression);
void executeArrayJoin( BlockInputStreams & streams, ExpressionPtr & expression);
void executeWhere( BlockInputStreams & streams, ExpressionPtr & expression); void executeWhere( BlockInputStreams & streams, ExpressionPtr & expression);
void executeAggregation( BlockInputStreams & streams, ExpressionPtr & expression); void executeAggregation( BlockInputStreams & streams, ExpressionPtr & expression);
void executeMergeAggregated( BlockInputStreams & streams, ExpressionPtr & expression); void executeMergeAggregated( BlockInputStreams & streams, ExpressionPtr & expression);

View File

@ -13,6 +13,7 @@
namespace DB namespace DB
{ {
DataTypeArray::DataTypeArray(DataTypePtr nested_) : nested(nested_) DataTypeArray::DataTypeArray(DataTypePtr nested_) : nested(nested_)
{ {
offsets = new DataTypeFromFieldType<ColumnArray::Offset_t>::Type; offsets = new DataTypeFromFieldType<ColumnArray::Offset_t>::Type;
@ -54,7 +55,52 @@ void DataTypeArray::deserializeBinary(IColumn & column, ReadBuffer & istr, size_
ColumnArray & column_array = dynamic_cast<ColumnArray &>(column); ColumnArray & column_array = dynamic_cast<ColumnArray &>(column);
ColumnArray::Offsets_t & offsets = column_array.getOffsets(); ColumnArray::Offsets_t & offsets = column_array.getOffsets();
nested->deserializeBinary(column_array.getData(), istr, limit == 0 ? 0 : offsets[limit - 1]); /// Должно быть считано согласнованное с offsets количество значений.
size_t nested_limit = offsets.empty() ? 0 : offsets.back();
nested->deserializeBinary(column_array.getData(), istr, nested_limit);
if (column_array.getData().size() != nested_limit)
throw Exception("Cannot read all array values", ErrorCodes::CANNOT_READ_ALL_DATA);
}
void DataTypeArray::serializeOffsets(const IColumn & column, WriteBuffer & ostr, WriteCallback callback) const
{
const ColumnArray & column_array = dynamic_cast<const ColumnArray &>(column);
const ColumnArray::Offsets_t & offsets = column_array.getOffsets();
size_t size = offsets.size();
size_t next_callback_point = callback ? callback() : 0;
writeIntBinary(offsets[0], ostr);
for (size_t i = 1; i < size; ++i)
{
if (next_callback_point && i == next_callback_point)
next_callback_point = callback();
writeIntBinary(offsets[i] - offsets[i - 1], ostr);
}
}
void DataTypeArray::deserializeOffsets(IColumn & column, ReadBuffer & istr, size_t limit) const
{
ColumnArray & column_array = dynamic_cast<ColumnArray &>(column);
ColumnArray::Offsets_t & offsets = column_array.getOffsets();
offsets.resize(limit);
size_t i = 0;
ColumnArray::Offset_t current_offset = 0;
while (i < limit && !istr.eof())
{
ColumnArray::Offset_t current_size = 0;
readIntBinary(current_size, istr);
current_offset += current_size;
offsets[i] = current_offset;
++i;
}
offsets.resize(i);
} }

View File

@ -116,6 +116,7 @@ namespace FunctionsLibrary
("blockSize", new FunctionBlockSize) ("blockSize", new FunctionBlockSize)
("materialize", new FunctionMaterialize) ("materialize", new FunctionMaterialize)
("ignore", new FunctionIgnore) ("ignore", new FunctionIgnore)
("arrayJoin", new FunctionArrayJoin)
("tuple", new FunctionTuple) ("tuple", new FunctionTuple)
("tupleElement", new FunctionTupleElement) ("tupleElement", new FunctionTupleElement)

View File

@ -472,7 +472,7 @@ bool Expression::hasAggregates()
} }
void Expression::markBeforeAndAfterAggregationImpl(ASTPtr ast, unsigned before_part_id, unsigned after_part_id, bool below) void Expression::markBeforeAggregationImpl(ASTPtr ast, unsigned before_part_id, bool below)
{ {
if (ASTFunction * func = dynamic_cast<ASTFunction *>(&*ast)) if (ASTFunction * func = dynamic_cast<ASTFunction *>(&*ast))
if (func->aggregate_function) if (func->aggregate_function)
@ -480,18 +480,62 @@ void Expression::markBeforeAndAfterAggregationImpl(ASTPtr ast, unsigned before_p
if (below) if (below)
ast->part_id |= before_part_id; ast->part_id |= before_part_id;
else
ast->part_id |= after_part_id;
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
if (!dynamic_cast<ASTSelectQuery *>(&**it)) if (!dynamic_cast<ASTSelectQuery *>(&**it))
markBeforeAndAfterAggregationImpl(*it, before_part_id, after_part_id, below); markBeforeAggregationImpl(*it, before_part_id, below);
} }
void Expression::markBeforeAndAfterAggregation(unsigned before_part_id, unsigned after_part_id) void Expression::markBeforeAggregation(unsigned before_part_id)
{ {
markBeforeAndAfterAggregationImpl(ast, before_part_id, after_part_id); markBeforeAggregationImpl(ast, before_part_id);
}
bool Expression::getArrayJoinInfoImpl(ASTPtr ast, String & column_name)
{
if (ASTFunction * func = dynamic_cast<ASTFunction *>(&*ast))
{
if (func->name == "arrayJoin")
{
column_name = func->arguments->children.at(0)->getColumnName();
return true;
}
}
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
if (!dynamic_cast<ASTSelectQuery *>(&**it) && getArrayJoinInfoImpl(*it, column_name))
return true;
return false;
}
void Expression::markBeforeArrayJoinImpl(ASTPtr ast, unsigned part_id, bool below)
{
if (below)
ast->part_id |= part_id;
if (ASTFunction * func = dynamic_cast<ASTFunction *>(&*ast))
if (func->name == "arrayJoin")
below = true;
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
if (!dynamic_cast<ASTSelectQuery *>(&**it))
markBeforeArrayJoinImpl(*it, part_id, below);
}
bool Expression::getArrayJoinInfo(String & column_name)
{
return getArrayJoinInfoImpl(ast, column_name);
}
void Expression::markBeforeArrayJoin(unsigned part_id)
{
markBeforeArrayJoinImpl(ast, part_id);
} }

View File

@ -10,6 +10,7 @@
#include <DB/DataStreams/AsynchronousBlockInputStream.h> #include <DB/DataStreams/AsynchronousBlockInputStream.h>
#include <DB/DataStreams/UnionBlockInputStream.h> #include <DB/DataStreams/UnionBlockInputStream.h>
#include <DB/DataStreams/ParallelAggregatingBlockInputStream.h> #include <DB/DataStreams/ParallelAggregatingBlockInputStream.h>
#include <DB/DataStreams/ArrayJoiningBlockInputStream.h>
#include <DB/DataStreams/NullBlockInputStream.h> #include <DB/DataStreams/NullBlockInputStream.h>
#include <DB/DataStreams/narrowBlockInputStreams.h> #include <DB/DataStreams/narrowBlockInputStreams.h>
#include <DB/DataStreams/copyData.h> #include <DB/DataStreams/copyData.h>
@ -152,6 +153,7 @@ BlockInputStreamPtr InterpreterSelectQuery::execute()
if (from_stage < QueryProcessingStage::WithMergeableState) if (from_stage < QueryProcessingStage::WithMergeableState)
{ {
executeArrayJoin(streams, expression);
executeWhere(streams, expression); executeWhere(streams, expression);
if (need_aggregate) if (need_aggregate)
@ -278,9 +280,28 @@ void InterpreterSelectQuery::executeWhere(BlockInputStreams & streams, Expressio
} }
void InterpreterSelectQuery::executeArrayJoin(BlockInputStreams & streams, ExpressionPtr & expression)
{
/// Если есть ARRAY JOIN - сначала выполним часть выражения, необходимую для его вычисления
String array_join_column_name;
if (expression->getArrayJoinInfo(array_join_column_name))
{
expression->markBeforeArrayJoin(PART_BEFORE_ARRAY_JOIN);
bool is_async = settings.asynchronous && streams.size() <= settings.max_threads;
for (BlockInputStreams::iterator it = streams.begin(); it != streams.end(); ++it)
{
BlockInputStreamPtr & stream = *it;
stream = maybeAsynchronous(new ExpressionBlockInputStream(stream, expression, PART_BEFORE_ARRAY_JOIN), is_async);
stream = maybeAsynchronous(new ArrayJoiningBlockInputStream(stream, array_join_column_name), is_async);
}
}
}
void InterpreterSelectQuery::executeAggregation(BlockInputStreams & streams, ExpressionPtr & expression) void InterpreterSelectQuery::executeAggregation(BlockInputStreams & streams, ExpressionPtr & expression)
{ {
expression->markBeforeAndAfterAggregation(PART_BEFORE_AGGREGATING, PART_AFTER_AGGREGATING); expression->markBeforeAggregation(PART_BEFORE_AGGREGATING);
if (query.group_expression_list) if (query.group_expression_list)
setPartID(query.group_expression_list, PART_GROUP); setPartID(query.group_expression_list, PART_GROUP);