From 8bbf6697cf262a76a6c544e45e3658cdfa5402ec Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 2 Nov 2023 14:57:37 +0100 Subject: [PATCH 1/5] MDEV-24784 JSON_ARRAYAGG charset issue set the proper charset for a temporary result --- mysql-test/main/func_json.result | 11 +++++++++++ mysql-test/main/func_json.test | 11 ++++++++++- sql/item_jsonfunc.cc | 7 +++++++ sql/item_jsonfunc.h | 1 + 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index 29f8c383abb..540c8244611 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -1646,5 +1646,16 @@ SELECT JSON_OBJECTAGG('\\', 1); JSON_OBJECTAGG('\\', 1) {"\\":1} # +# MDEV-24784 JSON_ARRAYAGG charset issue +# +set names utf8; +select json_arrayagg('ä'), json_objectagg(1, 'ä'); +json_arrayagg('ä') json_objectagg(1, 'ä') +["ä"] {"1":"ä"} +set names latin1; +select json_arrayagg('ä'), json_objectagg(1, 'ä'); +json_arrayagg('ä') json_objectagg(1, 'ä') +["ä"] {"1":"ä"} +# # End of 10.5 tests # diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index c21fa8d05db..696ffa41a5a 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -1108,7 +1108,16 @@ SELECT JSON_OBJECTAGG('"', 1); SELECT JSON_OBJECTAGG('\"', 1); SELECT JSON_OBJECTAGG('\\', 1); +--echo # +--echo # MDEV-24784 JSON_ARRAYAGG charset issue +--echo # +--disable_service_connection +set names utf8; +select json_arrayagg('ä'), json_objectagg(1, 'ä'); +set names latin1; +select json_arrayagg('ä'), json_objectagg(1, 'ä'); +--enable_service_connection + --echo # --echo # End of 10.5 tests --echo # - diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index b85adeff05d..1105406c658 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -3907,6 +3907,13 @@ int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s) return MY_TEST(sortcmp(res1, res2, compare_collation()) == 0); } +bool Item_func_json_arrayagg::fix_fields(THD *thd, Item **ref) +{ + bool res= Item_func_group_concat::fix_fields(thd, ref); + m_tmp_json.set_charset(collation.collation); + return res; +} + String *Item_func_json_arrayagg::get_str_from_item(Item *i, String *tmp) { diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index 4aaf66ec695..77936fcc4f4 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -570,6 +570,7 @@ public: } const char *func_name() const override { return "json_arrayagg("; } + bool fix_fields(THD *thd, Item **ref) override; enum Sumfunctype sum_func() const override { return JSON_ARRAYAGG_FUNC; } String* val_str(String *str) override; From 8aa2076426471a7496d448ce78921e8497b7b2ef Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 13 Nov 2023 18:41:22 +0100 Subject: [PATCH 2/5] Revert "MDEV-22243 type_test.type_test_double fails with 'NUMERIC_SCALE NULL'" This reverts commit 9d19b6526917c94ca03ef1b4c57152882b192cfe. --- .../type_test/type_test_double.result | 2 +- sql/field.cc | 54 ------------------- sql/field.h | 43 +++++++++++++-- 3 files changed, 39 insertions(+), 60 deletions(-) diff --git a/plugin/type_test/mysql-test/type_test/type_test_double.result b/plugin/type_test/mysql-test/type_test/type_test_double.result index edcfdc0eff8..6241ff95b8a 100644 --- a/plugin/type_test/mysql-test/type_test/type_test_double.result +++ b/plugin/type_test/mysql-test/type_test/type_test_double.result @@ -290,7 +290,7 @@ DATA_TYPE test_double CHARACTER_MAXIMUM_LENGTH NULL CHARACTER_OCTET_LENGTH NULL NUMERIC_PRECISION 22 -NUMERIC_SCALE NULL +NUMERIC_SCALE 31 DATETIME_PRECISION NULL CHARACTER_SET_NAME NULL COLLATION_NAME NULL diff --git a/sql/field.cc b/sql/field.cc index 0337b1e634e..53dc5f2e15a 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4645,28 +4645,6 @@ bool Field_longlong::is_max() single precision float ****************************************************************************/ -Field_float::Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, - const LEX_CSTRING *field_name_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - (dec_arg >= FLOATING_POINT_DECIMALS ? NOT_FIXED_DEC : dec_arg), - zero_arg, unsigned_arg) -{ -} - -Field_float::Field_float(uint32 len_arg, bool maybe_null_arg, - const LEX_CSTRING *field_name_arg, uint8 dec_arg) - :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, - NONE, field_name_arg, - (dec_arg >= FLOATING_POINT_DECIMALS ? NOT_FIXED_DEC : dec_arg), - 0, 0) -{ -} - - int Field_float::store(const char *from,size_t len,CHARSET_INFO *cs) { int error; @@ -4815,38 +4793,6 @@ Binlog_type_info Field_float::binlog_type_info() const double precision floating point numbers ****************************************************************************/ -Field_double::Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, - const LEX_CSTRING *field_name_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - (dec_arg >= FLOATING_POINT_DECIMALS ? NOT_FIXED_DEC : dec_arg), - zero_arg, unsigned_arg) -{ -} - -Field_double::Field_double(uint32 len_arg, bool maybe_null_arg, - const LEX_CSTRING *field_name_arg, uint8 dec_arg) - :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, - NONE, field_name_arg, - (dec_arg >= FLOATING_POINT_DECIMALS ? NOT_FIXED_DEC : dec_arg), - 0, 0) -{ -} - -Field_double::Field_double(uint32 len_arg, bool maybe_null_arg, - const LEX_CSTRING *field_name_arg, - uint8 dec_arg, bool not_fixed_arg) - :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, - NONE, field_name_arg, - (dec_arg >= FLOATING_POINT_DECIMALS ? NOT_FIXED_DEC : dec_arg), - 0, 0) -{ - not_fixed= not_fixed_arg; -} - int Field_double::store(const char *from,size_t len,CHARSET_INFO *cs) { int error; diff --git a/sql/field.h b/sql/field.h index 057bd8453c5..804394c58a6 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2842,9 +2842,22 @@ public: Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg); + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + dec_arg, zero_arg, unsigned_arg) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } Field_float(uint32 len_arg, bool maybe_null_arg, - const LEX_CSTRING *field_name_arg, uint8 dec_arg); + const LEX_CSTRING *field_name_arg, uint8 dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } const Type_handler *type_handler() const override { return &type_handler_float; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_FLOAT; } @@ -2877,12 +2890,32 @@ public: Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg); + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + dec_arg, zero_arg, unsigned_arg) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } Field_double(uint32 len_arg, bool maybe_null_arg, - const LEX_CSTRING *field_name_arg, uint8 dec_arg); + const LEX_CSTRING *field_name_arg, uint8 dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } Field_double(uint32 len_arg, bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - uint8 dec_arg, bool not_fixed_arg); + uint8 dec_arg, bool not_fixed_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + { + not_fixed= not_fixed_arg; + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } void init_for_tmp_table(Field *org_field, TABLE *new_table) override { Field::init_for_tmp_table(org_field, new_table); From 9b7a1c0e922a52759ed761152dfbf57d3cd55316 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 13 Nov 2023 23:38:47 +0100 Subject: [PATCH 3/5] MDEV-22243 type_test.type_test_double fails with 'NUMERIC_SCALE NULL' 1. fix useless correction of dec_arg *after it was used* 2. use DECIMAL_NOT_SPECIFIED instead of NOT_FIXED_DEC, because the latter is defined conditionally and has a wrong value in plugins --- .../type_test/type_test_double.result | 2 +- sql/field.h | 38 +++++++------------ 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/plugin/type_test/mysql-test/type_test/type_test_double.result b/plugin/type_test/mysql-test/type_test/type_test_double.result index 6241ff95b8a..edcfdc0eff8 100644 --- a/plugin/type_test/mysql-test/type_test/type_test_double.result +++ b/plugin/type_test/mysql-test/type_test/type_test_double.result @@ -290,7 +290,7 @@ DATA_TYPE test_double CHARACTER_MAXIMUM_LENGTH NULL CHARACTER_OCTET_LENGTH NULL NUMERIC_PRECISION 22 -NUMERIC_SCALE 31 +NUMERIC_SCALE NULL DATETIME_PRECISION NULL CHARACTER_SET_NAME NULL COLLATION_NAME NULL diff --git a/sql/field.h b/sql/field.h index 804394c58a6..5a5184ed7d4 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2105,7 +2105,7 @@ public: uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, const DTCollation &collation); - uint decimals() const override { return is_created_from_null_item ? 0 : NOT_FIXED_DEC; } + uint decimals() const override { return is_created_from_null_item ? 0 : DECIMAL_NOT_SPECIFIED; } int save_in_field(Field *to) override { return save_in_field_str(to); } bool memcpy_field_possible(const Field *from) const override { @@ -2267,7 +2267,7 @@ public: Information_schema_numeric_attributes information_schema_numeric_attributes() const override { - return dec == NOT_FIXED_DEC ? + return dec == DECIMAL_NOT_SPECIFIED ? Information_schema_numeric_attributes(field_length) : Information_schema_numeric_attributes(field_length, dec); } @@ -2836,6 +2836,8 @@ public: integers. But in all other cases we treat it as TIME_RESULT! */ }; +static inline uint8 fix_dec_arg(uint8 dec_arg) +{ return dec_arg >= FLOATING_POINT_DECIMALS ? DECIMAL_NOT_SPECIFIED : dec_arg; } class Field_float final :public Field_real { public: @@ -2845,19 +2847,13 @@ public: uint8 dec_arg,bool zero_arg,bool unsigned_arg) :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, - dec_arg, zero_arg, unsigned_arg) - { - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; - } + fix_dec_arg(dec_arg), zero_arg, unsigned_arg) + { } Field_float(uint32 len_arg, bool maybe_null_arg, const LEX_CSTRING *field_name_arg, uint8 dec_arg) :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, - NONE, field_name_arg, dec_arg, 0, 0) - { - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; - } + NONE, field_name_arg, fix_dec_arg(dec_arg), 0, 0) + { } const Type_handler *type_handler() const override { return &type_handler_float; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_FLOAT; } @@ -2893,28 +2889,20 @@ public: uint8 dec_arg,bool zero_arg,bool unsigned_arg) :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, - dec_arg, zero_arg, unsigned_arg) - { - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; - } + fix_dec_arg(dec_arg), zero_arg, unsigned_arg) + { } Field_double(uint32 len_arg, bool maybe_null_arg, const LEX_CSTRING *field_name_arg, uint8 dec_arg) :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, - NONE, field_name_arg, dec_arg, 0, 0) - { - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; - } + NONE, field_name_arg, fix_dec_arg(dec_arg), 0, 0) + { } Field_double(uint32 len_arg, bool maybe_null_arg, const LEX_CSTRING *field_name_arg, uint8 dec_arg, bool not_fixed_arg) :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, - NONE, field_name_arg, dec_arg, 0, 0) + NONE, field_name_arg, fix_dec_arg(dec_arg), 0, 0) { not_fixed= not_fixed_arg; - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; } void init_for_tmp_table(Field *org_field, TABLE *new_table) override { From cd04673a177d40f7c409284d87ead851ec775c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 20 Nov 2023 16:57:57 +0200 Subject: [PATCH 4/5] MDEV-32050 fixup: innodb.instant_alter_crash (take 2) We must disable persistent statistics, because a transaction commit from dict_stats_save() would occasionally interfere with this test. --- mysql-test/suite/innodb/r/instant_alter_crash.result | 7 +++---- mysql-test/suite/innodb/t/instant_alter_crash.test | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_crash.result b/mysql-test/suite/innodb/r/instant_alter_crash.result index b92f8ee8724..e423afe10a8 100644 --- a/mysql-test/suite/innodb/r/instant_alter_crash.result +++ b/mysql-test/suite/innodb/r/instant_alter_crash.result @@ -3,7 +3,7 @@ FLUSH TABLES; # MDEV-11369: Instant ADD COLUMN for InnoDB # CREATE TABLE t1(id INT PRIMARY KEY, c2 INT UNIQUE) -ENGINE=InnoDB ROW_FORMAT=REDUNDANT; +ENGINE=InnoDB STATS_PERSISTENT=0 ROW_FORMAT=REDUNDANT; CREATE TABLE t2 LIKE t1; INSERT INTO t1 VALUES(0,2); INSERT INTO t2 VALUES(2,1); @@ -27,7 +27,6 @@ SELECT * FROM t2; id c2 c3 2 1 De finibus bonorum 3 4 accusantium doloremque laudantium -InnoDB 0 transactions not purged BEGIN; DELETE FROM t1; ROLLBACK; @@ -161,7 +160,7 @@ t1 CREATE TABLE `t1` ( `c2` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `c2` (`c2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ROW_FORMAT=REDUNDANT +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci STATS_PERSISTENT=0 ROW_FORMAT=REDUNDANT SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( @@ -169,7 +168,7 @@ t2 CREATE TABLE `t2` ( `c2` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `c2` (`c2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ROW_FORMAT=REDUNDANT +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci STATS_PERSISTENT=0 ROW_FORMAT=REDUNDANT SHOW CREATE TABLE t3; Table Create Table t3 CREATE TABLE `t3` ( diff --git a/mysql-test/suite/innodb/t/instant_alter_crash.test b/mysql-test/suite/innodb/t/instant_alter_crash.test index 8eb03b39a1b..f51f61e3c04 100644 --- a/mysql-test/suite/innodb/t/instant_alter_crash.test +++ b/mysql-test/suite/innodb/t/instant_alter_crash.test @@ -14,7 +14,7 @@ let MYSQLD_DATADIR=`select @@datadir`; --echo # CREATE TABLE t1(id INT PRIMARY KEY, c2 INT UNIQUE) -ENGINE=InnoDB ROW_FORMAT=REDUNDANT; +ENGINE=InnoDB STATS_PERSISTENT=0 ROW_FORMAT=REDUNDANT; CREATE TABLE t2 LIKE t1; INSERT INTO t1 VALUES(0,2); INSERT INTO t2 VALUES(2,1); @@ -38,7 +38,6 @@ disconnect ddl; SELECT * FROM t1; SELECT * FROM t2; ---source include/wait_all_purged.inc BEGIN; DELETE FROM t1; ROLLBACK; From de31ca6a212118bd29876f964497050e446bda02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 21 Nov 2023 08:53:02 +0200 Subject: [PATCH 5/5] MDEV-32820 Race condition between trx_purge_free_segment() and trx_undo_create() trx_purge_free_segment(): If fseg_free_step_not_header() needs to be called multiple times, acquire an exclusive latch on the rollback segment header page after restarting the mini-transaction so that the rest of this function cannot execute concurrently with trx_undo_create() on the same rollback segment. This fixes a regression that was introduced in commit c14a39431b211017e6809bb79c4079b38ffc3dff (MDEV-30753). Note: The buffer-fixes that we are holding across the mini-transaction restart will prevent the pages from being evicted from the buffer pool. They may be accessed by other threads or written back to data files while we are not holding exclusive latches. Reviewed by: Vladislav Lesin --- storage/innobase/trx/trx0purge.cc | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 4a98dee573e..b06e3cb3e1b 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -365,8 +365,10 @@ void trx_purge_free_segment(mtr_t &mtr, trx_rseg_t* rseg, fil_addr_t hdr_addr) while (!fseg_free_step_not_header(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + block->frame, &mtr)) { - block->fix(); - const page_id_t id{block->page.id()}; + buf_block_buf_fix_inc(rseg_hdr, __FILE__, __LINE__); + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + ut_d(const page_id_t rseg_hdr_id{rseg_hdr->page.id()}); + ut_d(const page_id_t id{block->page.id()}); mtr.commit(); /* NOTE: If the server is killed after the log that was produced up to this point was written, and before the log from the mtr.commit() @@ -376,19 +378,12 @@ void trx_purge_free_segment(mtr_t &mtr, trx_rseg_t* rseg, fil_addr_t hdr_addr) This does not matter when using multiple innodb_undo_tablespaces; innodb_undo_log_truncate=ON will be able to reclaim the space. */ mtr.start(); - ut_ad(rw_lock_s_lock_nowait(block->debug_latch, __FILE__, __LINE__)); + rw_lock_x_lock(&rseg_hdr->lock); rw_lock_x_lock(&block->lock); - if (UNIV_UNLIKELY(block->page.id() != id)) - { - block->unfix(); - rw_lock_x_unlock(&block->lock); - ut_d(rw_lock_s_unlock(block->debug_latch)); - block= buf_page_get(id, 0, RW_X_LATCH, &mtr); - if (!block) - return; - } - else - mtr_memo_push(&mtr, block, MTR_MEMO_PAGE_X_FIX); + ut_ad(rseg_hdr->page.id() == rseg_hdr_id); + ut_ad(block->page.id() == id); + mtr_memo_push(&mtr, rseg_hdr, MTR_MEMO_PAGE_X_FIX); + mtr_memo_push(&mtr, block, MTR_MEMO_PAGE_X_FIX); } while (!fseg_free_step(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER +