2015-08-05 21:38:31 +00:00
# include <DB/Parsers/ASTSetQuery.h>
2015-06-02 11:16:02 +00:00
# include <DB/Parsers/ASTSelectQuery.h>
2015-08-05 21:38:31 +00:00
2015-06-02 11:16:02 +00:00
namespace DB
{
ASTSelectQuery : : ASTSelectQuery ( const StringRange range_ ) : ASTQueryWithOutput ( range_ )
{
}
bool ASTSelectQuery : : hasArrayJoin ( const ASTPtr & ast )
{
if ( const ASTFunction * function = typeid_cast < const ASTFunction * > ( & * ast ) )
if ( function - > kind = = ASTFunction : : ARRAY_JOIN )
return true ;
for ( const auto & child : ast - > children )
if ( hasArrayJoin ( child ) )
return true ;
return false ;
}
bool ASTSelectQuery : : hasAsterisk ( ) const
{
for ( const auto & ast : select_expression_list - > children )
if ( typeid_cast < const ASTAsterisk * > ( & * ast ) ! = nullptr )
return true ;
return false ;
}
void ASTSelectQuery : : renameColumns ( const ASTSelectQuery & source )
{
const ASTs & from = source . select_expression_list - > children ;
ASTs & to = select_expression_list - > children ;
if ( from . size ( ) ! = to . size ( ) )
throw Exception ( " Size mismatch in UNION ALL chain " ,
DB : : ErrorCodes : : UNION_ALL_RESULT_STRUCTURES_MISMATCH ) ;
for ( size_t i = 0 ; i < from . size ( ) ; + + i )
{
/// Если столбец имеет алиас, то он должен совпадать с названием исходного столбца.
/// В противном случае мы ему присваиваем алиас, если требуется.
if ( ! to [ i ] - > tryGetAlias ( ) . empty ( ) )
{
if ( to [ i ] - > tryGetAlias ( ) ! = from [ i ] - > getAliasOrColumnName ( ) )
throw Exception ( " Column alias mismatch in UNION ALL chain " ,
DB : : ErrorCodes : : UNION_ALL_COLUMN_ALIAS_MISMATCH ) ;
}
else if ( to [ i ] - > getColumnName ( ) ! = from [ i ] - > getAliasOrColumnName ( ) )
to [ i ] - > setAlias ( from [ i ] - > getAliasOrColumnName ( ) ) ;
}
}
void ASTSelectQuery : : rewriteSelectExpressionList ( const Names & column_names )
{
ASTPtr result = new ASTExpressionList ;
ASTs asts = select_expression_list - > children ;
/// Создать отображение.
/// Элемент отображения.
struct Arrow
{
Arrow ( ) = default ;
Arrow ( size_t to_position_ ) :
to_position ( to_position_ ) , is_selected ( true )
{
}
size_t to_position = 0 ;
bool is_selected = false ;
} ;
/// Отображение одного SELECT выражения в другое.
using Mapping = std : : vector < Arrow > ;
Mapping mapping ( asts . size ( ) ) ;
std : : vector < size_t > from ( column_names . size ( ) ) ;
/// Н е будем выбрасывать выражения, содержащие функцию arrayJoin.
for ( size_t i = 0 ; i < asts . size ( ) ; + + i )
{
if ( hasArrayJoin ( asts [ i ] ) )
mapping [ i ] = Arrow ( i ) ;
}
for ( size_t i = 0 ; i < column_names . size ( ) ; + + i )
{
bool done = false ;
for ( size_t j = 0 ; j < asts . size ( ) ; + + j )
{
if ( asts [ j ] - > getAliasOrColumnName ( ) = = column_names [ i ] )
{
from [ i ] = j ;
done = true ;
break ;
}
}
if ( ! done )
throw Exception ( " Error while rewriting expression list for select query. "
" Could not find alias: " + column_names [ i ] ,
DB : : ErrorCodes : : UNKNOWN_IDENTIFIER ) ;
}
auto to = from ;
std : : sort ( from . begin ( ) , from . end ( ) ) ;
for ( size_t i = 0 ; i < column_names . size ( ) ; + + i )
2015-06-02 14:18:14 +00:00
mapping [ from [ i ] ] = Arrow ( to [ i ] ) ;
2015-06-02 11:16:02 +00:00
/// Составить новое выражение.
for ( const auto & arrow : mapping )
{
if ( arrow . is_selected )
result - > children . push_back ( asts [ arrow . to_position ] - > clone ( ) ) ;
}
for ( auto & child : children )
{
if ( child = = select_expression_list )
{
child = result ;
break ;
}
}
select_expression_list = result ;
/** NOTE: Может показаться, что мы могли испортить запрос, выбросив выражение с алиасом, который используется где-то еще.
* Т а к о г о п р о и з о й т и н е м о ж е т , п о т о м у ч т о э т о т м е т о д в ы з ы в а е т с я в с е г д а д л я з а п р о с а , н а к о т о р о м х о т ь р а з с о з д а в а л и
* ExpressionAnalyzer , ч т о г а р а н т и р у е т , ч т о в н е м в с е а л и а с ы у ж е п о д с т а в л е н ы . Н е с о в с е м о ч е в и д н а я л о г и к а : )
*/
}
ASTPtr ASTSelectQuery : : clone ( ) const
2015-07-11 00:44:45 +00:00
{
2015-07-11 15:16:59 +00:00
ASTPtr ptr = cloneImpl ( true ) ;
2015-07-11 00:44:45 +00:00
/// Установить указатели на предыдущие запросы SELECT.
ASTPtr current = ptr ;
2015-07-13 15:02:29 +00:00
static_cast < ASTSelectQuery * > ( & * current ) - > prev_union_all = nullptr ;
2015-07-11 00:44:45 +00:00
ASTPtr next = static_cast < ASTSelectQuery * > ( & * current ) - > next_union_all ;
while ( ! next . isNull ( ) )
{
ASTSelectQuery * next_select_query = static_cast < ASTSelectQuery * > ( & * next ) ;
next_select_query - > prev_union_all = current ;
current = next ;
next = next_select_query - > next_union_all ;
}
return ptr ;
}
2015-07-11 15:16:59 +00:00
ASTPtr ASTSelectQuery : : cloneFirstSelect ( ) const
{
ASTPtr res = cloneImpl ( false ) ;
static_cast < ASTSelectQuery * > ( & * res ) - > prev_union_all = nullptr ;
return res ;
}
ASTPtr ASTSelectQuery : : cloneImpl ( bool traverse_union_all ) const
2015-06-02 11:16:02 +00:00
{
ASTSelectQuery * res = new ASTSelectQuery ( * this ) ;
ASTPtr ptr { res } ;
res - > children . clear ( ) ;
# define CLONE(member) if (member) { res->member = member->clone(); res->children.push_back(res->member); }
/** NOTE Члены должны клонироваться точно в таком же порядке,
* в к а к о м о н и б ы л и в с т а в л е н ы в children в ParserSelectQuery .
* Э т о в а ж н о , п о т о м у ч т о и з и м ё н children - о в с о с т а в л я е т с я и д е н т и ф и к а т о р ( getTreeID ) ,
* к о т о р ы й м о ж е т б ы т ь и с п о л ь з о в а н д л я и д е н т и ф и к а т о р о в с т о л б ц о в в с л у ч а е п о д з а п р о с о в в о п е р а т о р е IN .
* П р и р а с п р е д е л ё н н о й о б р а б о т к е з а п р о с а , в с л у ч а е , е с л и о д и н и з с е р в е р о в localhost , а д р у г о й - н е т ,
* з а п р о с н а localhost в ы п о л н я е т с я в р а м к а х п р о ц е с с а и п р и э т о м к л о н и р у е т с я ,
* а н а у д а л ё н н ы й с е р в е р з а п р о с о т п р а в л я е т с я в т е к с т о в о м в и д е п о TCP .
* И е с л и п о р я д о к п р и к л о н и р о в а н и и н е с о в п а д а е т с п о р я д к о м п р и п а р с и н г е ,
* т о н а р а з н ы х с е р в е р а х п о л у ч а т с я р а з н ы е и д е н т и ф и к а т о р ы .
*/
CLONE ( select_expression_list )
CLONE ( database )
CLONE ( table )
CLONE ( array_join_expression_list )
CLONE ( join )
CLONE ( sample_size )
CLONE ( prewhere_expression )
CLONE ( where_expression )
CLONE ( group_expression_list )
CLONE ( having_expression )
CLONE ( order_expression_list )
CLONE ( limit_offset )
CLONE ( limit_length )
2015-06-05 21:28:04 +00:00
CLONE ( settings )
2015-06-02 11:16:02 +00:00
CLONE ( format )
# undef CLONE
2015-07-11 15:16:59 +00:00
if ( traverse_union_all )
2015-07-11 13:43:48 +00:00
{
2015-07-11 15:16:59 +00:00
if ( next_union_all )
{
res - > next_union_all = static_cast < const ASTSelectQuery * > ( & * next_union_all ) - > cloneImpl ( true ) ;
res - > children . push_back ( res - > next_union_all ) ;
}
2015-07-11 13:43:48 +00:00
}
2015-07-11 15:16:59 +00:00
else
res - > next_union_all = nullptr ;
2015-07-11 13:43:48 +00:00
2015-06-02 11:16:02 +00:00
return ptr ;
}
2015-06-25 17:38:54 +00:00
const IAST * ASTSelectQuery : : getFormat ( ) const
{
const ASTSelectQuery * query = this ;
while ( ! query - > next_union_all . isNull ( ) )
query = static_cast < const ASTSelectQuery * > ( query - > next_union_all . get ( ) ) ;
return query - > format . get ( ) ;
}
2015-08-05 21:38:31 +00:00
void ASTSelectQuery : : formatImpl ( const FormatSettings & settings , FormatState & state , FormatStateStacked frame ) const override
{
frame . need_parens = false ;
std : : string indent_str = settings . one_line ? " " : std : : string ( 4 * frame . indent , ' ' ) ;
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < indent_str < < " SELECT " < < ( distinct ? " DISTINCT " : " " ) < < ( settings . hilite ? hilite_none : " " ) ;
settings . one_line
? select_expression_list - > formatImpl ( settings , state , frame )
: typeid_cast < const ASTExpressionList & > ( * select_expression_list ) . formatImplMultiline ( settings , state , frame ) ;
if ( table )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " FROM " < < ( settings . hilite ? hilite_none : " " ) ;
if ( database )
{
database - > formatImpl ( settings , state , frame ) ;
settings . ostr < < " . " ;
}
if ( typeid_cast < const ASTSelectQuery * > ( & * table ) )
{
if ( settings . one_line )
settings . ostr < < " ( " ;
else
settings . ostr < < " \n " < < indent_str < < " ( \n " ;
table - > formatImpl ( settings , state , frame ) ;
if ( settings . one_line )
settings . ostr < < " ) " ;
else
settings . ostr < < " \n " < < indent_str < < " ) " ;
}
else
table - > formatImpl ( settings , state , frame ) ;
}
if ( final )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " FINAL " < < ( settings . hilite ? hilite_none : " " ) ;
}
if ( sample_size )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " SAMPLE " < < ( settings . hilite ? hilite_none : " " ) ;
sample_size - > formatImpl ( settings , state , frame ) ;
}
if ( array_join_expression_list )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str
< < ( array_join_is_left ? " LEFT " : " " ) < < " ARRAY JOIN " < < ( settings . hilite ? hilite_none : " " ) ;
settings . one_line
? array_join_expression_list - > formatImpl ( settings , state , frame )
: typeid_cast < const ASTExpressionList & > ( * array_join_expression_list ) . formatImplMultiline ( settings , state , frame ) ;
}
if ( join )
{
settings . ostr < < " " ;
join - > formatImpl ( settings , state , frame ) ;
}
if ( prewhere_expression )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " PREWHERE " < < ( settings . hilite ? hilite_none : " " ) ;
prewhere_expression - > formatImpl ( settings , state , frame ) ;
}
if ( where_expression )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " WHERE " < < ( settings . hilite ? hilite_none : " " ) ;
where_expression , s , indent , hilite , settings . one_line ) ;
}
if ( group_expression_list )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " GROUP BY " < < ( settings . hilite ? hilite_none : " " ) ;
settings . one_line
? group_expression_list - > formatImpl ( settings , state , frame )
: typeid_cast < const ASTExpressionList & > ( * group_expression_list ) . formatImplMultiline ( settings , state , frame ) ;
}
if ( group_by_with_totals )
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < ( settings . one_line ? " " : " " ) < < " WITH TOTALS " < < ( settings . hilite ? hilite_none : " " ) ;
if ( having_expression )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " HAVING " < < ( settings . hilite ? hilite_none : " " ) ;
having_expression - > formatImpl ( settings , state , frame ) ;
}
if ( order_expression_list )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " ORDER BY " < < ( settings . hilite ? hilite_none : " " ) ;
settings . one_line
? order_expression_list - > formatImpl ( settings , state , frame )
: typeid_cast < const ASTExpressionList & > ( * order_expression_list ) . formatImplMultiline ( settings , state , frame ) ;
}
if ( limit_length )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " LIMIT " < < ( settings . hilite ? hilite_none : " " ) ;
if ( limit_offset )
{
limit_offset - > formatImpl ( settings , state , frame ) ;
settings . ostr < < " , " ;
}
limit_length - > formatImpl ( settings , state , frame ) ;
}
if ( settings )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " SETTINGS " < < ( settings . hilite ? hilite_none : " " ) ;
const ASTSetQuery & ast_set = typeid_cast < const ASTSetQuery & > ( * settings ) ;
for ( ASTSetQuery : : Changes : : const_iterator it = ast_set . changes . begin ( ) ; it ! = ast_set . changes . end ( ) ; + + it )
{
if ( it ! = ast_set . changes . begin ( ) )
settings . ostr < < " , " ;
settings . ostr < < it - > name < < " = " < < apply_visitor ( FieldVisitorToString ( ) , it - > value ) ;
}
}
if ( format )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " FORMAT " < < ( settings . hilite ? hilite_none : " " ) ;
format - > formatImpl ( settings , state , frame ) ;
}
if ( next_union_all )
{
settings . ostr < < ( settings . hilite ? hilite_keyword : " " ) < < settings . nl_or_ws < < settings . ostr < < indent_str < < " UNION ALL " < < settings . nl_or_ws < < settings . ostr < < ( settings . hilite ? hilite_none : " " ) ;
// NOTE Мы можем безопасно применить static_cast вместо typeid_cast, потому что знаем, что в цепочке UNION ALL
// имеются только деревья типа SELECT.
const ASTSelectQuery & next_ast = static_cast < const ASTSelectQuery & > ( * next_union_all ) ;
next_ast - > formatImpl ( settings , state , frame ) ;
}
}
2015-06-02 11:16:02 +00:00
} ;