diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index 0336de08e50..10aa6261089 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -1646,6 +1646,17 @@ 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 2218a976c31..18d970cff16 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -1111,6 +1111,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/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; diff --git a/sql/field.cc b/sql/field.cc index e94d5c19171..c3cd82a2cfc 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4741,30 +4741,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, - decimal_digits_t 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, - decimal_digits_t 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; @@ -4913,40 +4889,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, - decimal_digits_t 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, - decimal_digits_t 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, - decimal_digits_t 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 c456b2e774e..c1d9b1dfb81 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2137,7 +2137,7 @@ public: const LEX_CSTRING *field_name_arg, const DTCollation &collation); decimal_digits_t decimals() const override - { return is_created_from_null_item ? 0 : NOT_FIXED_DEC; } + { 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 { @@ -2307,7 +2307,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); } @@ -2879,15 +2879,24 @@ public: integers. But in all other cases we treat it as TIME_RESULT! */ }; +static inline decimal_digits_t fix_dec_arg(decimal_digits_t dec_arg) +{ return dec_arg >= FLOATING_POINT_DECIMALS ? DECIMAL_NOT_SPECIFIED : dec_arg; } class Field_float final :public Field_real { 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, - decimal_digits_t dec_arg,bool zero_arg,bool unsigned_arg); + decimal_digits_t 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, + fix_dec_arg(dec_arg), zero_arg, unsigned_arg) + { } Field_float(uint32 len_arg, bool maybe_null_arg, - const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg); + const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + 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; } @@ -2920,12 +2929,24 @@ 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, - decimal_digits_t dec_arg,bool zero_arg,bool unsigned_arg); + decimal_digits_t 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, + fix_dec_arg(dec_arg), zero_arg, unsigned_arg) + { } Field_double(uint32 len_arg, bool maybe_null_arg, - const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg); + const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + 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, - decimal_digits_t dec_arg, bool not_fixed_arg); + decimal_digits_t dec_arg, bool not_fixed_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, fix_dec_arg(dec_arg), 0, 0) + { + not_fixed= not_fixed_arg; + } void init_for_tmp_table(Field *org_field, TABLE *new_table) override { Field::init_for_tmp_table(org_field, new_table); diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 590fde88a52..040da099748 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -4088,6 +4088,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 6f6b6a7afe8..55bc3b8520a 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -717,6 +717,7 @@ public: static LEX_CSTRING name= {STRING_WITH_LEN("json_arrayagg(") }; return name; } + bool fix_fields(THD *thd, Item **ref) override; enum Sumfunctype sum_func() const override { return JSON_ARRAYAGG_FUNC; } String* val_str(String *str) override; diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index ffb58f09445..f24739e1e8d 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -350,14 +350,21 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) } /** Free an undo log segment. -@param block rollback segment header page +@param rseg_hdr rollback segment header page +@param block undo segment header page @param mtr mini-transaction */ -static void trx_purge_free_segment(buf_block_t *block, mtr_t &mtr) +static void trx_purge_free_segment(buf_block_t *rseg_hdr, buf_block_t *block, + mtr_t &mtr) { + ut_ad(mtr.memo_contains_flagged(rseg_hdr, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr.memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); + while (!fseg_free_step_not_header(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + block->page.frame, &mtr)) { + rseg_hdr->fix(); block->fix(); + 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 @@ -368,8 +375,11 @@ static void trx_purge_free_segment(buf_block_t *block, mtr_t &mtr) This does not matter when using multiple innodb_undo_tablespaces; innodb_undo_log_truncate=ON will be able to reclaim the space. */ mtr.start(); + rseg_hdr->page.lock.x_lock(); + ut_ad(rseg_hdr->page.id() == rseg_hdr_id); block->page.lock.x_lock(); ut_ad(block->page.id() == id); + mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_MODIFY); mtr.memo_push(block, MTR_MEMO_PAGE_X_MODIFY); } @@ -459,7 +469,7 @@ loop: free_segment: ut_ad(rseg.curr_size >= seg_size); rseg.curr_size-= seg_size; - trx_purge_free_segment(b, mtr); + trx_purge_free_segment(rseg_hdr, b, mtr); break; case TRX_UNDO_CACHED: /* rseg.undo_cached must point to this page */