Skip to content

Commit

Permalink
MDEV-22771 Instant extension of CHAR column is wrongly allowed
Browse files Browse the repository at this point in the history
commit 854c219 (MDEV-17301)
broke a constraint: Fixed-length columns cannot be extended in InnoDB
without rebuilding the table.

ha_innobase::can_convert_string(): Correct the condition. We must
not allow any instantaneous change to the length of CHAR columns
measured in characters. For any format other than ROW_FORMAT=REDUNDANT,
we can allow the length in bytes to be extended if mbminlen<mbmaxlen held
before the change of the character set.
  • Loading branch information
dr-m committed Jul 20, 2020
1 parent 956f21c commit 0a7faed
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 40 deletions.
31 changes: 20 additions & 11 deletions mysql-test/suite/innodb/r/instant_alter_extend,utf8.rdiff
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
--- instant_alter_convert.result
+++ instant_alter_convert,utf8.result
@@ -37,7 +37,7 @@
test.t check status OK
@@ -38,7 +38,7 @@
best.t check status OK
call check_table('t');
name mtype prtype len
-a 2 800FE 200
+a 13 2100FE 600
# CHAR enlargement
alter table t modify a char(220), algorithm=instant;
select count(a) from t where a = @bigval;
@@ -51,7 +51,7 @@
test.t check status OK
alter table t modify a char(220);
affected rows: 2
@@ -54,7 +54,7 @@
best.t check status OK
call check_table('t');
name mtype prtype len
-a 2 800FE 220
+a 13 2100FE 660
ALTER TABLE t CHANGE COLUMN a a CHAR(230) BINARY;
affected rows: 2
info: Records: 2 Duplicates: 0 Warnings: 0
@@ -69,7 +69,7 @@
best.t check status OK
call check_table('t');
name mtype prtype len
-a 13 2F00FE 230
+a 13 5300FE 690
# Convert from VARCHAR to a bigger CHAR
alter table t modify a varchar(200), algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
@@ -72,7 +72,7 @@
test.t check status OK
alter table t modify a varchar(200);
affected rows: 2
@@ -92,7 +92,7 @@
best.t check status OK
call check_table('t');
name mtype prtype len
-a 2 800FE 255
+a 13 2100FE 765
# BINARY/VARBINARY test
create or replace table t (a varbinary(300));
alter table t modify a binary(255), algorithm=instant;
insert into t values(NULL);
Binary file modified mysql-test/suite/innodb/r/instant_alter_extend.result
Binary file not shown.
9 changes: 9 additions & 0 deletions mysql-test/suite/innodb/t/instant_alter_extend.test
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ select a, length(a) from t where a = 'z';
check table t extended;
call check_table('t');

--enable_info
ALTER TABLE t CHANGE COLUMN a a CHAR(230) BINARY;
ALTER TABLE t ADD COLUMN b INT FIRST;
ALTER TABLE t DROP b;
--disable_info

check table t extended;
call check_table('t');

--echo # Convert from VARCHAR to a bigger CHAR
--enable_info
alter table t modify a varchar(200);
Expand Down
50 changes: 21 additions & 29 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20986,43 +20986,35 @@ is_part_of_a_primary_key(const Field* field)
&& field->part_of_key.is_set(s->primary_key);
}

bool
ha_innobase::can_convert_string(const Field_string* field,
const Column_definition& new_type) const
bool ha_innobase::can_convert_string(const Field_string *field,
const Column_definition &new_type) const
{
DBUG_ASSERT(!field->compression_method());
if (new_type.type_handler() != field->type_handler()) {
return false;
}
DBUG_ASSERT(!field->compression_method());
if (new_type.type_handler() != field->type_handler())
return false;

if (new_type.char_length < field->char_length()) {
return false;
}
if (new_type.char_length != field->char_length())
return false;

if (new_type.charset != field->charset()) {
if (new_type.length != field->max_display_length()
&& !m_prebuilt->table->not_redundant()) {
return IS_EQUAL_NO;
}
const Charset field_cs(field->charset());

Charset field_cs(field->charset());
if (!field_cs.encoding_allows_reinterpret_as(
new_type.charset)) {
return false;
}
if (new_type.length != field->max_display_length() &&
(!m_prebuilt->table->not_redundant() ||
field_cs.mbminlen() == field_cs.mbmaxlen()))
return false;

if (!field_cs.eq_collation_specific_names(new_type.charset)) {
return !is_part_of_a_primary_key(field);
}
if (new_type.charset != field->charset())
{
if (!field_cs.encoding_allows_reinterpret_as(new_type.charset))
return false;

return true;
}
if (!field_cs.eq_collation_specific_names(new_type.charset))
return !is_part_of_a_primary_key(field);

if (new_type.length != field->max_display_length()) {
return false;
}
return true;
}

return true;
return true;
}

static bool
Expand Down

0 comments on commit 0a7faed

Please sign in to comment.