2020-01-13 16:39:20 +00:00
# include <Compression/CompressionFactory.h>
# include <DataTypes/DataTypeArray.h>
# include <DataTypes/DataTypeDate.h>
# include <DataTypes/DataTypeDateTime.h>
# include <DataTypes/DataTypeEnum.h>
2018-06-13 13:49:27 +00:00
# include <DataTypes/DataTypeFactory.h>
2020-01-13 16:39:20 +00:00
# include <DataTypes/DataTypeNullable.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>
# include <Interpreters/ExpressionActions.h>
2020-03-03 10:02:43 +00:00
# include <Interpreters/addTypeConversionToAST.h>
2020-01-13 16:39:20 +00:00
# include <Interpreters/ExpressionAnalyzer.h>
2023-09-23 09:50:12 +00:00
# include <Interpreters/FunctionNameNormalizer.h>
2020-07-22 17:13:05 +00:00
# include <Interpreters/TreeRewriter.h>
2020-04-02 16:11:10 +00:00
# include <Interpreters/RenameColumnVisitor.h>
2022-09-28 14:28:28 +00:00
# include <Interpreters/GinFilter.h>
2023-11-18 07:45:10 +00:00
# include <Interpreters/inplaceBlockConversions.h>
2023-11-28 14:13:12 +00:00
# include <Interpreters/InterpreterSelectWithUnionQuery.h>
# include <Interpreters/InterpreterSelectQueryAnalyzer.h>
2020-02-19 12:52:27 +00:00
# include <Parsers/ASTAlterQuery.h>
# include <Parsers/ASTColumnDeclaration.h>
# include <Parsers/ASTConstraintDeclaration.h>
# include <Parsers/ASTExpressionList.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>
2021-02-10 14:12:49 +00:00
# include <Parsers/ASTProjectionDeclaration.h>
2023-08-09 20:57:49 +00:00
# include <Parsers/ASTStatisticDeclaration.h>
2017-04-01 09:19:00 +00:00
# include <Parsers/ASTLiteral.h>
2019-07-24 12:56:39 +00:00
# include <Parsers/ASTSetQuery.h>
2020-11-02 18:37:23 +00:00
# include <Parsers/queryToString.h>
2020-01-13 16:39:20 +00:00
# include <Storages/AlterCommands.h>
# include <Storages/IStorage.h>
2022-07-21 19:50:19 +00:00
# include <Storages/LightweightDeleteDescription.h>
2023-09-20 09:31:12 +00:00
# include <Storages/BlockNumberColumn.h>
2022-09-26 07:14:58 +00:00
# include <Storages/MergeTree/MergeTreeData.h>
2018-06-13 13:49:27 +00:00
# include <Common/typeid_cast.h>
2020-11-02 18:37:23 +00:00
# include <Common/randomSeed.h>
2019-04-15 09:30:45 +00:00
2023-11-18 15:44:45 +00:00
# include <ranges>
2014-10-16 13:37:01 +00:00
namespace DB
{
2016-01-11 21:46:36 +00:00
namespace ErrorCodes
{
extern const int ILLEGAL_COLUMN ;
2023-09-26 17:16:01 +00:00
extern const int ILLEGAL_STATISTIC ;
2018-11-13 12:51:55 +00:00
extern const int BAD_ARGUMENTS ;
2020-02-20 10:04:15 +00:00
extern const int NOT_FOUND_COLUMN_IN_BLOCK ;
2016-01-11 21:46:36 +00:00
extern const int LOGICAL_ERROR ;
2020-02-20 10:04:15 +00:00
extern const int DUPLICATE_COLUMN ;
2020-03-31 16:18:18 +00:00
extern const int NOT_IMPLEMENTED ;
2023-11-07 11:01:52 +00:00
extern const int SUPPORT_IS_DISABLED ;
2023-11-18 07:45:10 +00:00
extern const int ALTER_OF_COLUMN_IS_FORBIDDEN ;
2016-01-11 21:46:36 +00:00
}
2020-09-20 13:27:33 +00:00
namespace
{
AlterCommand : : RemoveProperty removePropertyFromString ( const String & property )
{
if ( property . empty ( ) )
return AlterCommand : : RemoveProperty : : NO_PROPERTY ;
else if ( property = = " DEFAULT " )
return AlterCommand : : RemoveProperty : : DEFAULT ;
else if ( property = = " MATERIALIZED " )
return AlterCommand : : RemoveProperty : : MATERIALIZED ;
else if ( property = = " ALIAS " )
return AlterCommand : : RemoveProperty : : ALIAS ;
else if ( property = = " COMMENT " )
return AlterCommand : : RemoveProperty : : COMMENT ;
else if ( property = = " CODEC " )
return AlterCommand : : RemoveProperty : : CODEC ;
else if ( property = = " TTL " )
return AlterCommand : : RemoveProperty : : TTL ;
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Cannot remove unknown property '{}' " , property ) ;
}
}
2016-01-11 21:46:36 +00:00
2020-08-28 17:40:45 +00:00
std : : optional < AlterCommand > AlterCommand : : parse ( const ASTAlterCommand * command_ast )
2018-06-13 13:49:27 +00:00
{
const DataTypeFactory & data_type_factory = DataTypeFactory : : instance ( ) ;
if ( command_ast - > type = = ASTAlterCommand : : ADD_COLUMN )
{
AlterCommand command ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2018-06-13 13:49:27 +00:00
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 )
2020-08-31 06:24:19 +00:00
{
if ( ast_col_decl . default_specifier = = " ALIAS " )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Cannot specify codec for column type ALIAS " ) ;
2020-08-28 17:40:45 +00:00
command . codec = ast_col_decl . codec ;
2020-08-31 06:24:19 +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 ;
2020-07-01 14:58:52 +00:00
command . first = command_ast - > first ;
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 ;
}
2020-03-17 13:49:50 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : DROP_COLUMN )
2018-06-13 13:49:27 +00:00
{
AlterCommand command ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2018-06-13 13:49:27 +00:00
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 ;
2020-03-17 13:49:50 +00:00
if ( command_ast - > clear_column )
command . clear = true ;
if ( command_ast - > partition )
command . partition = command_ast - > partition ;
2018-06-13 13:49:27 +00:00
return command ;
}
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_COLUMN )
{
AlterCommand command ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2018-06-13 13:49:27 +00:00
command . type = AlterCommand : : MODIFY_COLUMN ;
2019-03-15 16:14:13 +00:00
const auto & ast_col_decl = command_ast - > col_decl - > as < ASTColumnDeclaration & > ( ) ;
2020-09-11 17:07:00 +00:00
command . column_name = ast_col_decl . name ;
2020-09-20 13:27:33 +00:00
command . to_remove = removePropertyFromString ( command_ast - > remove_property ) ;
2018-06-13 13:49:27 +00:00
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 )
2020-08-28 17:40:45 +00:00
command . codec = ast_col_decl . codec ;
2019-03-15 14:59:03 +00:00
2020-07-01 14:58:52 +00:00
if ( command_ast - > column )
command . after_column = getIdentifierName ( command_ast - > column ) ;
command . first = command_ast - > first ;
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 ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2018-11-26 13:01:48 +00:00
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 ;
}
2021-09-20 11:06:19 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_COMMENT )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . type = COMMENT_TABLE ;
const auto & ast_comment = command_ast - > comment - > as < ASTLiteral & > ( ) ;
command . comment = ast_comment . value . get < String > ( ) ;
return command ;
}
2018-10-15 18:47:47 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_ORDER_BY )
{
AlterCommand command ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2018-10-15 18:47:47 +00:00
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 ;
}
2020-08-27 13:10:10 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_SAMPLE_BY )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . type = AlterCommand : : MODIFY_SAMPLE_BY ;
command . sample_by = command_ast - > sample_by ;
return command ;
}
2021-10-14 13:44:28 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : REMOVE_SAMPLE_BY )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . type = AlterCommand : : REMOVE_SAMPLE_BY ;
return command ;
}
2019-02-05 14:50:25 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : ADD_INDEX )
{
AlterCommand command ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2019-02-05 14:50:25 +00:00
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 )
2020-10-24 18:46:10 +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 ;
2021-07-01 15:59:16 +00:00
command . first = command_ast - > first ;
2019-02-05 14:50:25 +00:00
return command ;
}
2023-08-09 20:57:49 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : ADD_STATISTIC )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . statistic_decl = command_ast - > statistic_decl ;
command . type = AlterCommand : : ADD_STATISTIC ;
const auto & ast_stat_decl = command_ast - > statistic_decl - > as < ASTStatisticDeclaration & > ( ) ;
2023-09-08 00:27:17 +00:00
command . statistic_columns = ast_stat_decl . getColumnNames ( ) ;
2023-09-04 13:51:00 +00:00
command . statistic_type = ast_stat_decl . type ;
2023-08-09 20:57:49 +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 ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2019-06-02 14:41:12 +00:00
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 ;
}
2021-02-10 14:12:49 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : ADD_PROJECTION )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . projection_decl = command_ast - > projection_decl ;
command . type = AlterCommand : : ADD_PROJECTION ;
const auto & ast_projection_decl = command_ast - > projection_decl - > as < ASTProjectionDeclaration & > ( ) ;
command . projection_name = ast_projection_decl . name ;
if ( command_ast - > projection )
command . after_projection_name = command_ast - > projection - > as < ASTIdentifier & > ( ) . name ( ) ;
command . first = command_ast - > first ;
command . if_not_exists = command_ast - > if_not_exists ;
return command ;
}
2020-03-22 00:56:10 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : DROP_CONSTRAINT )
2019-06-02 14:41:12 +00:00
{
AlterCommand command ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2019-06-02 14:41:12 +00:00
command . if_exists = command_ast - > if_exists ;
2019-08-20 09:17:56 +00:00
command . type = AlterCommand : : DROP_CONSTRAINT ;
2020-10-24 18:46:10 +00:00
command . constraint_name = command_ast - > constraint - > as < ASTIdentifier & > ( ) . name ( ) ;
2019-08-20 09:17:56 +00:00
return command ;
}
2020-03-17 13:49:50 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : DROP_INDEX )
2019-02-05 14:50:25 +00:00
{
AlterCommand command ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2019-02-05 14:50:25 +00:00
command . type = AlterCommand : : DROP_INDEX ;
2020-10-24 18:46:10 +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 ;
2020-03-17 13:49:50 +00:00
if ( command_ast - > clear_index )
command . clear = true ;
if ( command_ast - > partition )
command . partition = command_ast - > partition ;
2019-02-05 14:50:25 +00:00
return command ;
}
2023-08-09 20:57:49 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : DROP_STATISTIC )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . type = AlterCommand : : DROP_STATISTIC ;
2023-09-04 13:51:00 +00:00
const auto & ast_stat_decl = command_ast - > statistic_decl - > as < ASTStatisticDeclaration & > ( ) ;
2023-09-08 00:27:17 +00:00
command . statistic_columns = ast_stat_decl . getColumnNames ( ) ;
2023-09-04 13:51:00 +00:00
command . statistic_type = ast_stat_decl . type ;
2023-08-09 20:57:49 +00:00
command . if_exists = command_ast - > if_exists ;
command . clear = command_ast - > clear_statistic ;
if ( command_ast - > partition )
command . partition = command_ast - > partition ;
return command ;
}
2021-02-10 14:12:49 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : DROP_PROJECTION )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . type = AlterCommand : : DROP_PROJECTION ;
command . projection_name = command_ast - > projection - > as < ASTIdentifier & > ( ) . name ( ) ;
command . if_exists = command_ast - > if_exists ;
if ( command_ast - > clear_projection )
command . clear = true ;
if ( command_ast - > partition )
command . partition = command_ast - > partition ;
return command ;
}
2019-04-15 09:30:45 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_TTL )
{
AlterCommand command ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2019-04-15 09:30:45 +00:00
command . type = AlterCommand : : MODIFY_TTL ;
command . ttl = command_ast - > ttl ;
return command ;
}
2020-09-20 13:27:33 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : REMOVE_TTL )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . type = AlterCommand : : REMOVE_TTL ;
return command ;
}
2019-07-24 12:56:39 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_SETTING )
{
AlterCommand command ;
2020-01-15 13:00:08 +00:00
command . ast = command_ast - > clone ( ) ;
2019-07-24 12:56:39 +00:00
command . type = AlterCommand : : MODIFY_SETTING ;
command . settings_changes = command_ast - > settings_changes - > as < ASTSetQuery & > ( ) . changes ;
return command ;
}
2021-08-27 06:30:21 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_DATABASE_SETTING )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . type = AlterCommand : : MODIFY_DATABASE_SETTING ;
command . settings_changes = command_ast - > settings_changes - > as < ASTSetQuery & > ( ) . changes ;
return command ;
}
2020-12-02 21:18:25 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : RESET_SETTING )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . type = AlterCommand : : RESET_SETTING ;
for ( const ASTPtr & identifier_ast : command_ast - > settings_resets - > children )
{
const auto & identifier = identifier_ast - > as < ASTIdentifier & > ( ) ;
auto insertion = command . settings_resets . emplace ( identifier . name ( ) ) ;
if ( ! insertion . second )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Duplicate setting name {} " , backQuote ( identifier . name ( ) ) ) ;
2020-12-02 21:18:25 +00:00
}
return command ;
}
2020-01-29 17:44:16 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : MODIFY_QUERY )
{
AlterCommand command ;
2020-03-24 17:05:38 +00:00
command . ast = command_ast - > clone ( ) ;
2020-01-29 17:44:16 +00:00
command . type = AlterCommand : : MODIFY_QUERY ;
command . select = command_ast - > select ;
return command ;
}
2020-03-24 17:05:38 +00:00
else if ( command_ast - > type = = ASTAlterCommand : : RENAME_COLUMN )
{
AlterCommand command ;
command . ast = command_ast - > clone ( ) ;
command . type = AlterCommand : : RENAME_COLUMN ;
2020-10-24 18:46:10 +00:00
command . column_name = command_ast - > column - > as < ASTIdentifier & > ( ) . name ( ) ;
command . rename_to = command_ast - > rename_to - > as < ASTIdentifier & > ( ) . name ( ) ;
2020-04-03 16:45:49 +00:00
command . if_exists = command_ast - > if_exists ;
2020-03-24 17:05:38 +00:00
return command ;
}
2018-06-13 13:49:27 +00:00
else
return { } ;
}
2021-04-10 23:33:54 +00:00
void AlterCommand : : apply ( StorageInMemoryMetadata & metadata , ContextPtr context ) const
2016-01-11 21:46:36 +00:00
{
2016-05-05 18:28:46 +00:00
if ( type = = ADD_COLUMN )
2014-10-16 13:37:01 +00:00
{
2020-04-27 13:55:30 +00:00
ColumnDescription column ( column_name , data_type ) ;
2019-03-14 15:20:51 +00:00
if ( default_expression )
2016-01-11 21:46:36 +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 ;
2020-08-28 17:40:45 +00:00
if ( codec )
2023-05-24 17:26:15 +00:00
column . codec = CompressionCodecFactory : : instance ( ) . validateCodecAndGetPreprocessedAST ( codec , data_type , false , true , true ) ;
2020-08-28 17:40:45 +00:00
2019-04-15 09:30:45 +00:00
column . ttl = ttl ;
2017-04-01 07:20:54 +00:00
2021-04-10 23:33:54 +00:00
if ( context - > getSettingsRef ( ) . flatten_nested )
2023-11-16 07:01:49 +00:00
{
StorageInMemoryMetadata temporary_metadata ;
temporary_metadata . columns . add ( column , /*after_column*/ " " , /*first*/ true ) ;
temporary_metadata . columns . flattenNested ( ) ;
const auto transformed_columns = temporary_metadata . columns . getAll ( ) ;
2023-11-18 15:44:45 +00:00
auto add_column = [ & ] ( const String & name )
2023-11-16 07:01:49 +00:00
{
2023-11-18 15:44:45 +00:00
const auto & transformed_column = temporary_metadata . columns . get ( name ) ;
2023-11-16 07:01:49 +00:00
metadata . columns . add ( transformed_column , after_column , first ) ;
2023-11-18 15:44:45 +00:00
} ;
if ( ! after_column . empty ( ) | | first )
{
for ( const auto & col : transformed_columns | std : : views : : reverse )
add_column ( col . name ) ;
}
else
{
for ( const auto & col : transformed_columns )
add_column ( col . name ) ;
2023-11-16 07:01:49 +00:00
}
}
else
{
metadata . columns . add ( column , after_column , first ) ;
}
2016-01-11 21:46:36 +00:00
}
2016-05-05 18:28:46 +00:00
else if ( type = = DROP_COLUMN )
2016-01-11 21:46:36 +00:00
{
2020-03-17 13:49:50 +00:00
/// Otherwise just clear data on disk
if ( ! clear & & ! partition )
metadata . columns . remove ( column_name ) ;
2016-01-11 21:46:36 +00:00
}
2016-05-05 18:28:46 +00:00
else if ( type = = MODIFY_COLUMN )
2016-01-11 21:46:36 +00:00
{
2020-07-01 14:58:52 +00:00
metadata . columns . modify ( column_name , after_column , first , [ & ] ( ColumnDescription & column )
2019-04-02 12:51:31 +00:00
{
2020-09-20 13:27:33 +00:00
if ( to_remove = = RemoveProperty : : DEFAULT
| | to_remove = = RemoveProperty : : MATERIALIZED
| | to_remove = = RemoveProperty : : ALIAS )
{
column . default_desc = ColumnDefault { } ;
}
else if ( to_remove = = RemoveProperty : : CODEC )
{
column . codec . reset ( ) ;
}
else if ( to_remove = = RemoveProperty : : COMMENT )
{
column . comment = String { } ;
}
else if ( to_remove = = RemoveProperty : : TTL )
{
column . ttl . reset ( ) ;
}
else
{
if ( codec )
2023-05-24 17:26:15 +00:00
column . codec = CompressionCodecFactory : : instance ( ) . validateCodecAndGetPreprocessedAST ( codec , data_type ? data_type : column . type , false , true , true ) ;
2019-05-01 21:43:05 +00:00
2020-09-20 13:27:33 +00:00
if ( comment )
column . comment = * comment ;
2019-05-01 21:43:05 +00:00
2020-09-20 13:27:33 +00:00
if ( ttl )
column . ttl = ttl ;
2019-05-01 21:43:05 +00:00
2020-09-20 13:27:33 +00:00
if ( data_type )
column . type = data_type ;
2018-11-13 12:08:07 +00:00
2020-09-20 13:27:33 +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-12-24 18:07:51 +00:00
}
2019-05-01 21:43:05 +00:00
} ) ;
2020-06-09 17:22:03 +00:00
2014-10-16 13:37:01 +00:00
}
2018-11-13 12:51:55 +00:00
else if ( type = = MODIFY_ORDER_BY )
{
2020-06-12 09:37:52 +00:00
auto & sorting_key = metadata . sorting_key ;
auto & primary_key = metadata . primary_key ;
if ( primary_key . definition_ast = = nullptr & & sorting_key . definition_ast ! = nullptr )
2018-11-13 12:51:55 +00:00
{
2020-06-12 09:37:52 +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.
primary_key = KeyDescription : : getKeyFromAST ( sorting_key . definition_ast , metadata . columns , context ) ;
2018-11-13 12:51:55 +00:00
}
2020-06-15 10:14:36 +00:00
/// Recalculate key with new order_by expression.
2020-06-12 09:37:52 +00:00
sorting_key . recalculateWithNewAST ( order_by , metadata . columns , context ) ;
2016-05-05 18:28:46 +00:00
}
2020-08-27 13:10:10 +00:00
else if ( type = = MODIFY_SAMPLE_BY )
{
metadata . sampling_key . recalculateWithNewAST ( sample_by , metadata . columns , context ) ;
}
2021-10-14 13:44:28 +00:00
else if ( type = = REMOVE_SAMPLE_BY )
{
metadata . sampling_key = { } ;
}
2018-10-14 15:30:06 +00:00
else if ( type = = COMMENT_COLUMN )
{
2020-06-08 18:49:54 +00:00
metadata . columns . modify ( column_name ,
[ & ] ( ColumnDescription & column ) { column . comment = * comment ; } ) ;
2018-10-14 15:30:06 +00:00
}
2021-09-20 11:06:19 +00:00
else if ( type = = COMMENT_TABLE )
{
metadata . comment = * comment ;
}
2019-02-05 14:50:25 +00:00
else if ( type = = ADD_INDEX )
{
if ( std : : any_of (
2020-06-01 12:11:23 +00:00
metadata . secondary_indices . cbegin ( ) ,
metadata . secondary_indices . cend ( ) ,
2020-05-28 12:37:05 +00:00
[ this ] ( const auto & index )
2019-02-05 14:50:25 +00:00
{
2020-05-28 12:37:05 +00:00
return index . name = = index_name ;
2019-02-05 14:50:25 +00:00
} ) )
{
if ( if_not_exists )
return ;
else
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Cannot add index {}: index with this name already exists " , index_name ) ;
2019-02-05 14:50:25 +00:00
}
2020-06-01 12:11:23 +00:00
auto insert_it = metadata . secondary_indices . end ( ) ;
2019-02-05 14:50:25 +00:00
2021-07-01 15:59:16 +00:00
/// insert the index in the beginning of the indices list
if ( first )
insert_it = metadata . secondary_indices . begin ( ) ;
2019-02-05 14:50:25 +00:00
if ( ! after_index_name . empty ( ) )
{
insert_it = std : : find_if (
2020-06-01 12:11:23 +00:00
metadata . secondary_indices . begin ( ) ,
metadata . secondary_indices . end ( ) ,
2020-05-28 12:37:05 +00:00
[ this ] ( const auto & index )
2019-02-05 14:50:25 +00:00
{
2020-05-28 12:37:05 +00:00
return index . name = = after_index_name ;
2019-02-05 14:50:25 +00:00
} ) ;
2020-06-01 12:11:23 +00:00
if ( insert_it = = metadata . secondary_indices . end ( ) )
2022-02-20 11:45:13 +00:00
{
auto hints = metadata . secondary_indices . getHints ( after_index_name ) ;
auto hints_string = ! hints . empty ( ) ? " , may be you meant: " + toString ( hints ) : " " ;
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Wrong index name. Cannot find index {} to insert after{} " ,
backQuote ( after_index_name ) , hints_string ) ;
2022-02-20 11:45:13 +00:00
}
2019-02-05 14:50:25 +00:00
+ + insert_it ;
}
2020-06-01 12:11:23 +00:00
metadata . secondary_indices . emplace ( insert_it , IndexDescription : : getIndexFromAST ( index_decl , metadata . columns , context ) ) ;
2019-02-05 14:50:25 +00:00
}
else if ( type = = DROP_INDEX )
{
2020-03-17 13:49:50 +00:00
if ( ! partition & & ! clear )
2019-06-03 21:08:52 +00:00
{
2020-03-17 13:49:50 +00:00
auto erase_it = std : : find_if (
2020-06-01 12:11:23 +00:00
metadata . secondary_indices . begin ( ) ,
metadata . secondary_indices . end ( ) ,
2020-05-28 12:37:05 +00:00
[ this ] ( const auto & index )
2020-03-17 13:49:50 +00:00
{
2020-05-28 12:37:05 +00:00
return index . name = = index_name ;
2020-03-17 13:49:50 +00:00
} ) ;
2019-02-05 14:50:25 +00:00
2020-06-01 12:11:23 +00:00
if ( erase_it = = metadata . secondary_indices . end ( ) )
2020-03-17 13:49:50 +00:00
{
if ( if_exists )
return ;
2022-02-20 11:45:13 +00:00
auto hints = metadata . secondary_indices . getHints ( index_name ) ;
auto hints_string = ! hints . empty ( ) ? " , may be you meant: " + toString ( hints ) : " " ;
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Wrong index name. Cannot find index {} to drop{} " ,
backQuote ( index_name ) , hints_string ) ;
2020-03-17 13:49:50 +00:00
}
2020-06-01 12:11:23 +00:00
metadata . secondary_indices . erase ( erase_it ) ;
2020-03-17 13:49:50 +00:00
}
2019-02-05 14:50:25 +00:00
}
2023-08-09 20:57:49 +00:00
else if ( type = = ADD_STATISTIC )
{
2023-09-08 00:27:17 +00:00
for ( const auto & statistic_column_name : statistic_columns )
2023-08-09 20:57:49 +00:00
{
2023-09-26 17:16:01 +00:00
if ( ! metadata . columns . has ( statistic_column_name ) )
2023-09-08 00:27:17 +00:00
{
2023-09-26 17:16:01 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_STATISTIC , " Cannot add statistic {} with type {}: this column is not found " , statistic_column_name , statistic_type ) ;
2023-09-08 00:27:17 +00:00
}
2023-10-29 23:39:16 +00:00
if ( ! if_exists & & metadata . columns . get ( statistic_column_name ) . stat )
2023-09-26 17:16:01 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_STATISTIC , " Cannot add statistic {} with type {}: statistic on this column with this type already exists " , statistic_column_name , statistic_type ) ;
2023-08-09 20:57:49 +00:00
}
2023-09-26 17:16:01 +00:00
auto stats = StatisticDescription : : getStatisticsFromAST ( statistic_decl , metadata . columns ) ;
for ( auto & & stat : stats )
{
metadata . columns . modify ( stat . column_name ,
[ & ] ( ColumnDescription & column ) { column . stat = std : : move ( stat ) ; } ) ;
}
2023-08-09 20:57:49 +00:00
}
else if ( type = = DROP_STATISTIC )
{
2023-09-26 17:16:01 +00:00
for ( const auto & stat_column_name : statistic_columns )
2023-08-09 20:57:49 +00:00
{
2023-09-26 17:16:01 +00:00
if ( ! metadata . columns . has ( stat_column_name ) | | ! metadata . columns . get ( stat_column_name ) . stat )
2023-08-09 20:57:49 +00:00
{
2023-09-26 17:16:01 +00:00
if ( if_exists )
return ;
throw Exception ( ErrorCodes : : ILLEGAL_STATISTIC , " Wrong statistic name. Cannot find statistic {} with type {} to drop " , backQuote ( stat_column_name ) , statistic_type ) ;
}
if ( ! partition & & ! clear )
{
metadata . columns . modify ( stat_column_name ,
[ & ] ( ColumnDescription & column ) { column . stat = std : : nullopt ; } ) ;
2023-08-09 20:57:49 +00:00
}
}
}
2019-06-02 14:41:12 +00:00
else if ( type = = ADD_CONSTRAINT )
{
2021-04-26 14:19:18 +00:00
auto constraints = metadata . constraints . getConstraints ( ) ;
2019-06-02 14:41:12 +00:00
if ( std : : any_of (
2021-04-26 14:19:18 +00:00
constraints . cbegin ( ) ,
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 ;
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Cannot add constraint {}: constraint with this name already exists " ,
constraint_name ) ;
2019-06-02 14:41:12 +00:00
}
2022-10-18 09:40:12 +00:00
auto * insert_it = constraints . end ( ) ;
2021-11-10 17:57:59 +00:00
constraints . emplace ( insert_it , constraint_decl ) ;
metadata . constraints = ConstraintsDescription ( constraints ) ;
2019-06-02 14:41:12 +00:00
}
else if ( type = = DROP_CONSTRAINT )
{
2021-04-26 14:19:18 +00:00
auto constraints = metadata . constraints . getConstraints ( ) ;
2022-10-18 09:40:12 +00:00
auto * erase_it = std : : find_if (
constraints . begin ( ) ,
constraints . end ( ) ,
[ this ] ( const ASTPtr & constraint_ast ) { return constraint_ast - > as < ASTConstraintDeclaration & > ( ) . name = = constraint_name ; } ) ;
2019-06-02 14:41:12 +00:00
2021-04-26 14:19:18 +00:00
if ( erase_it = = constraints . end ( ) )
2019-06-02 15:08:28 +00:00
{
2019-06-02 14:41:12 +00:00
if ( if_exists )
return ;
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Wrong constraint name. Cannot find constraint `{}` to drop " ,
constraint_name ) ;
2019-06-02 14:41:12 +00:00
}
2021-04-26 14:19:18 +00:00
constraints . erase ( erase_it ) ;
2021-11-10 17:57:59 +00:00
metadata . constraints = ConstraintsDescription ( constraints ) ;
2019-06-02 14:41:12 +00:00
}
2021-02-10 14:12:49 +00:00
else if ( type = = ADD_PROJECTION )
{
auto projection = ProjectionDescription : : getProjectionFromAST ( projection_decl , metadata . columns , context ) ;
metadata . projections . add ( std : : move ( projection ) , after_projection_name , first , if_not_exists ) ;
}
else if ( type = = DROP_PROJECTION )
{
if ( ! partition & & ! clear )
2021-05-28 13:27:36 +00:00
metadata . projections . remove ( projection_name , if_exists ) ;
2021-02-10 14:12:49 +00:00
}
2019-04-15 09:30:45 +00:00
else if ( type = = MODIFY_TTL )
{
2023-11-23 15:05:15 +00:00
metadata . table_ttl = TTLTableDescription : : getTTLForTableFromAST ( ttl , metadata . columns , context , metadata . primary_key , context - > getSettingsRef ( ) . allow_suspicious_ttl_expressions ) ;
2019-04-15 09:30:45 +00:00
}
2020-09-20 13:27:33 +00:00
else if ( type = = REMOVE_TTL )
{
metadata . table_ttl = TTLTableDescription { } ;
}
2020-01-29 17:44:16 +00:00
else if ( type = = MODIFY_QUERY )
{
2020-06-05 17:29:40 +00:00
metadata . select = SelectQueryDescription : : getSelectQueryFromASTForMatView ( select , context ) ;
2023-11-28 14:13:12 +00:00
Block as_select_sample ;
if ( context - > getSettingsRef ( ) . allow_experimental_analyzer )
{
as_select_sample = InterpreterSelectQueryAnalyzer : : getSampleBlock ( select - > clone ( ) , context ) ;
}
else
{
as_select_sample = InterpreterSelectWithUnionQuery : : getSampleBlock ( select - > clone ( ) ,
context ,
false /* is_subquery */ ,
false ) ;
}
metadata . columns = ColumnsDescription ( as_select_sample . getNamesAndTypesList ( ) ) ;
2020-01-29 17:44:16 +00:00
}
2019-07-24 12:56:39 +00:00
else if ( type = = MODIFY_SETTING )
{
2020-06-05 17:29:40 +00:00
auto & settings_from_storage = metadata . settings_changes - > 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
}
2020-12-02 21:18:25 +00:00
else if ( type = = RESET_SETTING )
{
auto & settings_from_storage = metadata . settings_changes - > as < ASTSetQuery & > ( ) . changes ;
for ( const auto & setting_name : settings_resets )
{
auto finder = [ & setting_name ] ( const SettingChange & c ) { return c . name = = setting_name ; } ;
auto it = std : : find_if ( settings_from_storage . begin ( ) , settings_from_storage . end ( ) , finder ) ;
if ( it ! = settings_from_storage . end ( ) )
settings_from_storage . erase ( it ) ;
/// Intentionally ignore if there is no such setting name
}
}
2020-03-24 17:05:38 +00:00
else if ( type = = RENAME_COLUMN )
{
metadata . columns . rename ( column_name , rename_to ) ;
2020-04-02 16:11:10 +00:00
RenameColumnData rename_data { column_name , rename_to } ;
RenameColumnVisitor rename_visitor ( rename_data ) ;
2020-04-22 06:22:14 +00:00
for ( const auto & column : metadata . columns )
2020-04-02 16:11:10 +00:00
{
2020-04-02 18:33:17 +00:00
metadata . columns . modify ( column . name , [ & ] ( ColumnDescription & column_to_modify )
{
2020-04-02 16:11:10 +00:00
if ( column_to_modify . default_desc . expression )
rename_visitor . visit ( column_to_modify . default_desc . expression ) ;
if ( column_to_modify . ttl )
rename_visitor . visit ( column_to_modify . ttl ) ;
2023-10-03 22:58:26 +00:00
if ( column_to_modify . name = = column_name & & column_to_modify . stat )
column_to_modify . stat - > column_name = rename_to ;
2020-04-02 16:11:10 +00:00
} ) ;
}
2020-06-05 17:29:40 +00:00
if ( metadata . table_ttl . definition_ast )
rename_visitor . visit ( metadata . table_ttl . definition_ast ) ;
2021-04-26 14:19:18 +00:00
auto constraints_data = metadata . constraints . getConstraints ( ) ;
for ( auto & constraint : constraints_data )
2020-05-12 11:26:44 +00:00
rename_visitor . visit ( constraint ) ;
2021-11-10 17:57:59 +00:00
metadata . constraints = ConstraintsDescription ( constraints_data ) ;
2020-07-09 14:14:44 +00:00
if ( metadata . isSortingKeyDefined ( ) )
rename_visitor . visit ( metadata . sorting_key . definition_ast ) ;
if ( metadata . isPrimaryKeyDefined ( ) )
rename_visitor . visit ( metadata . primary_key . definition_ast ) ;
if ( metadata . isSamplingKeyDefined ( ) )
rename_visitor . visit ( metadata . sampling_key . definition_ast ) ;
if ( metadata . isPartitionKeyDefined ( ) )
rename_visitor . visit ( metadata . partition_key . definition_ast ) ;
2020-07-09 14:30:38 +00:00
for ( auto & index : metadata . secondary_indices )
rename_visitor . visit ( index . definition_ast ) ;
2020-03-24 17:05:38 +00:00
}
2016-01-11 21:46:36 +00:00
else
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : LOGICAL_ERROR , " Wrong parameter type in ALTER query " ) ;
2016-01-11 21:46:36 +00:00
}
2014-10-21 12:11:20 +00:00
2020-01-13 16:39:20 +00:00
namespace
{
/// If true, then in order to ALTER the type of the column from the type from to the type to
/// we don't need to rewrite the data, we only need to update metadata and columns.txt in part directories.
/// The function works for Arrays and Nullables of the same structure.
bool isMetadataOnlyConversion ( const IDataType * from , const IDataType * to )
{
2022-04-03 12:03:34 +00:00
auto is_compatible_enum_types_conversion = [ ] ( const IDataType * from_type , const IDataType * to_type )
2020-07-21 14:05:30 +00:00
{
2022-04-03 12:03:34 +00:00
if ( const auto * from_enum8 = typeid_cast < const DataTypeEnum8 * > ( from_type ) )
{
if ( const auto * to_enum8 = typeid_cast < const DataTypeEnum8 * > ( to_type ) )
return to_enum8 - > contains ( * from_enum8 ) ;
}
2020-07-21 14:05:30 +00:00
2022-04-03 12:03:34 +00:00
if ( const auto * from_enum16 = typeid_cast < const DataTypeEnum16 * > ( from_type ) )
{
if ( const auto * to_enum16 = typeid_cast < const DataTypeEnum16 * > ( to_type ) )
return to_enum16 - > contains ( * from_enum16 ) ;
}
return false ;
} ;
2020-07-21 14:05:30 +00:00
2022-04-04 17:41:54 +00:00
static const std : : unordered_multimap < std : : type_index , const std : : type_info & > allowed_conversions =
2020-01-13 16:39:20 +00:00
{
{ typeid ( DataTypeEnum8 ) , typeid ( DataTypeInt8 ) } ,
{ typeid ( DataTypeEnum16 ) , typeid ( DataTypeInt16 ) } ,
{ typeid ( DataTypeDateTime ) , typeid ( DataTypeUInt32 ) } ,
{ typeid ( DataTypeUInt32 ) , typeid ( DataTypeDateTime ) } ,
{ typeid ( DataTypeDate ) , typeid ( DataTypeUInt16 ) } ,
{ typeid ( DataTypeUInt16 ) , typeid ( DataTypeDate ) } ,
} ;
2023-02-21 15:13:29 +00:00
/// Unwrap some nested and check for valid conversions
2020-01-13 16:39:20 +00:00
while ( true )
{
2022-04-03 12:03:34 +00:00
/// types are equal, obviously pure metadata alter
2021-08-17 13:14:13 +00:00
if ( from - > equals ( * to ) )
return true ;
2022-04-03 12:03:34 +00:00
/// We just adding something to enum, nothing changed on disk
if ( is_compatible_enum_types_conversion ( from , to ) )
return true ;
/// Types changed, but representation on disk didn't
2022-04-04 17:41:54 +00:00
auto it_range = allowed_conversions . equal_range ( typeid ( * from ) ) ;
2020-01-13 16:39:20 +00:00
for ( auto it = it_range . first ; it ! = it_range . second ; + + it )
{
if ( it - > second = = typeid ( * to ) )
return true ;
}
const auto * arr_from = typeid_cast < const DataTypeArray * > ( from ) ;
const auto * arr_to = typeid_cast < const DataTypeArray * > ( to ) ;
if ( arr_from & & arr_to )
{
from = arr_from - > getNestedType ( ) . get ( ) ;
to = arr_to - > getNestedType ( ) . get ( ) ;
continue ;
}
const auto * nullable_from = typeid_cast < const DataTypeNullable * > ( from ) ;
const auto * nullable_to = typeid_cast < const DataTypeNullable * > ( to ) ;
2023-02-21 15:13:29 +00:00
if ( nullable_from & & nullable_to )
2020-01-13 16:39:20 +00:00
{
2023-02-21 15:13:29 +00:00
from = nullable_from - > getNestedType ( ) . get ( ) ;
2020-01-13 16:39:20 +00:00
to = nullable_to - > getNestedType ( ) . get ( ) ;
continue ;
}
return false ;
}
}
}
2020-07-21 14:05:30 +00:00
bool AlterCommand : : isSettingsAlter ( ) const
{
2020-12-02 21:18:25 +00:00
return type = = MODIFY_SETTING | | type = = RESET_SETTING ;
2020-07-21 14:05:30 +00:00
}
2020-01-13 16:39:20 +00:00
bool AlterCommand : : isRequireMutationStage ( const StorageInMemoryMetadata & metadata ) const
{
2020-01-15 13:00:08 +00:00
if ( ignore )
return false ;
2020-09-20 13:27:33 +00:00
/// We remove properties on metadata level
2021-10-14 13:44:28 +00:00
if ( isRemovingProperty ( ) | | type = = REMOVE_TTL | | type = = REMOVE_SAMPLE_BY )
2020-09-20 13:27:33 +00:00
return false ;
2023-09-26 17:16:01 +00:00
if ( type = = DROP_INDEX | | type = = DROP_PROJECTION | | type = = RENAME_COLUMN | | type = = DROP_STATISTIC )
2020-01-15 13:00:08 +00:00
return true ;
2022-02-21 08:54:52 +00:00
/// Drop alias is metadata alter, in other case mutation is required.
2022-02-21 08:46:16 +00:00
if ( type = = DROP_COLUMN )
2022-07-17 18:41:17 +00:00
return metadata . columns . hasColumnOrNested ( GetColumnsOptions : : AllPhysical , column_name ) | |
2023-09-20 09:31:12 +00:00
column_name = = LightweightDeleteDescription : : FILTER_COLUMN . name | | column_name = = BlockNumberColumn : : name ;
2022-02-21 08:46:16 +00:00
2020-01-13 16:39:20 +00:00
if ( type ! = MODIFY_COLUMN | | data_type = = nullptr )
return false ;
for ( const auto & column : metadata . columns . getAllPhysical ( ) )
{
2020-01-15 13:00:08 +00:00
if ( column . name = = column_name & & ! isMetadataOnlyConversion ( column . type . get ( ) , data_type . get ( ) ) )
2020-01-13 16:39:20 +00:00
return true ;
}
return false ;
}
2019-12-27 14:36:59 +00:00
bool AlterCommand : : isCommentAlter ( ) const
{
2021-09-20 11:06:19 +00:00
if ( type = = COMMENT_COLUMN | | type = = COMMENT_TABLE )
2019-12-27 14:36:59 +00:00
{
return true ;
}
else if ( type = = MODIFY_COLUMN )
{
return comment . has_value ( )
& & codec = = nullptr
& & data_type = = nullptr
& & default_expression = = nullptr
& & ttl = = nullptr ;
}
return false ;
}
2020-05-19 01:53:01 +00:00
bool AlterCommand : : isTTLAlter ( const StorageInMemoryMetadata & metadata ) const
{
if ( type = = MODIFY_TTL )
2022-04-05 07:57:39 +00:00
{
if ( ! metadata . table_ttl . definition_ast )
return true ;
/// If TTL had not been changed, do not require mutations
2022-04-05 10:39:05 +00:00
return queryToString ( metadata . table_ttl . definition_ast ) ! = queryToString ( ttl ) ;
2022-04-05 07:57:39 +00:00
}
2020-05-19 01:53:01 +00:00
if ( ! ttl | | type ! = MODIFY_COLUMN )
return false ;
2022-04-05 07:57:39 +00:00
bool column_ttl_changed = true ;
2020-05-19 01:53:01 +00:00
for ( const auto & [ name , ttl_ast ] : metadata . columns . getColumnTTLs ( ) )
{
if ( name = = column_name & & queryToString ( * ttl ) = = queryToString ( * ttl_ast ) )
{
2022-04-05 07:57:39 +00:00
column_ttl_changed = false ;
2020-05-19 01:53:01 +00:00
break ;
}
}
2022-04-05 07:57:39 +00:00
return column_ttl_changed ;
2020-05-19 01:53:01 +00:00
}
2020-09-20 13:27:33 +00:00
bool AlterCommand : : isRemovingProperty ( ) const
{
return to_remove ! = RemoveProperty : : NO_PROPERTY ;
}
2023-10-10 17:59:48 +00:00
bool AlterCommand : : isDropSomething ( ) const
{
2023-10-11 15:42:44 +00:00
return type = = Type : : DROP_COLUMN | | type = = Type : : DROP_INDEX
| | type = = Type : : DROP_CONSTRAINT | | type = = Type : : DROP_PROJECTION ;
2023-10-10 17:59:48 +00:00
}
2021-04-10 23:33:54 +00:00
std : : optional < MutationCommand > AlterCommand : : tryConvertToMutationCommand ( StorageInMemoryMetadata & metadata , ContextPtr context ) const
2020-01-13 16:39:20 +00:00
{
if ( ! isRequireMutationStage ( metadata ) )
return { } ;
MutationCommand result ;
2020-01-17 13:54:22 +00:00
if ( type = = MODIFY_COLUMN )
{
result . type = MutationCommand : : Type : : READ_COLUMN ;
result . column_name = column_name ;
result . data_type = data_type ;
result . predicate = nullptr ;
}
else if ( type = = DROP_COLUMN )
{
result . type = MutationCommand : : Type : : DROP_COLUMN ;
result . column_name = column_name ;
2020-03-17 13:49:50 +00:00
if ( clear )
result . clear = true ;
if ( partition )
result . partition = partition ;
2020-01-17 13:54:22 +00:00
result . predicate = nullptr ;
}
else if ( type = = DROP_INDEX )
{
result . type = MutationCommand : : Type : : DROP_INDEX ;
2020-03-17 13:49:50 +00:00
result . column_name = index_name ;
if ( clear )
result . clear = true ;
if ( partition )
result . partition = partition ;
2020-01-17 13:54:22 +00:00
result . predicate = nullptr ;
}
2023-08-09 20:57:49 +00:00
else if ( type = = DROP_STATISTIC )
{
2023-09-04 13:51:00 +00:00
result . type = MutationCommand : : Type : : DROP_STATISTIC ;
2023-09-08 00:27:17 +00:00
result . statistic_columns = statistic_columns ;
2023-08-09 20:57:49 +00:00
2023-09-04 13:51:00 +00:00
if ( clear )
result . clear = true ;
if ( partition )
result . partition = partition ;
result . predicate = nullptr ;
2020-01-17 13:54:22 +00:00
}
2021-02-10 14:12:49 +00:00
else if ( type = = DROP_PROJECTION )
{
result . type = MutationCommand : : Type : : DROP_PROJECTION ;
result . column_name = projection_name ;
if ( clear )
result . clear = true ;
if ( partition )
result . partition = partition ;
result . predicate = nullptr ;
}
2020-03-30 12:51:05 +00:00
else if ( type = = RENAME_COLUMN )
{
result . type = MutationCommand : : Type : : RENAME_COLUMN ;
result . column_name = column_name ;
result . rename_to = rename_to ;
}
2020-01-17 13:54:22 +00:00
2020-01-15 13:00:08 +00:00
result . ast = ast - > clone ( ) ;
2020-05-28 12:37:05 +00:00
apply ( metadata , context ) ;
2020-01-13 16:39:20 +00:00
return result ;
}
2023-01-25 14:49:29 +00:00
bool AlterCommands : : hasInvertedIndex ( const StorageInMemoryMetadata & metadata )
2022-09-28 14:28:28 +00:00
{
for ( const auto & index : metadata . secondary_indices )
{
2023-01-20 09:32:36 +00:00
if ( index . type = = INVERTED_INDEX_NAME )
2022-09-28 14:28:28 +00:00
return true ;
}
return false ;
}
2023-01-20 09:32:36 +00:00
2021-04-10 23:33:54 +00:00
void AlterCommands : : apply ( StorageInMemoryMetadata & metadata , ContextPtr context ) const
2016-01-11 21:46:36 +00:00
{
2019-12-26 18:17:05 +00:00
if ( ! prepared )
2023-01-23 21:13:58 +00:00
throw DB : : Exception ( ErrorCodes : : LOGICAL_ERROR , " Alter commands is not prepared. Cannot apply. It's a bug " ) ;
2017-04-01 07:20:54 +00:00
2019-12-26 18:17:05 +00:00
auto metadata_copy = metadata ;
2020-12-16 07:26:18 +00:00
2016-01-11 21:46:36 +00:00
for ( const AlterCommand & command : * this )
2018-12-21 14:53:00 +00:00
if ( ! command . ignore )
2020-05-28 12:37:05 +00:00
command . apply ( metadata_copy , context ) ;
2019-12-26 18:17:05 +00:00
2020-06-15 08:12:01 +00:00
/// Changes in columns may lead to changes in keys expression.
2020-07-09 14:14:44 +00:00
metadata_copy . sorting_key . recalculateWithNewAST ( metadata_copy . sorting_key . definition_ast , metadata_copy . columns , context ) ;
2020-06-10 09:09:51 +00:00
if ( metadata_copy . primary_key . definition_ast ! = nullptr )
{
2020-07-09 14:14:44 +00:00
metadata_copy . primary_key . recalculateWithNewAST ( metadata_copy . primary_key . definition_ast , metadata_copy . columns , context ) ;
2020-06-10 09:09:51 +00:00
}
else
{
2020-06-10 11:16:31 +00:00
metadata_copy . primary_key = KeyDescription : : getKeyFromAST ( metadata_copy . sorting_key . definition_ast , metadata_copy . columns , context ) ;
2020-06-10 09:09:51 +00:00
metadata_copy . primary_key . definition_ast = nullptr ;
}
2020-06-25 23:21:04 +00:00
/// And in partition key expression
if ( metadata_copy . partition_key . definition_ast ! = nullptr )
2023-09-23 09:50:12 +00:00
{
2020-07-09 14:14:44 +00:00
metadata_copy . partition_key . recalculateWithNewAST ( metadata_copy . partition_key . definition_ast , metadata_copy . columns , context ) ;
2020-06-25 23:21:04 +00:00
2023-09-23 09:50:12 +00:00
/// If partition key expression is changed, we also need to rebuild minmax_count_projection
if ( ! blocksHaveEqualStructure ( metadata_copy . partition_key . sample_block , metadata . partition_key . sample_block ) )
{
auto minmax_columns = metadata_copy . getColumnsRequiredForPartitionKey ( ) ;
auto partition_key = metadata_copy . partition_key . expression_list_ast - > clone ( ) ;
FunctionNameNormalizer ( ) . visit ( partition_key . get ( ) ) ;
auto primary_key_asts = metadata_copy . primary_key . expression_list_ast - > children ;
metadata_copy . minmax_count_projection . emplace ( ProjectionDescription : : getMinMaxCountProjection (
metadata_copy . columns , partition_key , minmax_columns , primary_key_asts , context ) ) ;
}
}
2020-08-27 13:10:10 +00:00
// /// And in sample key expression
if ( metadata_copy . sampling_key . definition_ast ! = nullptr )
metadata_copy . sampling_key . recalculateWithNewAST ( metadata_copy . sampling_key . definition_ast , metadata_copy . columns , context ) ;
2020-06-19 10:53:20 +00:00
/// Changes in columns may lead to changes in secondary indices
for ( auto & index : metadata_copy . secondary_indices )
2021-02-10 14:12:49 +00:00
{
try
{
index = IndexDescription : : getIndexFromAST ( index . definition_ast , metadata_copy . columns , context ) ;
}
catch ( Exception & exception )
{
exception . addMessage ( " Cannot apply mutation because it breaks skip index " + index . name ) ;
throw ;
}
}
/// Changes in columns may lead to changes in projections
ProjectionsDescription new_projections ;
for ( const auto & projection : metadata_copy . projections )
{
try
{
2023-11-18 07:45:10 +00:00
/// Check if we can still build projection from new metadata.
auto new_projection = ProjectionDescription : : getProjectionFromAST ( projection . definition_ast , metadata_copy . columns , context ) ;
/// Check if new metadata has the same keys as the old one.
if ( ! blocksHaveEqualStructure ( projection . sample_block_for_keys , new_projection . sample_block_for_keys ) )
throw Exception ( ErrorCodes : : ALTER_OF_COLUMN_IS_FORBIDDEN , " Cannot ALTER column " ) ;
/// Check if new metadata is convertible from old metadata for projection.
Block old_projection_block = projection . sample_block ;
performRequiredConversions ( old_projection_block , new_projection . sample_block . getNamesAndTypesList ( ) , context ) ;
new_projections . add ( std : : move ( new_projection ) ) ;
2021-02-10 14:12:49 +00:00
}
catch ( Exception & exception )
{
exception . addMessage ( " Cannot apply mutation because it breaks projection " + projection . name ) ;
throw ;
}
}
metadata_copy . projections = std : : move ( new_projections ) ;
2020-06-19 10:53:20 +00:00
2020-06-15 08:12:01 +00:00
/// Changes in columns may lead to changes in TTL expressions.
2020-06-10 09:09:51 +00:00
auto column_ttl_asts = metadata_copy . columns . getColumnTTLs ( ) ;
2020-12-16 07:26:18 +00:00
metadata_copy . column_ttls_by_name . clear ( ) ;
2020-06-10 09:09:51 +00:00
for ( const auto & [ name , ast ] : column_ttl_asts )
{
2023-11-23 15:05:15 +00:00
auto new_ttl_entry = TTLDescription : : getTTLFromAST ( ast , metadata_copy . columns , context , metadata_copy . primary_key , context - > getSettingsRef ( ) . allow_suspicious_ttl_expressions ) ;
2020-06-10 09:09:51 +00:00
metadata_copy . column_ttls_by_name [ name ] = new_ttl_entry ;
}
if ( metadata_copy . table_ttl . definition_ast ! = nullptr )
2020-12-16 07:26:18 +00:00
metadata_copy . table_ttl = TTLTableDescription : : getTTLForTableFromAST (
2023-11-23 15:05:15 +00:00
metadata_copy . table_ttl . definition_ast , metadata_copy . columns , context , metadata_copy . primary_key , context - > getSettingsRef ( ) . allow_suspicious_ttl_expressions ) ;
2020-06-10 09:09:51 +00:00
2019-12-26 18:17:05 +00:00
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-20 10:04:15 +00:00
void AlterCommands : : prepare ( const StorageInMemoryMetadata & metadata )
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 )
2016-01-11 21:46:36 +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 )
2014-10-21 12:11:20 +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-09-20 13:27:33 +00:00
if ( has_column )
2016-01-11 21:46:36 +00:00
{
2020-02-19 12:52:27 +00:00
auto column_from_table = columns . get ( command . column_name ) ;
2020-09-20 13:27:33 +00:00
if ( command . data_type & & ! command . default_expression & & column_from_table . default_desc . expression )
2014-10-21 12:11:20 +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 ;
2014-10-21 12:11:20 +00:00
}
2020-09-20 13:27:33 +00:00
2014-10-21 12:11:20 +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
2020-04-03 16:45:49 +00:00
| | command . type = = AlterCommand : : COMMENT_COLUMN
| | command . type = = AlterCommand : : RENAME_COLUMN )
2014-10-21 12:11:20 +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 ;
2016-01-11 21:46:36 +00:00
}
2014-10-21 12:11:20 +00:00
}
2022-11-23 09:28:08 +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
2021-08-27 06:30:21 +00:00
2022-01-11 01:58:53 +00:00
void AlterCommands : : validate ( const StoragePtr & table , ContextPtr context ) const
2018-11-28 12:06:52 +00:00
{
2022-01-11 01:58:53 +00:00
const StorageInMemoryMetadata & metadata = table - > getInMemoryMetadata ( ) ;
2020-02-19 14:39:01 +00:00
auto all_columns = metadata . columns ;
2020-03-03 10:04:05 +00:00
/// Default expression for all added/modified columns
2020-03-03 10:02:43 +00:00
ASTPtr default_expr_list = std : : make_shared < ASTExpressionList > ( ) ;
2020-05-19 09:54:56 +00:00
NameSet modified_columns , renamed_columns ;
2019-12-26 18:17:05 +00:00
for ( size_t i = 0 ; i < size ( ) ; + + i )
{
2020-04-22 06:22:14 +00:00
const auto & command = ( * this ) [ i ] ;
2020-02-19 12:52:27 +00:00
2022-01-11 01:58:53 +00:00
if ( command . ttl & & ! table - > supportsTTL ( ) )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Engine {} doesn't support TTL clause " , table - > getName ( ) ) ;
2022-01-11 01:58:53 +00:00
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-05-19 09:54:56 +00:00
if ( all_columns . has ( column_name ) | | all_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 )
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : DUPLICATE_COLUMN ,
" Cannot add column {}: column with this name already exists " ,
backQuote ( column_name ) ) ;
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 )
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS ,
" Data type have to be specified for column {} to add " , backQuote ( column_name ) ) ;
2020-02-19 12:52:27 +00:00
2023-11-07 11:01:52 +00:00
/// FIXME: Adding a new column of type Object(JSON) is broken.
/// Looks like there is something around default expression for this column (method `getDefault` is not implemented for the data type Object).
/// But after ALTER TABLE ADD COLUMN we need to fill existing rows with something (exactly the default value).
/// So we don't allow to do it for now.
if ( command . data_type - > hasDynamicSubcolumns ( ) )
throw Exception ( ErrorCodes : : SUPPORT_IS_DISABLED , " Adding a new column of a type which has dynamic subcolumns to an existing table is not allowed. It has known bugs " ) ;
2022-09-26 07:14:58 +00:00
if ( column_name = = LightweightDeleteDescription : : FILTER_COLUMN . name & & std : : dynamic_pointer_cast < MergeTreeData > ( table ) )
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Cannot add column {}: "
" this column name is reserved for lightweight delete feature " , backQuote ( column_name ) ) ;
2022-09-26 07:14:58 +00:00
2023-09-20 09:31:12 +00:00
if ( column_name = = BlockNumberColumn : : name & & std : : dynamic_pointer_cast < MergeTreeData > ( table ) )
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Cannot add column {}: "
" this column name is reserved for _block_number persisting feature " , backQuote ( column_name ) ) ;
2020-08-28 17:40:45 +00:00
if ( command . codec )
2023-06-09 12:38:38 +00:00
CompressionCodecFactory : : instance ( ) . validateCodecAndGetPreprocessedAST ( command . codec , command . data_type , ! context - > getSettingsRef ( ) . allow_suspicious_codecs , context - > getSettingsRef ( ) . allow_experimental_codecs , context - > getSettingsRef ( ) . enable_deflate_qpl_codec ) ;
2020-08-28 17:40:45 +00:00
2020-04-27 13:55:30 +00:00
all_columns . add ( ColumnDescription ( column_name , command . data_type ) ) ;
2020-02-19 12:52:27 +00:00
}
else if ( command . type = = AlterCommand : : MODIFY_COLUMN )
{
2020-05-19 09:54:56 +00:00
if ( ! all_columns . has ( column_name ) )
2020-02-19 14:39:01 +00:00
{
2020-02-19 12:52:27 +00:00
if ( ! command . if_exists )
2022-04-01 13:12:54 +00:00
{
2023-08-14 16:57:40 +00:00
throw Exception ( ErrorCodes : : NOT_FOUND_COLUMN_IN_BLOCK , " Wrong column. Cannot find column {} to modify{} " ,
backQuote ( column_name ) , all_columns . getHintsMessage ( column_name ) ) ;
2022-04-01 13:12:54 +00:00
}
2020-02-19 14:39:01 +00:00
else
continue ;
}
2020-05-19 09:54:56 +00:00
2022-04-18 10:18:43 +00:00
if ( renamed_columns . contains ( column_name ) )
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : NOT_IMPLEMENTED , " Cannot rename and modify the same column {} "
" in a single ALTER query " , backQuote ( column_name ) ) ;
2020-08-28 17:40:45 +00:00
if ( command . codec )
2023-05-01 16:25:08 +00:00
{
2023-05-01 20:59:38 +00:00
if ( all_columns . hasAlias ( column_name ) )
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Cannot specify codec for column type ALIAS " ) ;
2023-06-09 12:38:38 +00:00
CompressionCodecFactory : : instance ( ) . validateCodecAndGetPreprocessedAST ( command . codec , command . data_type , ! context - > getSettingsRef ( ) . allow_suspicious_codecs , context - > getSettingsRef ( ) . allow_experimental_codecs , context - > getSettingsRef ( ) . enable_deflate_qpl_codec ) ;
2023-05-01 16:25:08 +00:00
}
2020-09-20 13:27:33 +00:00
auto column_default = all_columns . getDefault ( column_name ) ;
if ( column_default )
{
if ( command . to_remove = = AlterCommand : : RemoveProperty : : DEFAULT & & column_default - > kind ! = ColumnDefaultKind : : Default )
{
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
" Cannot remove DEFAULT from column {}, because column default type is {}. Use REMOVE {} to delete it " ,
backQuote ( column_name ) , toString ( column_default - > kind ) , toString ( column_default - > kind ) ) ;
}
if ( command . to_remove = = AlterCommand : : RemoveProperty : : MATERIALIZED & & column_default - > kind ! = ColumnDefaultKind : : Materialized )
{
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
" Cannot remove MATERIALIZED from column {}, because column default type is {}. Use REMOVE {} to delete it " ,
backQuote ( column_name ) , toString ( column_default - > kind ) , toString ( column_default - > kind ) ) ;
}
if ( command . to_remove = = AlterCommand : : RemoveProperty : : ALIAS & & column_default - > kind ! = ColumnDefaultKind : : Alias )
{
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
" Cannot remove ALIAS from column {}, because column default type is {}. Use REMOVE {} to delete it " ,
backQuote ( column_name ) , toString ( column_default - > kind ) , toString ( column_default - > kind ) ) ;
}
}
2023-11-07 11:01:52 +00:00
/// FIXME: Modifying the column to/from Object(JSON) is broken.
/// Looks like there is something around default expression for this column (method `getDefault` is not implemented for the data type Object).
/// But after ALTER TABLE MODIFY COLUMN we need to fill existing rows with something (exactly the default value) or calculate the common type for it.
/// So we don't allow to do it for now.
2023-05-05 15:50:43 +00:00
if ( command . data_type )
{
2023-11-09 07:07:41 +00:00
const GetColumnsOptions options ( GetColumnsOptions : : All ) ;
2023-05-05 18:37:49 +00:00
const auto old_data_type = all_columns . getColumn ( options , column_name ) . type ;
2023-05-05 15:50:43 +00:00
2023-11-07 11:01:52 +00:00
bool new_type_has_object = command . data_type - > hasDynamicSubcolumns ( ) ;
bool old_type_has_object = old_data_type - > hasDynamicSubcolumns ( ) ;
if ( new_type_has_object | | old_type_has_object )
2023-05-05 15:50:43 +00:00
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
2023-11-07 11:01:52 +00:00
" The change of data type {} of column {} to {} is not allowed. It has known bugs " ,
2023-05-05 18:37:49 +00:00
old_data_type - > getName ( ) , backQuote ( column_name ) , command . data_type - > getName ( ) ) ;
2023-05-05 15:50:43 +00:00
}
2020-09-20 13:27:33 +00:00
if ( command . isRemovingProperty ( ) )
{
if ( ! column_default & & command . to_remove = = AlterCommand : : RemoveProperty : : DEFAULT )
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
" Column {} doesn't have DEFAULT, cannot remove it " ,
backQuote ( column_name ) ) ;
if ( ! column_default & & command . to_remove = = AlterCommand : : RemoveProperty : : ALIAS )
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
" Column {} doesn't have ALIAS, cannot remove it " ,
backQuote ( column_name ) ) ;
if ( ! column_default & & command . to_remove = = AlterCommand : : RemoveProperty : : MATERIALIZED )
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
" Column {} doesn't have MATERIALIZED, cannot remove it " ,
backQuote ( column_name ) ) ;
2023-09-21 10:54:09 +00:00
const auto & column_from_table = all_columns . get ( column_name ) ;
2020-09-20 13:27:33 +00:00
if ( command . to_remove = = AlterCommand : : RemoveProperty : : TTL & & column_from_table . ttl = = nullptr )
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
" Column {} doesn't have TTL, cannot remove it " ,
backQuote ( column_name ) ) ;
if ( command . to_remove = = AlterCommand : : RemoveProperty : : CODEC & & column_from_table . codec = = nullptr )
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
" Column {} doesn't have TTL, cannot remove it " ,
backQuote ( column_name ) ) ;
if ( command . to_remove = = AlterCommand : : RemoveProperty : : COMMENT & & column_from_table . comment . empty ( ) )
throw Exception (
ErrorCodes : : BAD_ARGUMENTS ,
" Column {} doesn't have COMMENT, cannot remove it " ,
backQuote ( column_name ) ) ;
}
2020-08-28 17:40:45 +00:00
2020-05-19 09:54:56 +00:00
modified_columns . emplace ( column_name ) ;
2019-12-26 18:17:05 +00:00
}
else if ( command . type = = AlterCommand : : DROP_COLUMN )
{
2022-07-17 18:41:17 +00:00
if ( all_columns . has ( command . column_name ) | |
all_columns . hasNested ( command . column_name ) | |
2022-07-25 14:15:15 +00:00
( command . clear & & column_name = = LightweightDeleteDescription : : FILTER_COLUMN . name ) )
2019-12-26 18:17:05 +00:00
{
2020-07-10 05:54:35 +00:00
if ( ! command . clear ) /// CLEAR column is Ok even if there are dependencies.
2019-12-26 18:17:05 +00:00
{
2020-07-10 05:54:35 +00:00
/// Check if we are going to DROP a column that some other columns depend on.
for ( const ColumnDescription & column : all_columns )
2020-02-19 12:52:27 +00:00
{
2020-07-10 05:54:35 +00:00
const auto & default_expression = column . default_desc . expression ;
if ( default_expression )
{
ASTPtr query = default_expression - > clone ( ) ;
2020-07-22 17:13:05 +00:00
auto syntax_result = TreeRewriter ( context ) . analyze ( query , all_columns . getAll ( ) ) ;
2020-07-10 05:54:35 +00:00
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 ) )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Cannot drop column {}, because column {} depends on it " ,
backQuote ( command . column_name ) , backQuote ( column . name ) ) ;
2020-07-10 05:54:35 +00:00
}
2020-02-19 12:52:27 +00:00
}
2019-12-26 18:17:05 +00:00
}
2020-05-19 09:54:56 +00:00
all_columns . remove ( command . column_name ) ;
2019-12-26 18:17:05 +00:00
}
else if ( ! command . if_exists )
2022-04-01 13:12:54 +00:00
{
2023-01-25 20:16:42 +00:00
auto message = PreformattedMessage : : create (
" Wrong column name. Cannot find column {} to drop " , backQuote ( command . column_name ) ) ;
all_columns . appendHintsMessage ( message . text , command . column_name ) ;
throw Exception ( std : : move ( message ) , ErrorCodes : : NOT_FOUND_COLUMN_IN_BLOCK ) ;
2022-04-01 13:12:54 +00:00
}
2019-12-26 18:17:05 +00:00
}
else if ( command . type = = AlterCommand : : COMMENT_COLUMN )
{
2020-05-19 09:54:56 +00:00
if ( ! all_columns . has ( command . column_name ) )
2019-12-26 18:17:05 +00:00
{
if ( ! command . if_exists )
2022-04-01 13:12:54 +00:00
{
2023-01-25 20:16:42 +00:00
auto message = PreformattedMessage : : create (
" Wrong column name. Cannot find column {} to comment " , backQuote ( command . column_name ) ) ;
all_columns . appendHintsMessage ( message . text , command . column_name ) ;
throw Exception ( std : : move ( message ) , ErrorCodes : : NOT_FOUND_COLUMN_IN_BLOCK ) ;
2022-04-01 13:12:54 +00:00
}
2019-12-26 18:17:05 +00:00
}
}
2020-12-02 21:18:25 +00:00
else if ( command . type = = AlterCommand : : MODIFY_SETTING | | command . type = = AlterCommand : : RESET_SETTING )
2020-02-28 12:44:50 +00:00
{
2020-06-05 17:29:40 +00:00
if ( metadata . settings_changes = = nullptr )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Cannot alter settings, because table engine doesn't support settings changes " ) ;
2020-02-28 12:44:50 +00:00
}
2020-03-30 13:34:19 +00:00
else if ( command . type = = AlterCommand : : RENAME_COLUMN )
{
2020-05-13 17:43:30 +00:00
for ( size_t j = i + 1 ; j < size ( ) ; + + j )
{
auto next_command = ( * this ) [ j ] ;
if ( next_command . type = = AlterCommand : : RENAME_COLUMN )
{
if ( next_command . column_name = = command . rename_to )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : NOT_IMPLEMENTED , " Transitive renames in a single ALTER query are not allowed (don't make sense) " ) ;
2020-05-13 17:43:30 +00:00
else if ( next_command . column_name = = command . column_name )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Cannot rename column '{}' to two different names in a single ALTER query " ,
backQuote ( command . column_name ) ) ;
2020-05-13 17:43:30 +00:00
}
}
2020-03-31 16:18:18 +00:00
/// TODO Implement nested rename
2020-05-13 17:43:30 +00:00
if ( all_columns . hasNested ( command . column_name ) )
2020-03-31 16:18:18 +00:00
{
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : NOT_IMPLEMENTED , " Cannot rename whole Nested struct " ) ;
2020-03-31 16:18:18 +00:00
}
2020-05-13 17:43:30 +00:00
if ( ! all_columns . has ( command . column_name ) )
2020-03-30 13:34:19 +00:00
{
if ( ! command . if_exists )
2022-04-01 13:12:54 +00:00
{
2023-01-25 20:16:42 +00:00
auto message = PreformattedMessage : : create (
" Wrong column name. Cannot find column {} to rename " , backQuote ( command . column_name ) ) ;
all_columns . appendHintsMessage ( message . text , command . column_name ) ;
throw Exception ( std : : move ( message ) , ErrorCodes : : NOT_FOUND_COLUMN_IN_BLOCK ) ;
2022-04-01 13:12:54 +00:00
}
2020-05-13 17:43:30 +00:00
else
continue ;
2020-03-30 13:34:19 +00:00
}
2020-05-13 17:43:30 +00:00
if ( all_columns . has ( command . rename_to ) )
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : DUPLICATE_COLUMN , " Cannot rename to {}: "
" column with this name already exists " , backQuote ( command . rename_to ) ) ;
2020-03-30 13:34:19 +00:00
2022-09-26 07:14:58 +00:00
if ( command . rename_to = = LightweightDeleteDescription : : FILTER_COLUMN . name & & std : : dynamic_pointer_cast < MergeTreeData > ( table ) )
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Cannot rename to {}: "
" this column name is reserved for lightweight delete feature " , backQuote ( command . rename_to ) ) ;
2022-09-26 07:14:58 +00:00
2023-09-20 09:31:12 +00:00
if ( command . rename_to = = BlockNumberColumn : : name & & std : : dynamic_pointer_cast < MergeTreeData > ( table ) )
throw Exception ( ErrorCodes : : ILLEGAL_COLUMN , " Cannot rename to {}: "
" this column name is reserved for _block_number persisting feature " , backQuote ( command . rename_to ) ) ;
2022-04-18 10:18:43 +00:00
if ( modified_columns . contains ( column_name ) )
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : NOT_IMPLEMENTED , " Cannot rename and modify the same column {} "
" in a single ALTER query " , backQuote ( column_name ) ) ;
2020-03-30 13:34:19 +00:00
2020-03-31 16:18:18 +00:00
String from_nested_table_name = Nested : : extractTableName ( command . column_name ) ;
String to_nested_table_name = Nested : : extractTableName ( command . rename_to ) ;
bool from_nested = from_nested_table_name ! = command . column_name ;
bool to_nested = to_nested_table_name ! = command . rename_to ;
if ( from_nested & & to_nested )
{
if ( from_nested_table_name ! = to_nested_table_name )
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Cannot rename column from one nested name to another " ) ;
2020-03-31 16:18:18 +00:00
}
else if ( ! from_nested & & ! to_nested )
{
2020-05-13 17:43:30 +00:00
all_columns . rename ( command . column_name , command . rename_to ) ;
2020-05-19 09:54:56 +00:00
renamed_columns . emplace ( command . column_name ) ;
renamed_columns . emplace ( command . rename_to ) ;
2020-03-31 16:18:18 +00:00
}
else
{
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Cannot rename column from nested struct to normal column and vice versa " ) ;
2020-03-31 16:18:18 +00:00
}
2020-03-30 13:34:19 +00:00
}
2020-09-20 13:27:33 +00:00
else if ( command . type = = AlterCommand : : REMOVE_TTL & & ! metadata . hasAnyTableTTL ( ) )
{
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Table doesn't have any table TTL expression, cannot remove " ) ;
2020-09-20 13:27:33 +00:00
}
2021-10-14 13:44:28 +00:00
else if ( command . type = = AlterCommand : : REMOVE_SAMPLE_BY & & ! metadata . hasSamplingKey ( ) )
{
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Table doesn't have SAMPLE BY, cannot remove " ) ;
2021-10-14 13:44:28 +00:00
}
2020-02-19 12:52:27 +00:00
2022-09-02 08:54:48 +00:00
/// Collect default expressions for MODIFY and ADD commands
2020-03-03 10:02:43 +00:00
if ( command . type = = AlterCommand : : MODIFY_COLUMN | | command . type = = AlterCommand : : ADD_COLUMN )
{
if ( command . default_expression )
{
2020-10-12 11:02:35 +00:00
DataTypePtr data_type_ptr ;
/// If we modify default, but not type.
if ( ! command . data_type ) /// it's not ADD COLUMN, because we cannot add column without type
data_type_ptr = all_columns . get ( column_name ) . type ;
2020-03-03 10:02:43 +00:00
else
2020-10-12 11:02:35 +00:00
data_type_ptr = command . data_type ;
2020-02-19 12:52:27 +00:00
2020-10-12 11:02:35 +00:00
const auto & final_column_name = column_name ;
2020-11-02 18:37:23 +00:00
const auto tmp_column_name = final_column_name + " _tmp_alter " + toString ( randomSeed ( ) ) ;
2020-03-03 10:02:43 +00:00
2020-10-12 11:02:35 +00:00
default_expr_list - > children . emplace_back ( setAlias (
addTypeConversionToAST ( std : : make_shared < ASTIdentifier > ( tmp_column_name ) , data_type_ptr - > getName ( ) ) ,
final_column_name ) ) ;
2020-03-03 10:02:43 +00:00
2020-10-12 11:02:35 +00:00
default_expr_list - > children . emplace_back ( setAlias ( command . default_expression - > clone ( ) , tmp_column_name ) ) ;
2020-03-03 10:02:43 +00:00
} /// if we change data type for column with default
2020-05-19 09:54:56 +00:00
else if ( all_columns . has ( column_name ) & & command . data_type )
2020-03-03 10:02:43 +00:00
{
2020-05-19 09:54:56 +00:00
auto column_in_table = all_columns . get ( column_name ) ;
2020-03-03 10:02:43 +00:00
/// Column doesn't have a default, nothing to check
if ( ! column_in_table . default_desc . expression )
continue ;
const auto & final_column_name = column_name ;
2020-11-02 18:37:23 +00:00
const auto tmp_column_name = final_column_name + " _tmp_alter " + toString ( randomSeed ( ) ) ;
2020-03-03 10:02:43 +00:00
const auto data_type_ptr = command . data_type ;
default_expr_list - > children . emplace_back ( setAlias (
addTypeConversionToAST ( std : : make_shared < ASTIdentifier > ( tmp_column_name ) , data_type_ptr - > getName ( ) ) , final_column_name ) ) ;
default_expr_list - > children . emplace_back ( setAlias ( column_in_table . default_desc . expression - > clone ( ) , tmp_column_name ) ) ;
}
}
2020-02-19 12:52:27 +00:00
}
2020-03-03 10:02:43 +00:00
2020-07-14 08:19:39 +00:00
if ( all_columns . empty ( ) )
2023-01-17 16:39:07 +00:00
throw Exception ( ErrorCodes : : BAD_ARGUMENTS , " Cannot DROP or CLEAR all columns " ) ;
2020-07-13 17:27:52 +00:00
2020-03-03 10:02:43 +00:00
validateColumnsDefaultsAndGetSampleBlock ( default_expr_list , all_columns . getAll ( ) , context ) ;
2020-02-19 12:52:27 +00:00
}
2019-08-06 12:52:08 +00:00
2023-09-06 12:17:46 +00:00
bool AlterCommands : : hasNonReplicatedAlterCommand ( ) const
2021-07-30 16:34:18 +00:00
{
2023-09-06 12:17:46 +00:00
return std : : any_of ( begin ( ) , end ( ) , [ ] ( const AlterCommand & c ) { return c . isSettingsAlter ( ) | | c . isCommentAlter ( ) ; } ) ;
}
bool AlterCommands : : areNonReplicatedAlterCommands ( ) const
{
return std : : all_of ( begin ( ) , end ( ) , [ ] ( const AlterCommand & c ) { return c . isSettingsAlter ( ) | | c . isCommentAlter ( ) ; } ) ;
2021-07-30 16:34:18 +00:00
}
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 ( ) ; } ) ;
}
2020-01-13 16:39:20 +00:00
2020-05-19 01:53:01 +00:00
static MutationCommand createMaterializeTTLCommand ( )
{
MutationCommand command ;
auto ast = std : : make_shared < ASTAlterCommand > ( ) ;
ast - > type = ASTAlterCommand : : MATERIALIZE_TTL ;
command . type = MutationCommand : : MATERIALIZE_TTL ;
command . ast = std : : move ( ast ) ;
return command ;
}
2020-01-13 16:39:20 +00:00
2022-12-22 13:31:42 +00:00
MutationCommands AlterCommands : : getMutationCommands ( StorageInMemoryMetadata metadata , bool materialize_ttl , ContextPtr context , bool with_alters ) const
2020-01-13 16:39:20 +00:00
{
MutationCommands result ;
for ( const auto & alter_cmd : * this )
2022-12-22 13:31:42 +00:00
{
2020-05-28 12:37:05 +00:00
if ( auto mutation_cmd = alter_cmd . tryConvertToMutationCommand ( metadata , context ) ; mutation_cmd )
2022-12-22 13:31:42 +00:00
{
2020-01-13 16:39:20 +00:00
result . push_back ( * mutation_cmd ) ;
2022-12-22 13:31:42 +00:00
}
else if ( with_alters )
{
result . push_back ( MutationCommand { . ast = alter_cmd . ast - > clone ( ) , . type = MutationCommand : : Type : : ALTER_WITHOUT_MUTATION } ) ;
}
}
2020-05-19 01:53:01 +00:00
if ( materialize_ttl )
{
for ( const auto & alter_cmd : * this )
{
2020-09-11 17:07:00 +00:00
if ( alter_cmd . isTTLAlter ( metadata ) )
2020-05-19 01:53:01 +00:00
{
result . push_back ( createMaterializeTTLCommand ( ) ) ;
break ;
}
}
}
2020-01-13 16:39:20 +00:00
return result ;
}
2016-01-11 21:46:36 +00:00
}