From b681eed72b4cf7fb463f99de55a1f7e297123b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=AF=92?= Date: Thu, 10 Jul 2025 19:42:33 +0800 Subject: [PATCH] PS-10072 Fix extend varchar bug when using column_format compressed https://perconadev.atlassian.net/browse/PS-10072 When modifying the metadata of a compressed column, if only the length metadata is modified, the new threshold is no longer 256, but 254, which needs to be reduced by the length of the compressed column header. --- ...nd_varchar_column_compressed_bugfix.result | 79 ++++++++++++++++++ ...tend_varchar_column_compressed_bugfix.test | 82 +++++++++++++++++++ sql/field.cc | 10 ++- sql/field.h | 7 ++ 4 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/innodb/r/extend_varchar_column_compressed_bugfix.result create mode 100644 mysql-test/suite/innodb/t/extend_varchar_column_compressed_bugfix.test diff --git a/mysql-test/suite/innodb/r/extend_varchar_column_compressed_bugfix.result b/mysql-test/suite/innodb/r/extend_varchar_column_compressed_bugfix.result new file mode 100644 index 000000000000..a3c571c27ad5 --- /dev/null +++ b/mysql-test/suite/innodb/r/extend_varchar_column_compressed_bugfix.result @@ -0,0 +1,79 @@ +create database database20250708; +# basic bugfix +# -------------------------------------------------------------------- +create table database20250708.t11(c1 varchar(253) column_format compressed)CHARACTER SET ascii; +insert into database20250708.t11 values('qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzR'); +# test from 253 to 254 +alter table database20250708.t11 modify c1 varchar(254) column_format compressed; +select * from database20250708.t11; +c1 +qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzR +SHOW CREATE TABLE database20250708.t11; +Table Create Table +t11 CREATE TABLE `t11` ( + `c1` varchar(254) /*!50633 COLUMN_FORMAT COMPRESSED */ DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=ascii +CHECK TABLE database20250708.t11; +Table Op Msg_type Msg_text +database20250708.t11 check status OK +alter table database20250708.t11 modify c1 varchar(250) column_format compressed; +# test from 250 to 255 +alter table database20250708.t11 modify c1 varchar(255) column_format compressed; +select * from database20250708.t11; +c1 +qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzR +SHOW CREATE TABLE database20250708.t11; +Table Create Table +t11 CREATE TABLE `t11` ( + `c1` varchar(255) /*!50633 COLUMN_FORMAT COMPRESSED */ DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=ascii +CHECK TABLE database20250708.t11; +Table Op Msg_type Msg_text +database20250708.t11 check status OK +# test new threshold 254 in inplace algorithm +alter table database20250708.t11 modify c1 varchar(256) column_format compressed,algorithm=inplace; +SHOW CREATE TABLE database20250708.t11; +Table Create Table +t11 CREATE TABLE `t11` ( + `c1` varchar(256) /*!50633 COLUMN_FORMAT COMPRESSED */ DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=ascii +CHECK TABLE database20250708.t11; +Table Op Msg_type Msg_text +database20250708.t11 check status OK +alter table database20250708.t11 modify c1 varchar(253) column_format compressed; +alter table database20250708.t11 modify c1 varchar(254) column_format compressed,algorithm=inplace; +ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY. +alter table database20250708.t11 modify c1 varchar(252) column_format compressed; +alter table database20250708.t11 modify c1 varchar(256) column_format compressed,algorithm=inplace; +ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY. +# -------------------------------------------------------------------- +# test row log +# -------------------------------------------------------------------- +alter table database20250708.t11 modify c1 varchar(251) column_format compressed; +SET DEBUG_SYNC='alter_table_inplace_after_lock_downgrade SIGNAL update_now WAIT_FOR update_done'; +alter table database20250708.t11 modify c1 varchar(253) column_format compressed,algorithm=inplace; +SET DEBUG_SYNC='now WAIT_FOR update_now'; +insert into database20250708.t11 values('qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzRa1'); +begin; +insert into database20250708.t11 values('qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzRa2'); +delete from database20250708.t11; +rollback; +begin; +update database20250708.t11 set c1 = 'qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzRgg'; +commit; +SET DEBUG_SYNC='now SIGNAL update_done'; +SELECT * FROM database20250708.t11; +c1 +qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzRgg +qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzRgg +SHOW CREATE TABLE database20250708.t11; +Table Create Table +t11 CREATE TABLE `t11` ( + `c1` varchar(253) /*!50633 COLUMN_FORMAT COMPRESSED */ DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=ascii +CHECK TABLE database20250708.t11; +Table Op Msg_type Msg_text +database20250708.t11 check status OK +# -------------------------------------------------------------------- +# clean up +drop database database20250708; diff --git a/mysql-test/suite/innodb/t/extend_varchar_column_compressed_bugfix.test b/mysql-test/suite/innodb/t/extend_varchar_column_compressed_bugfix.test new file mode 100644 index 000000000000..4f351d8e57a9 --- /dev/null +++ b/mysql-test/suite/innodb/t/extend_varchar_column_compressed_bugfix.test @@ -0,0 +1,82 @@ +# Fix extend varchar bug with column compressed +# +# Author : Han Wei +# Date created : 07/08/2025 + +# Run this test only for debug builds and with debug_sync enabled +--source include/have_debug.inc +--source include/have_debug_sync.inc + +connect (con1,localhost,root,,); +connection default; + +create database database20250708; + +--echo # basic bugfix +--echo # -------------------------------------------------------------------- +create table database20250708.t11(c1 varchar(253) column_format compressed)CHARACTER SET ascii; + +insert into database20250708.t11 values('qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzR'); + +--echo # test from 253 to 254 +alter table database20250708.t11 modify c1 varchar(254) column_format compressed; + +select * from database20250708.t11; +SHOW CREATE TABLE database20250708.t11; +CHECK TABLE database20250708.t11; + +alter table database20250708.t11 modify c1 varchar(250) column_format compressed; +--echo # test from 250 to 255 +alter table database20250708.t11 modify c1 varchar(255) column_format compressed; +select * from database20250708.t11; +SHOW CREATE TABLE database20250708.t11; +CHECK TABLE database20250708.t11; + +--echo # test new threshold 254 in inplace algorithm +alter table database20250708.t11 modify c1 varchar(256) column_format compressed,algorithm=inplace; +SHOW CREATE TABLE database20250708.t11; +CHECK TABLE database20250708.t11; + + +alter table database20250708.t11 modify c1 varchar(253) column_format compressed; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +alter table database20250708.t11 modify c1 varchar(254) column_format compressed,algorithm=inplace; + + +alter table database20250708.t11 modify c1 varchar(252) column_format compressed; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +alter table database20250708.t11 modify c1 varchar(256) column_format compressed,algorithm=inplace; + +--echo # -------------------------------------------------------------------- + + +--echo # test row log +--echo # -------------------------------------------------------------------- +alter table database20250708.t11 modify c1 varchar(251) column_format compressed; + +SET DEBUG_SYNC='alter_table_inplace_after_lock_downgrade SIGNAL update_now WAIT_FOR update_done'; +--send alter table database20250708.t11 modify c1 varchar(253) column_format compressed,algorithm=inplace + + +connection con1; +SET DEBUG_SYNC='now WAIT_FOR update_now'; +insert into database20250708.t11 values('qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzRa1'); +begin; +insert into database20250708.t11 values('qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzRa2'); +delete from database20250708.t11; +rollback; +begin; +update database20250708.t11 set c1 = 'qGjZtLxVfDaKbYOpEUmNRWSiHgBcFpLaQwMrSnTzXyCvJuKdFEaBnCdRgTpMwQfJxHyUvIeOzGkSfNbPkYwVcXzAjLmDtFuQiOWdVjAyKfLpUsXnRzBmQeCiTgHoFvYwZxMkNjGbRaEpCuIdSqTFeYgIuBvNxRzQpSmTkCjHzWdVbYaMlEkFhOjZqUcXiDfPgLaRLpZkYjIxGfEdRcBnAmSqUoWtVhNjKpLmFgCvXzQaByTfEuIzRgg'; +commit; + +SET DEBUG_SYNC='now SIGNAL update_done'; + +connection default; +--reap +SELECT * FROM database20250708.t11; +SHOW CREATE TABLE database20250708.t11; +CHECK TABLE database20250708.t11; + +--echo # -------------------------------------------------------------------- +--echo # clean up +drop database database20250708; diff --git a/sql/field.cc b/sql/field.cc index da960287f499..97e28cbfb524 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -161,6 +161,7 @@ bool length_prevents_inplace(const Field &from, const Create_field &to) { "to.max_display_width_in_bytes():%zu", &from, to.field, to.field ? to.field->row_pack_length() : (uint)-1, to.max_display_width_in_bytes())); + size_t threshold_size = 256; if (to.pack_length() < from.pack_length()) { DBUG_PRINT( @@ -170,7 +171,13 @@ bool length_prevents_inplace(const Field &from, const Create_field &to) { return true; } - if (to.max_display_width_in_bytes() >= 256 && from.row_pack_length() < 256) { + if (to.column_format() == COLUMN_FORMAT_TYPE_COMPRESSED && + from.column_format() == COLUMN_FORMAT_TYPE_COMPRESSED) { + threshold_size -= INNOBASE_ZIP_COLUMN_HEADER_LENGTH; + } + + if (to.max_display_width_in_bytes() >= threshold_size && + from.row_pack_length() < threshold_size) { DBUG_PRINT("inplace", ("row_pack_length increases past the 256 threshold, from %u to " "%zu, -> true for '%s'", @@ -179,6 +186,7 @@ bool length_prevents_inplace(const Field &from, const Create_field &to) { DBUG_PRINT("inplace", ("from:%p, to.field:%p, to.field->row_pack_length():%u", &from, to.field, to.field ? to.field->row_pack_length() : (uint)-1)); + DBUG_PRINT("inplace", ("threshold_size:%zu", threshold_size)); return true; } DBUG_PRINT("inplace", ("-> false")); diff --git a/sql/field.h b/sql/field.h index 0bc976bb6761..cfb78cc36a6c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -117,6 +117,13 @@ struct timeval; */ #define portable_sizeof_char_ptr 8 +/* + In InnoDB, the header length of compressed columns is 2 byte. In the + SQL layer, this value is needed to determine whether the inplace + ddl algorithm can be executed in extending varchar DDL. +*/ +#define INNOBASE_ZIP_COLUMN_HEADER_LENGTH 2 + /* Field class hierarchy