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>
2020-02-19 12:52:27 +00:00
# include <Parsers/ASTAlterQuery.h>
# include <Parsers/ASTColumnDeclaration.h>
# include <Parsers/ASTConstraintDeclaration.h>
# include <Parsers/ASTCreateQuery.h>
# include <Parsers/ASTExpressionList.h>
# include <Parsers/ASTFunction.h>
2017-04-01 09:19:00 +00:00
# include <Parsers/ASTIdentifier.h>
2019-02-05 14:50:25 +00:00
# include <Parsers/ASTIndexDeclaration.h>
2019-06-02 14:41:12 +00:00
# include <Parsers/ASTConstraintDeclaration.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>
2019-07-24 12:56:39 +00:00
# include <Parsers/ASTSetQuery.h>
2019-12-26 18:17:05 +00:00
# include <Parsers/ASTCreateQuery.h>
2018-06-13 13:49:27 +00:00
# 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 ;
2019-07-24 12:56:39 +00:00
extern const int UNKNOWN_SETTING ;
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-08-08 20:02:30 +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-08-08 20:02:30 +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 & > ( ) ;
2019-12-23 16:44:50 +00:00
command . comment . emplace ( ast_comment . value . get < String > ( ) ) ;
2018-11-14 22:46:39 +00:00
}
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-08-08 20:02:30 +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 ;
}
2019-06-02 14:41:12 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : ADD_CONSTRAINT )
{
AlterCommand command ;
command . constraint_decl = command_ast - > constraint_decl ;
command . type = AlterCommand : : ADD_CONSTRAINT ;
const auto & ast_constraint_decl = command_ast - > constraint_decl - > as < ASTConstraintDeclaration & > ( ) ;
command . constraint_name = ast_constraint_decl . name ;
command . if_not_exists = command_ast - > if_not_exists ;
return command ;
}
2019-08-20 09:17:56 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : DROP_CONSTRAINT & & ! command_ast - > partition )
2019-06-02 14:41:12 +00:00
{
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 . if_exists = command_ast - > if_exists ;
2019-08-20 09:17:56 +00:00
command . type = AlterCommand : : DROP_CONSTRAINT ;
command . constraint_name = command_ast - > constraint - > as < ASTIdentifier & > ( ) . name ;
return command ;
}
2019-05-09 17:04:05 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : DROP_INDEX & & ! command_ast - > partition )
2019-02-05 14:50:25 +00:00
{
if ( command_ast - > clear_column )
2019-05-09 17:04:05 +00:00
throw Exception ( " \" ALTER TABLE table CLEAR INDEX index \" queries are not supported yet. Use \" CLEAR INDEX index IN PARTITION \" . " , ErrorCodes : : NOT_IMPLEMENTED ) ;
2019-02-05 14:50:25 +00:00
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 ;
}
2019-07-24 12:56:39 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_SETTING )
{
AlterCommand command ;
command . type = AlterCommand : : MODIFY_SETTING ;
command . settings_changes = command_ast - > settings_changes - > as < ASTSetQuery & > ( ) . changes ;
return command ;
}
2020-01-29 17:44:16 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_QUERY )
{
AlterCommand command ;
command . type = AlterCommand : : MODIFY_QUERY ;
command . select = command_ast - > select ;
return command ;
}
2018-06-13 13:49:27 +00:00
else
return { } ;
}
2019-12-26 18:17:05 +00:00
void AlterCommand : : apply ( StorageInMemoryMetadata & metadata ) const
2016-01-11 21:46:36 +00:00
{
2017-04-01 07:20:54 +00:00
if ( type = = ADD_COLUMN )
{
2019-05-21 11:24:32 +00:00
ColumnDescription column ( column_name , data_type , false ) ;
2019-03-14 15:20:51 +00:00
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 ;
}
2019-12-24 20:03:33 +00:00
if ( comment )
column . comment = * comment ;
2019-03-14 15:20:51 +00:00
column . codec = codec ;
2019-04-15 09:30:45 +00:00
column . ttl = ttl ;
2017-04-01 07:20:54 +00:00
2019-12-26 18:17:05 +00:00
metadata . columns . 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-12-26 18:17:05 +00:00
metadata . columns . flattenNested ( ) ;
2017-04-01 07:20:54 +00:00
}
else if ( type = = DROP_COLUMN )
{
2019-12-26 18:17:05 +00:00
metadata . columns . remove ( column_name ) ;
2017-04-01 07:20:54 +00:00
}
else if ( type = = MODIFY_COLUMN )
{
2019-12-26 18:17:05 +00:00
metadata . columns . 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 ) ;
2020-01-10 15:26:40 +00:00
else /// use info about new DataType
codec - > useInfoAboutType ( data_type ) ;
2019-05-01 21:43:05 +00:00
column . codec = codec ;
}
2019-12-23 16:44:50 +00:00
if ( comment )
column . comment = * comment ;
2019-05-01 21:43:05 +00:00
if ( ttl )
column . ttl = ttl ;
2019-12-24 18:07:51 +00:00
if ( data_type )
column . type = data_type ;
2018-11-13 12:08:07 +00:00
2019-12-24 18:07:51 +00:00
/// User specified default expression or changed
/// datatype. We have to replace default.
if ( default_expression | | data_type )
{
column . default_desc . kind = default_kind ;
column . default_desc . expression = default_expression ;
}
2019-05-01 21:43:05 +00:00
} ) ;
2017-04-01 07:20:54 +00:00
}
2018-11-13 12:51:55 +00:00
else if ( type = = MODIFY_ORDER_BY )
{
2019-12-27 14:46:11 +00:00
if ( ! metadata . primary_key_ast & & metadata . 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.
2019-12-27 14:46:11 +00:00
metadata . primary_key_ast = metadata . order_by_ast - > clone ( ) ;
2018-11-13 12:51:55 +00:00
}
2019-12-27 14:46:11 +00:00
metadata . 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-12-26 18:17:05 +00:00
metadata . columns . 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 (
2019-12-26 18:17:05 +00:00
metadata . indices . indices . cbegin ( ) ,
metadata . indices . indices . cend ( ) ,
2019-02-05 14:50:25 +00:00
[ 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 } ;
}
2019-12-26 18:17:05 +00:00
auto insert_it = metadata . indices . indices . end ( ) ;
2019-02-05 14:50:25 +00:00
if ( ! after_index_name . empty ( ) )
{
insert_it = std : : find_if (
2019-12-26 18:17:05 +00:00
metadata . indices . indices . begin ( ) ,
metadata . indices . indices . end ( ) ,
2019-02-05 14:50:25 +00:00
[ 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
} ) ;
2019-12-26 18:17:05 +00:00
if ( insert_it = = metadata . indices . indices . end ( ) )
2019-06-15 12:06:22 +00:00
throw Exception ( " Wrong index name. Cannot find index " + backQuote ( after_index_name ) + " to insert after. " ,
2019-12-30 14:46:02 +00:00
ErrorCodes : : BAD_ARGUMENTS ) ;
2019-02-05 14:50:25 +00:00
+ + insert_it ;
}
2019-12-26 18:17:05 +00:00
metadata . indices . indices . emplace ( insert_it , std : : dynamic_pointer_cast < ASTIndexDeclaration > ( index_decl ) ) ;
2019-02-05 14:50:25 +00:00
}
else if ( type = = DROP_INDEX )
{
auto erase_it = std : : find_if (
2019-12-26 18:17:05 +00:00
metadata . indices . indices . begin ( ) ,
metadata . indices . indices . end ( ) ,
2019-02-05 14:50:25 +00:00
[ 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
} ) ;
2019-12-26 18:17:05 +00:00
if ( erase_it = = metadata . indices . indices . end ( ) )
2019-06-03 21:08:52 +00:00
{
if ( if_exists )
return ;
2019-06-15 12:06:22 +00:00
throw Exception ( " Wrong index name. Cannot find index " + backQuote ( index_name ) + " to drop. " ,
2019-12-30 14:46:02 +00:00
ErrorCodes : : BAD_ARGUMENTS ) ;
2019-06-03 21:08:52 +00:00
}
2019-02-05 14:50:25 +00:00
2019-12-26 18:17:05 +00:00
metadata . indices . indices . erase ( erase_it ) ;
2019-02-05 14:50:25 +00:00
}
2019-06-02 14:41:12 +00:00
else if ( type = = ADD_CONSTRAINT )
{
if ( std : : any_of (
2019-12-26 18:17:05 +00:00
metadata . constraints . constraints . cbegin ( ) ,
metadata . constraints . constraints . cend ( ) ,
2019-06-02 14:41:12 +00:00
[ this ] ( const ASTPtr & constraint_ast )
{
return constraint_ast - > as < ASTConstraintDeclaration & > ( ) . name = = constraint_name ;
} ) )
{
if ( if_not_exists )
return ;
throw Exception ( " Cannot add constraint " + constraint_name + " : constraint with this name already exists " ,
ErrorCodes : : ILLEGAL_COLUMN ) ;
}
2019-12-26 18:17:05 +00:00
auto insert_it = metadata . constraints . constraints . end ( ) ;
2019-06-02 14:41:12 +00:00
2019-12-26 18:17:05 +00:00
metadata . constraints . constraints . emplace ( insert_it , std : : dynamic_pointer_cast < ASTConstraintDeclaration > ( constraint_decl ) ) ;
2019-06-02 14:41:12 +00:00
}
else if ( type = = DROP_CONSTRAINT )
{
auto erase_it = std : : find_if (
2019-12-26 18:17:05 +00:00
metadata . constraints . constraints . begin ( ) ,
metadata . constraints . constraints . end ( ) ,
2019-06-02 14:41:12 +00:00
[ this ] ( const ASTPtr & constraint_ast )
{
return constraint_ast - > as < ASTConstraintDeclaration & > ( ) . name = = constraint_name ;
} ) ;
2019-12-26 18:17:05 +00:00
if ( erase_it = = metadata . constraints . constraints . end ( ) )
2019-06-02 15:08:28 +00:00
{
2019-06-02 14:41:12 +00:00
if ( if_exists )
return ;
throw Exception ( " Wrong constraint name. Cannot find constraint ` " + constraint_name + " ` to drop. " ,
2019-12-30 14:46:02 +00:00
ErrorCodes : : BAD_ARGUMENTS ) ;
2019-06-02 14:41:12 +00:00
}
2019-12-26 18:17:05 +00:00
metadata . constraints . constraints . erase ( erase_it ) ;
2019-06-02 14:41:12 +00:00
}
2019-04-15 09:30:45 +00:00
else if ( type = = MODIFY_TTL )
{
2019-12-27 14:46:11 +00:00
metadata . ttl_for_table_ast = ttl ;
2019-04-15 09:30:45 +00:00
}
2020-01-29 17:44:16 +00:00
else if ( type = = MODIFY_QUERY )
{
metadata . select = select ;
}
2019-07-24 12:56:39 +00:00
else if ( type = = MODIFY_SETTING )
{
2019-12-27 14:36:59 +00:00
auto & settings_from_storage = metadata . settings_ast - > as < ASTSetQuery & > ( ) . changes ;
2019-12-26 18:17:05 +00:00
for ( const auto & change : settings_changes )
{
auto finder = [ & change ] ( const SettingChange & c ) { return c . name = = change . name ; } ;
2019-12-29 11:25:26 +00:00
auto it = std : : find_if ( settings_from_storage . begin ( ) , settings_from_storage . end ( ) , finder ) ;
if ( it ! = settings_from_storage . end ( ) )
2019-12-26 18:17:05 +00:00
it - > value = change . value ;
else
2019-12-27 14:36:59 +00:00
settings_from_storage . push_back ( change ) ;
2019-12-26 18:17:05 +00:00
}
2019-07-24 12:56:39 +00:00
}
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
2019-12-23 16:44:50 +00:00
bool AlterCommand : : isModifyingData ( ) const
2018-11-13 12:08:07 +00:00
{
2019-12-24 18:07:51 +00:00
/// Possible change data representation on disk
2018-11-13 12:08:07 +00:00
if ( type = = MODIFY_COLUMN )
2019-12-24 18:07:51 +00:00
return data_type ! = nullptr ;
2019-12-23 16:44:50 +00:00
2019-12-24 18:07:51 +00:00
return type = = ADD_COLUMN /// We need to change columns.txt in each part for MergeTree
| | type = = DROP_COLUMN /// We need to change columns.txt in each part for MergeTree
| | type = = DROP_INDEX ; /// We need to remove file from filesystem for MergeTree
2018-11-13 12:08:07 +00:00
}
2016-05-05 18:28:46 +00:00
2019-08-06 12:52:08 +00:00
bool AlterCommand : : isSettingsAlter ( ) const
{
return type = = MODIFY_SETTING ;
}
2019-12-27 14:36:59 +00:00
bool AlterCommand : : isCommentAlter ( ) const
{
if ( type = = COMMENT_COLUMN )
{
return true ;
}
else if ( type = = MODIFY_COLUMN )
{
return comment . has_value ( )
& & codec = = nullptr
& & data_type = = nullptr
& & default_expression = = nullptr
& & ttl = = nullptr ;
}
return false ;
}
2019-12-26 18:17:05 +00:00
String alterTypeToString ( const AlterCommand : : Type type )
{
switch ( type )
{
case AlterCommand : : Type : : ADD_COLUMN :
return " ADD COLUMN " ;
case AlterCommand : : Type : : ADD_CONSTRAINT :
return " ADD CONSTRAINT " ;
case AlterCommand : : Type : : ADD_INDEX :
return " ADD INDEX " ;
case AlterCommand : : Type : : COMMENT_COLUMN :
return " COMMENT COLUMN " ;
case AlterCommand : : Type : : DROP_COLUMN :
return " DROP COLUMN " ;
case AlterCommand : : Type : : DROP_CONSTRAINT :
return " DROP CONSTRAINT " ;
case AlterCommand : : Type : : DROP_INDEX :
return " DROP INDEX " ;
case AlterCommand : : Type : : MODIFY_COLUMN :
return " MODIFY COLUMN " ;
case AlterCommand : : Type : : MODIFY_ORDER_BY :
return " MODIFY ORDER BY " ;
case AlterCommand : : Type : : MODIFY_TTL :
return " MODIFY TTL " ;
case AlterCommand : : Type : : MODIFY_SETTING :
return " MODIFY SETTING " ;
2020-01-29 17:44:16 +00:00
case AlterCommand : : Type : : MODIFY_QUERY :
return " MODIFY QUERY " ;
2019-12-26 18:17:05 +00:00
}
__builtin_unreachable ( ) ;
}
void AlterCommands : : apply ( StorageInMemoryMetadata & metadata ) const
2016-01-11 21:46:36 +00:00
{
2019-12-26 18:17:05 +00:00
if ( ! prepared )
throw DB : : Exception ( " Alter commands is not prepared. Cannot apply. It's a bug " , ErrorCodes : : LOGICAL_ERROR ) ;
2017-04-01 07:20:54 +00:00
2019-12-26 18:17:05 +00:00
auto metadata_copy = metadata ;
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-12-26 18:17:05 +00:00
command . apply ( metadata_copy ) ;
metadata = std : : move ( metadata_copy ) ;
2016-01-11 21:46:36 +00:00
}
2014-10-21 12:11:20 +00:00
2019-12-26 18:17:05 +00:00
2020-02-19 12:52:27 +00:00
void AlterCommands : : prepare ( const StorageInMemoryMetadata & metadata , const Context & /*context*/ )
2016-01-11 21:46:36 +00:00
{
2019-12-26 18:17:05 +00:00
auto columns = metadata . columns ;
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 ] ;
2020-02-19 14:39:01 +00:00
bool has_column = columns . has ( command . column_name ) | | columns . hasNested ( command . column_name ) ;
2020-02-19 12:52:27 +00:00
if ( command . type = = AlterCommand : : MODIFY_COLUMN )
2017-04-01 07:20:54 +00:00
{
2020-02-19 12:52:27 +00:00
if ( ! has_column & & command . if_exists )
command . ignore = true ;
2017-04-01 07:20:54 +00:00
2020-02-19 12:52:27 +00:00
if ( has_column )
2017-04-01 07:20:54 +00:00
{
2020-02-19 12:52:27 +00:00
auto column_from_table = columns . get ( command . column_name ) ;
if ( ! command . default_expression & & column_from_table . default_desc . expression )
2017-04-01 07:20:54 +00:00
{
2020-02-19 12:52:27 +00:00
command . default_kind = column_from_table . default_desc . kind ;
command . default_expression = column_from_table . default_desc . expression ;
2017-04-01 07:20:54 +00:00
}
}
}
2020-02-19 14:39:01 +00:00
else if ( command . type = = AlterCommand : : ADD_COLUMN )
{
if ( has_column & & command . if_not_exists )
command . ignore = true ;
}
else if ( command . type = = AlterCommand : : DROP_COLUMN
| | command . type = = AlterCommand : : COMMENT_COLUMN )
2017-04-01 07:20:54 +00:00
{
2020-02-19 12:52:27 +00:00
if ( ! has_column & & command . if_exists )
2019-03-14 15:20:51 +00:00
command . ignore = true ;
2017-04-01 07:20:54 +00:00
}
}
2019-12-26 18:17:05 +00:00
prepared = true ;
2014-10-16 13:37:01 +00:00
}
2016-01-11 21:46:36 +00:00
2019-12-26 18:17:05 +00:00
void AlterCommands : : validate ( const StorageInMemoryMetadata & metadata , const Context & context ) const
2018-11-28 12:06:52 +00:00
{
2020-02-19 14:39:01 +00:00
auto all_columns = metadata . columns ;
2019-12-26 18:17:05 +00:00
for ( size_t i = 0 ; i < size ( ) ; + + i )
{
auto & command = ( * this ) [ i ] ;
2020-02-19 12:52:27 +00:00
const auto & column_name = command . column_name ;
if ( command . type = = AlterCommand : : ADD_COLUMN )
2019-12-26 18:17:05 +00:00
{
2020-02-19 12:52:27 +00:00
if ( metadata . columns . has ( column_name ) | | metadata . columns . hasNested ( column_name ) )
2020-02-19 14:39:01 +00:00
{
2020-02-19 12:52:27 +00:00
if ( ! command . if_not_exists )
throw Exception { " Cannot add column " + column_name + " : column with this name already exists " , ErrorCodes : : ILLEGAL_COLUMN } ;
2020-02-19 14:39:01 +00:00
else
continue ;
}
2019-08-06 12:52:08 +00:00
2020-02-19 12:52:27 +00:00
if ( ! command . data_type )
throw Exception { " Data type have to be specified for column " + column_name + " to add " , ErrorCodes : : ILLEGAL_COLUMN } ;
if ( command . default_expression )
2020-02-19 14:43:34 +00:00
validateDefaultExpressionForColumn ( command . default_expression , column_name , command . data_type , all_columns , context ) ;
2020-02-19 14:39:01 +00:00
all_columns . add ( ColumnDescription ( column_name , command . data_type , false ) ) ;
2020-02-19 12:52:27 +00:00
}
else if ( command . type = = AlterCommand : : MODIFY_COLUMN )
{
if ( ! metadata . columns . has ( column_name ) )
2020-02-19 14:39:01 +00:00
{
2020-02-19 12:52:27 +00:00
if ( ! command . if_exists )
throw Exception { " Wrong column name. Cannot find column " + column_name + " to modify " , ErrorCodes : : ILLEGAL_COLUMN } ;
2020-02-19 14:39:01 +00:00
else
continue ;
}
2020-02-19 12:52:27 +00:00
2020-02-19 14:39:01 +00:00
auto column_in_table = metadata . columns . get ( column_name ) ;
2020-02-19 12:52:27 +00:00
if ( command . default_expression )
2019-12-26 18:17:05 +00:00
{
2020-02-19 12:52:27 +00:00
if ( ! command . data_type )
2020-02-19 14:43:34 +00:00
validateDefaultExpressionForColumn (
2020-02-19 14:39:01 +00:00
command . default_expression , column_name , column_in_table . type , all_columns , context ) ;
2020-02-19 12:52:27 +00:00
else
2020-02-19 14:43:34 +00:00
validateDefaultExpressionForColumn (
2020-02-19 14:39:01 +00:00
command . default_expression , column_name , command . data_type , all_columns , context ) ;
}
else if ( column_in_table . default_desc . expression & & command . data_type )
{
2020-02-19 14:43:34 +00:00
validateDefaultExpressionForColumn (
2020-02-19 14:39:01 +00:00
column_in_table . default_desc . expression , column_name , command . data_type , all_columns , context ) ;
2019-12-26 18:17:05 +00:00
}
}
else if ( command . type = = AlterCommand : : DROP_COLUMN )
{
if ( metadata . columns . has ( command . column_name ) | | metadata . columns . hasNested ( command . column_name ) )
{
for ( const ColumnDescription & column : metadata . columns )
{
const auto & default_expression = column . default_desc . expression ;
2020-02-19 12:52:27 +00:00
if ( default_expression )
{
ASTPtr query = default_expression - > clone ( ) ;
auto syntax_result = SyntaxAnalyzer ( context ) . analyze ( query , metadata . 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 ) ;
}
2019-12-26 18:17:05 +00:00
}
}
else if ( ! command . if_exists )
throw Exception ( " Wrong column name. Cannot find column " + command . column_name + " to drop " ,
ErrorCodes : : ILLEGAL_COLUMN ) ;
}
else if ( command . type = = AlterCommand : : COMMENT_COLUMN )
{
if ( ! metadata . columns . has ( command . column_name ) )
{
if ( ! command . if_exists )
throw Exception { " Wrong column name. Cannot find column " + command . column_name + " to comment " , ErrorCodes : : ILLEGAL_COLUMN } ;
}
}
}
2019-08-06 12:52:08 +00:00
}
2020-02-19 12:52:27 +00:00
2020-02-19 14:43:34 +00:00
void AlterCommands : : validateDefaultExpressionForColumn (
2020-02-19 12:52:27 +00:00
const ASTPtr default_expression ,
const String & column_name ,
const DataTypePtr column_type ,
const ColumnsDescription & all_columns ,
const Context & context ) const
{
try
{
String tmp_column_name = " __tmp " + column_name ;
auto copy_expression = default_expression - > clone ( ) ;
auto default_with_cast = makeASTFunction ( " CAST " , copy_expression , std : : make_shared < ASTLiteral > ( column_type - > getName ( ) ) ) ;
auto query_with_alias = setAlias ( default_with_cast , tmp_column_name ) ;
auto syntax_result = SyntaxAnalyzer ( context ) . analyze ( query_with_alias , all_columns . getAll ( ) ) ;
2020-02-19 15:07:02 +00:00
ExpressionAnalyzer ( query_with_alias , syntax_result , context ) . getActions ( true ) ;
2020-02-19 12:52:27 +00:00
}
catch ( Exception & ex )
{
ex . addMessage ( " default expression and column type are incompatible. Cannot alter column ' " + column_name + " ' " ) ;
throw ( ex ) ;
}
}
2019-08-06 12:52:08 +00:00
2019-12-23 16:44:50 +00:00
bool AlterCommands : : isModifyingData ( ) const
2018-11-15 13:12:27 +00:00
{
for ( const auto & param : * this )
{
2019-12-23 16:44:50 +00:00
if ( param . isModifyingData ( ) )
2018-11-15 13:12:27 +00:00
return true ;
}
return false ;
}
2019-08-06 12:52:08 +00:00
bool AlterCommands : : isSettingsAlter ( ) const
{
return std : : all_of ( begin ( ) , end ( ) , [ ] ( const AlterCommand & c ) { return c . isSettingsAlter ( ) ; } ) ;
}
2019-12-27 14:36:59 +00:00
bool AlterCommands : : isCommentAlter ( ) const
{
return std : : all_of ( begin ( ) , end ( ) , [ ] ( const AlterCommand & c ) { return c . isCommentAlter ( ) ; } ) ;
}
2016-01-11 21:46:36 +00:00
}