2013-05-24 10:49:19 +00:00
# pragma once
2013-06-04 13:34:46 +00:00
# include <DB/DataTypes/IDataType.h>
2013-05-28 12:19:25 +00:00
# include <DB/Interpreters/Settings.h>
2013-06-04 13:34:46 +00:00
# include <DB/Core/Names.h>
# include <DB/Core/ColumnWithNameAndType.h>
# include <DB/Core/Block.h>
# include <set>
2013-05-24 10:49:19 +00:00
namespace DB
{
2013-05-28 14:24:20 +00:00
2013-06-04 13:34:46 +00:00
class IFunction ;
typedef Poco : : SharedPtr < IFunction > FunctionPtr ;
2013-05-24 10:49:19 +00:00
typedef std : : pair < std : : string , std : : string > NameWithAlias ;
typedef std : : vector < NameWithAlias > NamesWithAliases ;
2013-06-11 16:21:25 +00:00
typedef std : : set < String > NameSet ;
2013-07-30 17:25:46 +00:00
typedef std : : map < String , String > NameToNameMap ;
2013-06-11 16:21:25 +00:00
2013-05-24 10:49:19 +00:00
/** Содержит последовательность действий над блоком.
*/
2013-05-29 11:46:51 +00:00
class ExpressionActions
2013-05-24 10:49:19 +00:00
{
public :
struct Action
{
2013-05-30 16:52:21 +00:00
private :
Action ( ) { }
public :
2013-05-24 10:49:19 +00:00
enum Type
{
APPLY_FUNCTION ,
ADD_COLUMN ,
REMOVE_COLUMN ,
COPY_COLUMN ,
2013-10-17 13:32:32 +00:00
ARRAY_JOIN , /// Заменяет указанные столбцы с массивами на столбцы с элементами. Размножает значения в остальных столбцах по количеству элементов в массивах. Массивы должны быть параллельными (иметь одинаковые длины).
2013-06-20 14:24:43 +00:00
PROJECT , /// Переупорядочить и переименовать столбцы, удалить лишние. Допускаются одинаковые имена столбцов в результате.
2013-05-24 10:49:19 +00:00
} ;
Type type ;
std : : string source_name ;
std : : string result_name ;
DataTypePtr result_type ;
2013-10-17 13:32:32 +00:00
/// Для ARRAY_JOIN
NameSet array_joined_columns ;
2013-07-26 13:46:52 +00:00
2013-06-08 20:17:51 +00:00
/// Для ADD_COLUMN.
2013-05-24 10:49:19 +00:00
ColumnPtr added_column ;
/// Для APPLY_FUNCTION.
2013-06-05 10:34:59 +00:00
mutable FunctionPtr function ; /// mutable - чтобы можно было делать execute.
2013-05-24 10:49:19 +00:00
Names argument_names ;
2013-06-04 13:34:46 +00:00
Names prerequisite_names ;
2013-05-24 10:49:19 +00:00
2013-05-28 11:54:37 +00:00
/// Для PROJECT.
NamesWithAliases projection ;
2013-06-04 14:59:05 +00:00
/// Если result_name_ == "", в качестве имени используется "имя_фу нкци(аргументы через запятую)".
static Action applyFunction ( FunctionPtr function_ , const std : : vector < std : : string > & argument_names_ , std : : string result_name_ = " " ) ;
2013-05-30 16:52:21 +00:00
static Action addColumn ( ColumnWithNameAndType added_column_ )
{
Action a ;
a . type = ADD_COLUMN ;
a . result_name = added_column_ . name ;
a . result_type = added_column_ . type ;
a . added_column = added_column_ . column ;
return a ;
}
static Action removeColumn ( const std : : string & removed_name )
{
Action a ;
a . type = REMOVE_COLUMN ;
a . source_name = removed_name ;
return a ;
}
static Action copyColumn ( const std : : string & from_name , const std : : string & to_name )
2013-05-28 11:54:37 +00:00
{
2013-05-30 16:52:21 +00:00
Action a ;
a . type = COPY_COLUMN ;
a . source_name = from_name ;
a . result_name = to_name ;
return a ;
}
static Action project ( const NamesWithAliases & projected_columns_ )
{
Action a ;
a . type = PROJECT ;
a . projection = projected_columns_ ;
return a ;
}
static Action project ( const Names & projected_columns_ )
{
Action a ;
a . type = PROJECT ;
a . projection . resize ( projected_columns_ . size ( ) ) ;
2013-05-28 11:54:37 +00:00
for ( size_t i = 0 ; i < projected_columns_ . size ( ) ; + + i )
2013-05-30 16:52:21 +00:00
a . projection [ i ] = NameWithAlias ( projected_columns_ [ i ] , " " ) ;
return a ;
}
2013-10-17 13:32:32 +00:00
static Action arrayJoin ( const NameSet & array_joined_columns )
2013-05-30 16:52:21 +00:00
{
2013-10-17 13:32:32 +00:00
if ( array_joined_columns . empty ( ) )
throw Exception ( " No arrays to join " , ErrorCodes : : LOGICAL_ERROR ) ;
2013-05-30 16:52:21 +00:00
Action a ;
a . type = ARRAY_JOIN ;
2013-08-01 13:29:32 +00:00
a . array_joined_columns = array_joined_columns ;
2013-07-26 13:46:52 +00:00
return a ;
}
2013-06-11 16:21:25 +00:00
/// Какие столбцы нужны, чтобы выполнить это действие.
/// Если этот Action еще не добавлен в ExpressionActions, возвращаемый список может быть неполным, потому что не учтены prerequisites.
Names getNeededColumns ( ) const ;
std : : string toString ( ) const ;
private :
friend class ExpressionActions ;
2013-06-04 13:34:46 +00:00
std : : vector < Action > getPrerequisites ( Block & sample_block ) ;
2013-05-24 10:49:19 +00:00
void prepare ( Block & sample_block ) ;
2013-06-05 10:34:59 +00:00
void execute ( Block & block ) const ;
2013-05-24 10:49:19 +00:00
} ;
typedef std : : vector < Action > Actions ;
2013-05-28 12:19:25 +00:00
ExpressionActions ( const NamesAndTypesList & input_columns_ , const Settings & settings_ )
: input_columns ( input_columns_ ) , settings ( settings_ )
2013-05-24 10:49:19 +00:00
{
for ( NamesAndTypesList : : iterator it = input_columns . begin ( ) ; it ! = input_columns . end ( ) ; + + it )
{
2013-06-03 12:26:06 +00:00
sample_block . insert ( ColumnWithNameAndType ( NULL , it - > second , it - > first ) ) ;
2013-05-24 10:49:19 +00:00
}
}
2013-06-04 13:34:46 +00:00
/// Для константных столбцов в input_columns_ могут содержаться сами столбцы.
ExpressionActions ( const ColumnsWithNameAndType & input_columns_ , const Settings & settings_ )
: settings ( settings_ )
{
for ( ColumnsWithNameAndType : : const_iterator it = input_columns_ . begin ( ) ; it ! = input_columns_ . end ( ) ; + + it )
{
input_columns . push_back ( NameAndTypePair ( it - > name , it - > type ) ) ;
sample_block . insert ( * it ) ;
}
}
2013-06-11 16:21:25 +00:00
/// Добавить входной столбец.
/// Название столбца не должно совпадать с названиями промежуточных столбцов, возникающих при вычислении выражения.
/// В выражении не должно быть действий PROJECT.
void addInput ( const ColumnWithNameAndType & column ) ;
void addInput ( const NameAndTypePair & column ) ;
2013-05-28 12:19:25 +00:00
void add ( const Action & action ) ;
2013-05-24 10:49:19 +00:00
2013-06-11 16:21:25 +00:00
/// Кладет в out_new_columns названия новых столбцов
/// (образовавшихся в результате добавляемого действия и е г о rerequisites).
void add ( const Action & action , Names & out_new_columns ) ;
2013-05-28 14:47:37 +00:00
/// Добавляет в начало удаление всех лишних столбцов.
void prependProjectInput ( ) ;
2013-05-28 11:54:37 +00:00
/// - Добавляет действия для удаления всех столбцов, кроме указанных.
/// - Убирает неиспользуемые входные столбцы.
2013-06-11 16:21:25 +00:00
/// - Может как-нибудь оптимизировать выражение.
2013-05-28 11:54:37 +00:00
/// - Н е переупорядочивает столбцы.
/// - Н е удаляет "неожиданные" столбцы (например, добавленные функциями).
2013-06-03 10:18:41 +00:00
/// - Если output_columns пуст, оставляет один произвольный столбец (чтобы не потерялось количество строк в блоке).
2013-05-28 11:54:37 +00:00
void finalize ( const Names & output_columns ) ;
2013-05-24 10:49:19 +00:00
/// Получить список входных столбцов.
2013-05-28 11:54:37 +00:00
Names getRequiredColumns ( ) const
{
Names names ;
for ( NamesAndTypesList : : const_iterator it = input_columns . begin ( ) ; it ! = input_columns . end ( ) ; + + it )
names . push_back ( it - > first ) ;
return names ;
}
const NamesAndTypesList & getRequiredColumnsWithTypes ( ) const { return input_columns ; }
2013-05-24 10:49:19 +00:00
/// Выполнить выражение над блоком. Блок должен содержать все столбцы , возвращаемые getRequiredColumns.
2013-06-05 10:34:59 +00:00
void execute ( Block & block ) const ;
2013-05-24 10:49:19 +00:00
/// Получить блок-образец, содержащий имена и типы столбцов результата.
2013-06-05 10:34:59 +00:00
const Block & getSampleBlock ( ) const { return sample_block ; }
2013-05-24 10:49:19 +00:00
2013-05-30 16:52:21 +00:00
std : : string getID ( ) const ;
2013-05-24 10:49:19 +00:00
std : : string dumpActions ( ) const ;
2013-06-20 13:50:55 +00:00
static std : : string getSmallestColumn ( const NamesAndTypesList & columns ) ;
2013-05-24 10:49:19 +00:00
private :
NamesAndTypesList input_columns ;
Actions actions ;
Block sample_block ;
2013-05-28 12:19:25 +00:00
Settings settings ;
2013-06-05 10:34:59 +00:00
void checkLimits ( Block & block ) const ;
2013-06-04 13:34:46 +00:00
/// Добавляет сначала все prerequisites, потом само действие.
/// current_names - столбцы, prerequisites которых сейчас обрабатываются.
2013-06-11 16:21:25 +00:00
void addImpl ( Action action , NameSet & current_names , Names & new_names ) ;
2013-06-10 16:03:23 +00:00
/// Попробовать что-нибудь улучшить, не меняя списки входных и выходных столбцов.
void optimize ( ) ;
/// Переместить все arrayJoin как можно ближе к концу.
void optimizeArrayJoin ( ) ;
2013-05-24 10:49:19 +00:00
} ;
typedef SharedPtr < ExpressionActions > ExpressionActionsPtr ;
2013-06-20 12:27:33 +00:00
/** Последовательность преобразований над блоком.
* П р е д п о л а г а е т с я , ч т о р е з у л ь т а т к а ж д о г о ш а г а п о д а е т с я н а в х о д с л е д у ю щ е г о ш а г а .
* И с п о л ь з у е т с я д л я в ы п о л н е н и я н е к о т о р ы х ч а с т е й з а п р о с а п о о т д е л ь н о с т и .
*
* Н а п р и м е р , м о ж н о с о с т а в и т ь ц е п о ч к у и з д в у х ш а г о в :
* 1 ) в ы ч и с л и т ь в ы р а ж е н и е в с е к ц и и WHERE ,
* 2 ) в ы ч и с л и т ь в ы р а ж е н и е в с е к ц и и SELECT ,
* и м е ж д у д в у м я ш а г а м и д е л а т ь ф и л ь т р а ц и ю п о з н а ч е н и ю в с е к ц и и WHERE .
*/
2013-05-28 14:24:20 +00:00
struct ExpressionActionsChain
{
struct Step
{
ExpressionActionsPtr actions ;
Names required_output ;
Step ( ExpressionActionsPtr actions_ = NULL , Names required_output_ = Names ( ) )
: actions ( actions_ ) , required_output ( required_output_ ) { }
} ;
typedef std : : vector < Step > Steps ;
Settings settings ;
Steps steps ;
void addStep ( )
{
if ( steps . empty ( ) )
throw Exception ( " Cannot add action to empty ExpressionActionsChain " , ErrorCodes : : LOGICAL_ERROR ) ;
2013-06-04 13:34:46 +00:00
ColumnsWithNameAndType columns = steps . back ( ) . actions - > getSampleBlock ( ) . getColumns ( ) ;
2013-05-28 14:24:20 +00:00
steps . push_back ( Step ( new ExpressionActions ( columns , settings ) ) ) ;
}
void finalize ( )
{
for ( int i = static_cast < int > ( steps . size ( ) ) - 1 ; i > = 0 ; - - i )
{
steps [ i ] . actions - > finalize ( steps [ i ] . required_output ) ;
if ( i > 0 )
{
2013-07-23 14:19:03 +00:00
Names & previous_output = steps [ i - 1 ] . required_output ;
2013-05-28 14:24:20 +00:00
const NamesAndTypesList & columns = steps [ i ] . actions - > getRequiredColumnsWithTypes ( ) ;
for ( NamesAndTypesList : : const_iterator it = columns . begin ( ) ; it ! = columns . end ( ) ; + + it )
2013-05-28 14:47:37 +00:00
previous_output . push_back ( it - > first ) ;
std : : sort ( previous_output . begin ( ) , previous_output . end ( ) ) ;
2013-05-28 15:04:35 +00:00
previous_output . erase ( std : : unique ( previous_output . begin ( ) , previous_output . end ( ) ) , previous_output . end ( ) ) ;
2013-05-28 14:47:37 +00:00
/// Если на выходе предыдущего шага образуются ненужные столбцы, добавим в начало этого шага их выбрасывание.
2013-06-03 10:43:25 +00:00
/// З а исключением случая, когда мы выбросим все столбцы и потеряем количество строк в блоке.
if ( ! steps [ i ] . actions - > getRequiredColumnsWithTypes ( ) . empty ( )
& & previous_output . size ( ) > steps [ i ] . actions - > getRequiredColumnsWithTypes ( ) . size ( ) )
2013-05-28 14:47:37 +00:00
steps [ i ] . actions - > prependProjectInput ( ) ;
2013-05-28 14:24:20 +00:00
}
}
}
2013-06-03 10:18:41 +00:00
void clear ( )
{
steps . clear ( ) ;
}
2013-06-05 12:46:41 +00:00
ExpressionActionsPtr getLastActions ( )
2013-06-03 10:18:41 +00:00
{
if ( steps . empty ( ) )
throw Exception ( " Empty ExpressionActionsChain " , ErrorCodes : : LOGICAL_ERROR ) ;
return steps . back ( ) . actions ;
}
2013-06-05 12:46:41 +00:00
Step & getLastStep ( )
2013-06-03 10:18:41 +00:00
{
if ( steps . empty ( ) )
throw Exception ( " Empty ExpressionActionsChain " , ErrorCodes : : LOGICAL_ERROR ) ;
return steps . back ( ) ;
}
2013-05-28 14:24:20 +00:00
} ;
2013-05-24 10:49:19 +00:00
}