2017-04-01 09:19:00 +00:00
# include <Storages/AlterCommands.h>
# include <Storages/IStorage.h>
2018-06-13 13:49:27 +00:00
# include <DataTypes/DataTypeFactory.h>
2017-04-01 09:19:00 +00:00
# include <DataTypes/DataTypesNumber.h>
2017-12-25 18:58:39 +00:00
# include <DataTypes/NestedUtils.h>
2017-04-01 09:19:00 +00:00
# include <Interpreters/Context.h>
2018-11-08 15:43:14 +00:00
# include <Interpreters/SyntaxAnalyzer.h>
2017-04-01 09:19:00 +00:00
# include <Interpreters/ExpressionAnalyzer.h>
# include <Interpreters/ExpressionActions.h>
# include <Parsers/ASTIdentifier.h>
2019-02-05 14:50:25 +00:00
# include <Parsers/ASTIndexDeclaration.h>
2017-04-01 09:19:00 +00:00
# include <Parsers/ASTExpressionList.h>
# include <Parsers/ASTLiteral.h>
# include <Parsers/ASTFunction.h>
2018-06-13 13:49:27 +00:00
# include <Parsers/ASTAlterQuery.h>
# include <Parsers/ASTColumnDeclaration.h>
# include <Common/typeid_cast.h>
2018-12-21 14:40:20 +00:00
# include <Compression/CompressionFactory.h>
2014-10-16 13:37:01 +00:00
2019-04-15 09:30:45 +00:00
# include <Parsers/queryToString.h>
2015-10-20 16:22:08 +00:00
2014-10-16 13:37:01 +00:00
namespace DB
{
2016-01-11 21:46:36 +00:00
namespace ErrorCodes
{
2017-04-01 07:20:54 +00:00
extern const int ILLEGAL_COLUMN ;
2018-11-13 12:51:55 +00:00
extern const int BAD_ARGUMENTS ;
2017-04-01 07:20:54 +00:00
extern const int LOGICAL_ERROR ;
2016-01-11 21:46:36 +00:00
}
2018-06-13 13:49:27 +00:00
std : : optional < AlterCommand > AlterCommand : : parse ( const ASTAlterCommand * command_ast )
{
const DataTypeFactory & data_type_factory = DataTypeFactory : : instance ( ) ;
2018-12-21 14:40:20 +00:00
const CompressionCodecFactory & compression_codec_factory = CompressionCodecFactory : : instance ( ) ;
2018-06-13 13:49:27 +00:00
if ( command_ast - > type = = ASTAlterCommand : : ADD_COLUMN )
{
AlterCommand command ;
command . type = AlterCommand : : ADD_COLUMN ;
2019-03-15 16:14:13 +00:00
const auto & ast_col_decl = command_ast - > col_decl - > as < ASTColumnDeclaration & > ( ) ;
2018-06-13 13:49:27 +00:00
command . column_name = ast_col_decl . name ;
if ( ast_col_decl . type )
{
command . data_type = data_type_factory . get ( ast_col_decl . type ) ;
}
if ( ast_col_decl . default_expression )
{
command . default_kind = columnDefaultKindFromString ( ast_col_decl . default_specifier ) ;
command . default_expression = ast_col_decl . default_expression ;
}
2019-03-15 14:59:03 +00:00
if ( ast_col_decl . comment )
{
const auto & ast_comment = typeid_cast < ASTLiteral & > ( * ast_col_decl . comment ) ;
command . comment = ast_comment . value . get < String > ( ) ;
}
2018-12-21 14:40:20 +00:00
if ( ast_col_decl . codec )
2019-04-02 12:51:31 +00:00
command . codec = compression_codec_factory . get ( ast_col_decl . codec , command . data_type ) ;
2018-12-21 14:40:20 +00:00
2018-06-13 13:49:27 +00:00
if ( command_ast - > column )
2019-01-14 18:15:04 +00:00
command . after_column = * getIdentifierName ( command_ast - > column ) ;
2018-06-13 13:49:27 +00:00
2019-04-15 09:30:45 +00:00
if ( ast_col_decl . ttl )
command . ttl = ast_col_decl . ttl ;
2018-12-21 14:53:00 +00:00
command . if_not_exists = command_ast - > if_not_exists ;
2018-06-13 13:49:27 +00:00
return command ;
}
else if ( command_ast - > type = = ASTAlterCommand : : DROP_COLUMN & & ! command_ast - > partition )
{
if ( command_ast - > clear_column )
throw Exception ( " \" ALTER TABLE table CLEAR COLUMN column \" queries are not supported yet. Use \" CLEAR COLUMN column IN PARTITION \" . " , ErrorCodes : : NOT_IMPLEMENTED ) ;
AlterCommand command ;
command . type = AlterCommand : : DROP_COLUMN ;
2019-01-14 18:15:04 +00:00
command . column_name = * getIdentifierName ( command_ast - > column ) ;
2018-12-21 14:53:00 +00:00
command . if_exists = command_ast - > if_exists ;
2018-06-13 13:49:27 +00:00
return command ;
}
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_COLUMN )
{
AlterCommand command ;
command . type = AlterCommand : : MODIFY_COLUMN ;
2019-03-15 16:14:13 +00:00
const auto & ast_col_decl = command_ast - > col_decl - > as < ASTColumnDeclaration & > ( ) ;
2018-06-13 13:49:27 +00:00
command . column_name = ast_col_decl . name ;
if ( ast_col_decl . type )
{
command . data_type = data_type_factory . get ( ast_col_decl . type ) ;
}
if ( ast_col_decl . default_expression )
{
command . default_kind = columnDefaultKindFromString ( ast_col_decl . default_specifier ) ;
command . default_expression = ast_col_decl . default_expression ;
}
2018-11-14 22:46:39 +00:00
if ( ast_col_decl . comment )
{
2019-03-15 16:14:13 +00:00
const auto & ast_comment = ast_col_decl . comment - > as < ASTLiteral & > ( ) ;
2018-11-14 22:46:39 +00:00
command . comment = ast_comment . value . get < String > ( ) ;
}
2019-03-15 14:59:03 +00:00
2019-04-15 09:30:45 +00:00
if ( ast_col_decl . ttl )
command . ttl = ast_col_decl . ttl ;
2019-03-15 14:59:03 +00:00
if ( ast_col_decl . codec )
2019-04-02 12:51:31 +00:00
command . codec = compression_codec_factory . get ( ast_col_decl . codec , command . data_type ) ;
2019-03-15 14:59:03 +00:00
2018-12-21 14:53:00 +00:00
command . if_exists = command_ast - > if_exists ;
2018-11-14 22:46:39 +00:00
2018-06-13 13:49:27 +00:00
return command ;
}
2018-11-26 13:01:48 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : COMMENT_COLUMN )
{
AlterCommand command ;
command . type = COMMENT_COLUMN ;
2019-01-14 18:15:04 +00:00
command . column_name = * getIdentifierName ( command_ast - > column ) ;
2019-03-15 16:14:13 +00:00
const auto & ast_comment = command_ast - > comment - > as < ASTLiteral & > ( ) ;
2018-11-26 13:01:48 +00:00
command . comment = ast_comment . value . get < String > ( ) ;
2018-12-21 14:53:00 +00:00
command . if_exists = command_ast - > if_exists ;
2018-06-13 13:49:27 +00:00
return command ;
}
2018-10-15 18:47:47 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_ORDER_BY )
{
AlterCommand command ;
command . type = AlterCommand : : MODIFY_ORDER_BY ;
2018-11-06 18:25:36 +00:00
command . order_by = command_ast - > order_by ;
2018-10-15 18:47:47 +00:00
return command ;
}
2019-02-05 14:50:25 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : ADD_INDEX )
{
AlterCommand command ;
command . index_decl = command_ast - > index_decl ;
command . type = AlterCommand : : ADD_INDEX ;
2019-03-15 16:14:13 +00:00
const auto & ast_index_decl = command_ast - > index_decl - > as < ASTIndexDeclaration & > ( ) ;
2019-02-05 14:50:25 +00:00
command . index_name = ast_index_decl . name ;
if ( command_ast - > index )
2019-03-15 16:14:13 +00:00
command . after_index_name = command_ast - > index - > as < ASTIdentifier & > ( ) . name ;
2019-02-05 14:50:25 +00:00
command . if_not_exists = command_ast - > if_not_exists ;
return command ;
}
else if ( command_ast - > type = = ASTAlterCommand : : DROP_INDEX )
{
if ( command_ast - > clear_column )
throw Exception ( " \" ALTER TABLE table CLEAR COLUMN column \" queries are not supported yet. Use \" CLEAR COLUMN column IN PARTITION \" . " , ErrorCodes : : NOT_IMPLEMENTED ) ;
AlterCommand command ;
command . type = AlterCommand : : DROP_INDEX ;
2019-03-15 16:14:13 +00:00
command . index_name = command_ast - > index - > as < ASTIdentifier & > ( ) . name ;
2019-02-05 14:50:25 +00:00
command . if_exists = command_ast - > if_exists ;
return command ;
}
2019-04-15 09:30:45 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_TTL )
{
AlterCommand command ;
command . type = AlterCommand : : MODIFY_TTL ;
command . ttl = command_ast - > ttl ;
return command ;
}
2018-06-13 13:49:27 +00:00
else
return { } ;
}
2019-02-05 14:50:25 +00:00
void AlterCommand : : apply ( ColumnsDescription & columns_description , IndicesDescription & indices_description ,
2019-04-15 09:30:45 +00:00
ASTPtr & order_by_ast , ASTPtr & primary_key_ast , ASTPtr & ttl_table_ast ) const
2016-01-11 21:46:36 +00:00
{
2017-04-01 07:20:54 +00:00
if ( type = = ADD_COLUMN )
{
2019-03-14 15:20:51 +00:00
ColumnDescription column ( column_name , data_type ) ;
if ( default_expression )
2017-04-01 07:20:54 +00:00
{
2019-03-14 15:20:51 +00:00
column . default_desc . kind = default_kind ;
column . default_desc . expression = default_expression ;
}
column . comment = comment ;
column . codec = codec ;
2019-04-15 09:30:45 +00:00
column . ttl = ttl ;
2017-04-01 07:20:54 +00:00
2019-03-14 15:20:51 +00:00
columns_description . add ( column , after_column ) ;
2018-12-21 14:40:20 +00:00
2017-04-01 07:20:54 +00:00
/// Slow, because each time a list is copied
2019-03-14 15:20:51 +00:00
columns_description . flattenNested ( ) ;
2017-04-01 07:20:54 +00:00
}
else if ( type = = DROP_COLUMN )
{
2019-03-14 15:20:51 +00:00
columns_description . remove ( column_name ) ;
2017-04-01 07:20:54 +00:00
}
else if ( type = = MODIFY_COLUMN )
{
2019-05-01 21:43:05 +00:00
columns_description . modify ( column_name , [ & ] ( ColumnDescription & column )
2019-04-02 12:51:31 +00:00
{
2019-05-01 21:43:05 +00:00
if ( codec )
{
/// User doesn't specify data type, it means that datatype doesn't change
/// let's use info about old type
if ( data_type = = nullptr )
codec - > useInfoAboutType ( column . type ) ;
column . codec = codec ;
}
if ( ! is_mutable ( ) )
{
column . comment = comment ;
return ;
}
if ( ttl )
column . ttl = ttl ;
column . type = data_type ;
2018-11-13 12:08:07 +00:00
2019-05-01 21:43:05 +00:00
column . default_desc . kind = default_kind ;
column . default_desc . expression = default_expression ;
} ) ;
2017-04-01 07:20:54 +00:00
}
2018-11-13 12:51:55 +00:00
else if ( type = = MODIFY_ORDER_BY )
{
2019-03-25 08:55:26 +00:00
if ( ! primary_key_ast & & order_by_ast )
2018-11-13 12:51:55 +00:00
{
/// Primary and sorting key become independent after this ALTER so we have to
/// save the old ORDER BY expression as the new primary key.
2018-11-28 12:06:52 +00:00
primary_key_ast = order_by_ast - > clone ( ) ;
2018-11-13 12:51:55 +00:00
}
2018-11-28 12:06:52 +00:00
order_by_ast = order_by ;
2017-04-01 07:20:54 +00:00
}
2018-10-14 15:30:06 +00:00
else if ( type = = COMMENT_COLUMN )
{
2019-05-01 21:43:05 +00:00
columns_description . modify ( column_name , [ & ] ( ColumnDescription & column ) { column . comment = comment ; } ) ;
2018-10-14 15:30:06 +00:00
}
2019-02-05 14:50:25 +00:00
else if ( type = = ADD_INDEX )
{
if ( std : : any_of (
indices_description . indices . cbegin ( ) ,
indices_description . indices . cend ( ) ,
[ this ] ( const ASTPtr & index_ast )
{
2019-03-15 16:14:13 +00:00
return index_ast - > as < ASTIndexDeclaration & > ( ) . name = = index_name ;
2019-02-05 14:50:25 +00:00
} ) )
{
if ( if_not_exists )
return ;
else
throw Exception { " Cannot add index " + index_name + " : index with this name already exists " ,
ErrorCodes : : ILLEGAL_COLUMN } ;
}
auto insert_it = indices_description . indices . end ( ) ;
if ( ! after_index_name . empty ( ) )
{
insert_it = std : : find_if (
indices_description . indices . begin ( ) ,
indices_description . indices . end ( ) ,
[ this ] ( const ASTPtr & index_ast )
{
2019-03-15 16:14:13 +00:00
return index_ast - > as < ASTIndexDeclaration & > ( ) . name = = after_index_name ;
2019-02-05 14:50:25 +00:00
} ) ;
if ( insert_it = = indices_description . indices . end ( ) )
throw Exception ( " Wrong index name. Cannot find index ` " + after_index_name + " ` to insert after. " ,
ErrorCodes : : LOGICAL_ERROR ) ;
+ + insert_it ;
}
indices_description . indices . emplace ( insert_it , std : : dynamic_pointer_cast < ASTIndexDeclaration > ( index_decl ) ) ;
}
else if ( type = = DROP_INDEX )
{
auto erase_it = std : : find_if (
indices_description . indices . begin ( ) ,
indices_description . indices . end ( ) ,
[ this ] ( const ASTPtr & index_ast )
{
2019-03-15 16:14:13 +00:00
return index_ast - > as < ASTIndexDeclaration & > ( ) . name = = index_name ;
2019-02-05 14:50:25 +00:00
} ) ;
if ( erase_it = = indices_description . indices . end ( ) )
throw Exception ( " Wrong index name. Cannot find index ` " + index_name + " ` to drop. " ,
ErrorCodes : : LOGICAL_ERROR ) ;
indices_description . indices . erase ( erase_it ) ;
}
2019-04-15 09:30:45 +00:00
else if ( type = = MODIFY_TTL )
{
ttl_table_ast = ttl ;
}
2017-04-01 07:20:54 +00:00
else
throw Exception ( " Wrong parameter type in ALTER query " , ErrorCodes : : LOGICAL_ERROR ) ;
2016-01-11 21:46:36 +00:00
}
2014-10-21 12:11:20 +00:00
2018-11-13 12:08:07 +00:00
bool AlterCommand : : is_mutable ( ) const
{
if ( type = = COMMENT_COLUMN )
return false ;
if ( type = = MODIFY_COLUMN )
return data_type . get ( ) | | default_expression ;
2018-11-14 22:46:39 +00:00
// TODO: возможно, здесь нужно дополнить
2018-11-13 12:08:07 +00:00
return true ;
}
2016-05-05 18:28:46 +00:00
2019-02-05 14:50:25 +00:00
void AlterCommands : : apply ( ColumnsDescription & columns_description , IndicesDescription & indices_description ,
2019-04-15 09:30:45 +00:00
ASTPtr & order_by_ast , ASTPtr & primary_key_ast , ASTPtr & ttl_table_ast ) const
2016-01-11 21:46:36 +00:00
{
2018-03-06 20:18:34 +00:00
auto new_columns_description = columns_description ;
2019-02-05 14:50:25 +00:00
auto new_indices_description = indices_description ;
2018-11-28 12:06:52 +00:00
auto new_order_by_ast = order_by_ast ;
auto new_primary_key_ast = primary_key_ast ;
2019-04-15 09:30:45 +00:00
auto new_ttl_table_ast = ttl_table_ast ;
2017-04-01 07:20:54 +00:00
for ( const AlterCommand & command : * this )
2018-12-21 14:53:00 +00:00
if ( ! command . ignore )
2019-04-15 09:30:45 +00:00
command . apply ( new_columns_description , new_indices_description , new_order_by_ast , new_primary_key_ast , new_ttl_table_ast ) ;
2018-03-06 20:18:34 +00:00
columns_description = std : : move ( new_columns_description ) ;
2019-02-05 14:50:25 +00:00
indices_description = std : : move ( new_indices_description ) ;
2018-11-28 12:06:52 +00:00
order_by_ast = std : : move ( new_order_by_ast ) ;
primary_key_ast = std : : move ( new_primary_key_ast ) ;
2019-04-15 09:30:45 +00:00
ttl_table_ast = std : : move ( new_ttl_table_ast ) ;
2016-01-11 21:46:36 +00:00
}
2014-10-21 12:11:20 +00:00
2018-05-15 12:56:14 +00:00
void AlterCommands : : validate ( const IStorage & table , const Context & context )
2016-01-11 21:46:36 +00:00
{
2019-03-14 15:20:51 +00:00
/// A temporary object that is used to keep track of the current state of columns after applying a subset of commands.
auto columns = table . getColumns ( ) ;
2017-04-01 07:20:54 +00:00
2019-03-14 15:20:51 +00:00
/// Default expressions will be added to this list for type deduction.
2017-04-01 07:20:54 +00:00
auto default_expr_list = std : : make_shared < ASTExpressionList > ( ) ;
2019-03-14 15:20:51 +00:00
/// We will save ALTER ADD/MODIFY command indices (only the last for each column) for possible modification
/// (we might need to add deduced types or modify default expressions).
/// Saving indices because we can add new commands later and thus cause vector resize.
std : : unordered_map < String , size_t > column_to_command_idx ;
2017-04-01 07:20:54 +00:00
2019-03-14 15:20:51 +00:00
for ( size_t i = 0 ; i < size ( ) ; + + i )
2017-04-01 07:20:54 +00:00
{
2019-03-14 15:20:51 +00:00
auto & command = ( * this ) [ i ] ;
2017-04-01 07:20:54 +00:00
if ( command . type = = AlterCommand : : ADD_COLUMN | | command . type = = AlterCommand : : MODIFY_COLUMN )
{
const auto & column_name = command . column_name ;
if ( command . type = = AlterCommand : : ADD_COLUMN )
{
2019-03-14 15:20:51 +00:00
if ( columns . has ( column_name ) | | columns . hasNested ( column_name ) )
2018-12-21 14:53:00 +00:00
{
if ( command . if_not_exists )
command . ignore = true ;
else
throw Exception { " Cannot add column " + column_name + " : column with this name already exists " , ErrorCodes : : ILLEGAL_COLUMN } ;
}
2017-04-01 07:20:54 +00:00
}
else if ( command . type = = AlterCommand : : MODIFY_COLUMN )
{
2019-03-14 15:20:51 +00:00
if ( ! columns . has ( column_name ) )
2018-12-21 14:53:00 +00:00
{
if ( command . if_exists )
command . ignore = true ;
else
throw Exception { " Wrong column name. Cannot find column " + column_name + " to modify " , ErrorCodes : : ILLEGAL_COLUMN } ;
}
2017-04-01 07:20:54 +00:00
2018-12-21 14:53:00 +00:00
if ( ! command . ignore )
2019-03-14 15:20:51 +00:00
columns . remove ( column_name ) ;
2017-04-01 07:20:54 +00:00
}
2018-12-21 14:53:00 +00:00
if ( ! command . ignore )
2017-04-01 07:20:54 +00:00
{
2019-03-14 15:20:51 +00:00
column_to_command_idx [ column_name ] = i ;
2018-12-21 14:53:00 +00:00
/// we're creating dummy DataTypeUInt8 in order to prevent the NullPointerException in ExpressionActions
2019-03-14 15:20:51 +00:00
columns . add ( ColumnDescription (
column_name , command . data_type ? command . data_type : std : : make_shared < DataTypeUInt8 > ( ) ) ) ;
2017-04-01 07:20:54 +00:00
2018-12-21 14:53:00 +00:00
if ( command . default_expression )
2017-04-01 07:20:54 +00:00
{
2018-12-21 14:53:00 +00:00
if ( command . data_type )
{
2019-03-14 15:20:51 +00:00
const auto & final_column_name = column_name ;
2018-12-21 14:53:00 +00:00
const auto tmp_column_name = final_column_name + " _tmp " ;
default_expr_list - > children . emplace_back ( setAlias (
makeASTFunction ( " CAST " , std : : make_shared < ASTIdentifier > ( tmp_column_name ) ,
2019-03-14 15:20:51 +00:00
std : : make_shared < ASTLiteral > ( command . data_type - > getName ( ) ) ) ,
2018-12-21 14:53:00 +00:00
final_column_name ) ) ;
default_expr_list - > children . emplace_back ( setAlias ( command . default_expression - > clone ( ) , tmp_column_name ) ) ;
}
else
{
/// no type explicitly specified, will deduce later
default_expr_list - > children . emplace_back (
setAlias ( command . default_expression - > clone ( ) , column_name ) ) ;
}
2017-04-01 07:20:54 +00:00
}
}
}
else if ( command . type = = AlterCommand : : DROP_COLUMN )
{
2019-03-14 15:20:51 +00:00
if ( columns . has ( command . column_name ) | | columns . hasNested ( command . column_name ) )
2018-03-02 19:32:30 +00:00
{
2019-03-14 15:20:51 +00:00
for ( const ColumnDescription & column : columns )
2017-04-01 07:20:54 +00:00
{
2019-03-14 15:20:51 +00:00
const auto & default_expression = column . default_desc . expression ;
if ( ! default_expression )
continue ;
ASTPtr query = default_expression - > clone ( ) ;
auto syntax_result = SyntaxAnalyzer ( context ) . analyze ( query , columns . getAll ( ) ) ;
const auto actions = ExpressionAnalyzer ( query , syntax_result , context ) . getActions ( true ) ;
const auto required_columns = actions - > getRequiredColumns ( ) ;
if ( required_columns . end ( ) ! = std : : find ( required_columns . begin ( ) , required_columns . end ( ) , command . column_name ) )
throw Exception (
" Cannot drop column " + command . column_name + " , because column " + column . name +
" depends on it " , ErrorCodes : : ILLEGAL_COLUMN ) ;
2017-04-01 07:20:54 +00:00
}
2019-03-14 15:20:51 +00:00
columns . remove ( command . column_name ) ;
2018-12-21 14:53:00 +00:00
}
2019-03-14 15:20:51 +00:00
else if ( command . if_exists )
command . ignore = true ;
else
throw Exception ( " Wrong column name. Cannot find column " + command . column_name + " to drop " ,
ErrorCodes : : ILLEGAL_COLUMN ) ;
2017-04-01 07:20:54 +00:00
}
2018-10-14 15:30:06 +00:00
else if ( command . type = = AlterCommand : : COMMENT_COLUMN )
{
2019-03-14 15:20:51 +00:00
if ( ! columns . has ( command . column_name ) )
2018-10-14 15:30:06 +00:00
{
2018-12-21 14:53:00 +00:00
if ( command . if_exists )
command . ignore = true ;
else
throw Exception { " Wrong column name. Cannot find column " + command . column_name + " to comment " , ErrorCodes : : ILLEGAL_COLUMN } ;
2018-10-14 15:30:06 +00:00
}
}
2017-04-01 07:20:54 +00:00
}
/** Existing defaulted columns may require default expression extensions with a type conversion,
2019-03-14 15:20:51 +00:00
* therefore we add them to default_expr_list to recalculate their types */
for ( const auto & column : columns )
2017-04-01 07:20:54 +00:00
{
2019-03-14 15:20:51 +00:00
if ( column . default_desc . expression )
{
const auto tmp_column_name = column . name + " _tmp " ;
2017-04-01 07:20:54 +00:00
default_expr_list - > children . emplace_back ( setAlias (
2019-03-14 15:20:51 +00:00
makeASTFunction ( " CAST " , std : : make_shared < ASTIdentifier > ( tmp_column_name ) ,
std : : make_shared < ASTLiteral > ( column . type - > getName ( ) ) ) ,
column . name ) ) ;
2017-04-01 07:20:54 +00:00
2019-03-14 15:20:51 +00:00
default_expr_list - > children . emplace_back ( setAlias ( column . default_desc . expression - > clone ( ) , tmp_column_name ) ) ;
}
2017-04-01 07:20:54 +00:00
}
2018-11-08 15:43:14 +00:00
ASTPtr query = default_expr_list ;
2019-03-14 15:20:51 +00:00
auto syntax_result = SyntaxAnalyzer ( context ) . analyze ( query , columns . getAll ( ) ) ;
2018-11-08 17:28:52 +00:00
const auto actions = ExpressionAnalyzer ( query , syntax_result , context ) . getActions ( true ) ;
2017-04-01 07:20:54 +00:00
const auto block = actions - > getSampleBlock ( ) ;
/// set deduced types, modify default expression if necessary
2019-03-14 15:20:51 +00:00
for ( const auto & column : columns )
2017-04-01 07:20:54 +00:00
{
2019-03-14 15:20:51 +00:00
AlterCommand * command = nullptr ;
auto command_it = column_to_command_idx . find ( column . name ) ;
if ( command_it ! = column_to_command_idx . end ( ) )
command = & ( * this ) [ command_it - > second ] ;
2017-04-01 07:20:54 +00:00
2019-03-14 15:20:51 +00:00
if ( ! ( command & & command - > default_expression ) & & ! column . default_desc . expression )
continue ;
2017-04-01 07:20:54 +00:00
2019-03-14 15:20:51 +00:00
const DataTypePtr & explicit_type = command ? command - > data_type : column . type ;
if ( explicit_type )
2017-04-01 07:20:54 +00:00
{
2019-03-14 15:20:51 +00:00
const auto & tmp_column = block . getByName ( column . name + " _tmp " ) ;
2017-04-01 07:20:54 +00:00
const auto & deduced_type = tmp_column . type ;
2017-12-23 01:55:46 +00:00
if ( ! explicit_type - > equals ( * deduced_type ) )
2017-04-01 07:20:54 +00:00
{
2019-03-14 15:20:51 +00:00
if ( ! command )
2017-04-01 07:20:54 +00:00
{
2019-03-14 15:20:51 +00:00
/// column has no associated alter command, let's create it
2017-04-01 07:20:54 +00:00
/// add a new alter command to modify existing column
2019-03-14 15:20:51 +00:00
this - > emplace_back ( AlterCommand { AlterCommand : : MODIFY_COLUMN ,
column . name , explicit_type , column . default_desc . kind , column . default_desc . expression } ) ;
2017-04-01 07:20:54 +00:00
2019-03-14 15:20:51 +00:00
command = & back ( ) ;
2017-04-01 07:20:54 +00:00
}
2019-03-14 15:20:51 +00:00
command - > default_expression = makeASTFunction ( " CAST " ,
command - > default_expression - > clone ( ) ,
2018-10-22 08:54:54 +00:00
std : : make_shared < ASTLiteral > ( explicit_type - > getName ( ) ) ) ;
2017-04-01 07:20:54 +00:00
}
}
else
{
/// just set deduced type
2019-03-14 15:20:51 +00:00
command - > data_type = block . getByName ( column . name ) . type ;
2017-04-01 07:20:54 +00:00
}
}
2014-10-16 13:37:01 +00:00
}
2016-01-11 21:46:36 +00:00
2018-11-28 12:06:52 +00:00
void AlterCommands : : apply ( ColumnsDescription & columns_description ) const
{
auto out_columns_description = columns_description ;
2019-02-05 14:50:25 +00:00
IndicesDescription indices_description ;
2018-11-28 12:06:52 +00:00
ASTPtr out_order_by ;
ASTPtr out_primary_key ;
2019-04-15 09:30:45 +00:00
ASTPtr out_ttl_table ;
apply ( out_columns_description , indices_description , out_order_by , out_primary_key , out_ttl_table ) ;
2018-11-28 12:06:52 +00:00
if ( out_order_by )
throw Exception ( " Storage doesn't support modifying ORDER BY expression " , ErrorCodes : : NOT_IMPLEMENTED ) ;
if ( out_primary_key )
throw Exception ( " Storage doesn't support modifying PRIMARY KEY expression " , ErrorCodes : : NOT_IMPLEMENTED ) ;
2019-02-05 14:50:25 +00:00
if ( ! indices_description . indices . empty ( ) )
throw Exception ( " Storage doesn't support modifying indices " , ErrorCodes : : NOT_IMPLEMENTED ) ;
2019-04-15 09:30:45 +00:00
if ( out_ttl_table )
throw Exception ( " Storage doesn't support modifying TTL expression " , ErrorCodes : : NOT_IMPLEMENTED ) ;
2018-11-28 12:06:52 +00:00
columns_description = std : : move ( out_columns_description ) ;
}
2018-11-15 13:12:27 +00:00
bool AlterCommands : : is_mutable ( ) const
{
for ( const auto & param : * this )
{
if ( param . is_mutable ( ) )
return true ;
}
return false ;
}
2016-01-11 21:46:36 +00:00
}