Backport #70123 to 24.9: Check for Nullable(Nothing) type during ALTER TABLE MODIFY COLUMN/QUERY

This commit is contained in:
robot-clickhouse 2024-10-01 19:10:51 +00:00
parent 9a435e4c9e
commit e1d195a5ac
6 changed files with 23 additions and 2 deletions

View File

@ -35,6 +35,7 @@
#include <Parsers/queryToString.h>
#include <Storages/AlterCommands.h>
#include <Storages/IStorage.h>
#include <Storages/StorageFactory.h>
#include <Storages/MergeTree/MergeTreeData.h>
#include <Storages/MergeTree/MergeTreeSettings.h>
#include <Common/typeid_cast.h>
@ -1365,6 +1366,7 @@ void AlterCommands::validate(const StoragePtr & table, ContextPtr context) const
"Data type have to be specified for column {} to add", backQuote(column_name));
validateDataType(command.data_type, DataTypeValidationSettings(context->getSettingsRef()));
checkAllTypesAreAllowedInTable(NamesAndTypesList{{command.column_name, command.data_type}});
/// 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).
@ -1453,6 +1455,7 @@ void AlterCommands::validate(const StoragePtr & table, ContextPtr context) const
if (command.data_type)
{
validateDataType(command.data_type, DataTypeValidationSettings(context->getSettingsRef()));
checkAllTypesAreAllowedInTable(NamesAndTypesList{{command.column_name, command.data_type}});
const GetColumnsOptions options(GetColumnsOptions::All);
const auto old_data_type = all_columns.getColumn(options, column_name).type;

View File

@ -28,11 +28,11 @@ namespace ErrorCodes
/// Some types are only for intermediate values of expressions and cannot be used in tables.
static void checkAllTypesAreAllowedInTable(const NamesAndTypesList & names_and_types)
void checkAllTypesAreAllowedInTable(const NamesAndTypesList & names_and_types)
{
for (const auto & elem : names_and_types)
if (elem.type->cannotBeStoredInTables())
throw Exception(ErrorCodes::DATA_TYPE_CANNOT_BE_USED_IN_TABLES, "Data type {} cannot be used in tables", elem.type->getName());
throw Exception(ErrorCodes::DATA_TYPE_CANNOT_BE_USED_IN_TABLES, "Data type {} of column '{}' cannot be used in tables", elem.type->getName(), elem.name);
}

View File

@ -135,4 +135,6 @@ private:
Storages storages;
};
void checkAllTypesAreAllowedInTable(const NamesAndTypesList & names_and_types);
}

View File

@ -517,6 +517,10 @@ void StorageMaterializedView::alter(
/// We need to copy the target table's columns (after checkTargetTableHasQueryOutputColumns() they can be still different - e.g. the data types of those columns can differ).
new_metadata.columns = target_table_metadata->columns;
}
else
{
checkAllTypesAreAllowedInTable(new_metadata.getColumns().getAll());
}
DatabaseCatalog::instance().getDatabase(table_id.database_name)->alterTable(local_context, table_id, new_metadata);
setInMemoryMetadata(new_metadata);

View File

@ -0,0 +1,12 @@
drop table if exists src;
drop table if exists dst;
drop view if exists v;
create table src (x Nullable(Int32)) engine=Memory;
alter table src modify column x Nullable(Nothing); -- {serverError DATA_TYPE_CANNOT_BE_USED_IN_TABLES}
create table dst (x Nullable(Int32)) engine=Memory;
create materialized view v to dst as select x from src;
alter table v modify query select NULL as x from src; -- {serverError DATA_TYPE_CANNOT_BE_USED_IN_TABLES}
drop view v;
drop table dst;
drop table src;