From d56f42a0b20dd5c5a12b6a7874d872253ae0b159 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Thu, 2 Oct 2025 19:27:08 +1000 Subject: [PATCH 01/54] MDEV-37113 Some cleanup and documentation of spider gbh creation --- storage/spider/ha_spider.h | 9 +++++++++ storage/spider/spd_db_include.h | 2 +- storage/spider/spd_group_by_handler.cc | 23 +++++++++++++++++++---- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/storage/spider/ha_spider.h b/storage/spider/ha_spider.h index 074339c2aca..1353b932e53 100644 --- a/storage/spider/ha_spider.h +++ b/storage/spider/ha_spider.h @@ -95,8 +95,17 @@ public: bool da_status; bool use_spatial_index; + /* + Index of the table in FROM tables, for the use of direct + execution by gbh + */ uint idx_for_direct_join; + /* + Whether using a spider_fields, only applicable to direct + execution by gbh + */ bool use_fields; + /* If use_fields == true, the spider_fields in use for gbh */ spider_fields *fields; SPIDER_LINK_IDX_CHAIN *link_idx_chain; SPIDER_LINK_IDX_CHAIN *result_link_idx_chain; diff --git a/storage/spider/spd_db_include.h b/storage/spider/spd_db_include.h index dd4aa02a6dc..017b077f819 100644 --- a/storage/spider/spd_db_include.h +++ b/storage/spider/spd_db_include.h @@ -616,7 +616,7 @@ public: ); SPIDER_CONN_HOLDER *create_conn_holder(); bool has_conn_holder(); - void clear_conn_holder_from_conn(); + void clear_conn_holder_checked(); bool check_conn_same_conn( SPIDER_CONN *conn_arg ); diff --git a/storage/spider/spd_group_by_handler.cc b/storage/spider/spd_group_by_handler.cc index a612ec5e382..21e40eb37e2 100644 --- a/storage/spider/spd_group_by_handler.cc +++ b/storage/spider/spd_group_by_handler.cc @@ -631,7 +631,8 @@ bool spider_fields::has_conn_holder( DBUG_RETURN(first_conn_holder); } -void spider_fields::clear_conn_holder_from_conn( +/* Mark checked_for_same_conn to false for all conn holders */ +void spider_fields::clear_conn_holder_checked( ) { DBUG_ENTER("spider_fields::clear_conn_checked_for_same_conn"); DBUG_PRINT("info",("spider this=%p", this)); @@ -643,6 +644,9 @@ void spider_fields::clear_conn_holder_from_conn( DBUG_VOID_RETURN; } +/* Set current conn holder to be the first conn holder with a matching + conn and mark its checked_for_same_conn to be true. Return true if + one is found and vice versa. */ bool spider_fields::check_conn_same_conn( SPIDER_CONN *conn_arg ) { @@ -660,6 +664,7 @@ bool spider_fields::check_conn_same_conn( DBUG_RETURN(FALSE); } +/* Remove all conn holders with false checked_for_same_conn */ bool spider_fields::remove_conn_if_not_checked( ) { SPIDER_CONN_HOLDER *conn_holder; @@ -1468,6 +1473,7 @@ group_by_handler *spider_create_group_by_handler( goto skip_free_table_holder; } memset(dbton_bitmap, 0, spider_bitmap_size(SPIDER_DBTON_SIZE)); + /* Find all backends used by the first table. */ for (roop_count = 0; roop_count < (int) share->use_dbton_count; ++roop_count) { dbton_id = share->use_sql_dbton_ids[roop_count]; @@ -1498,6 +1504,7 @@ group_by_handler *spider_create_group_by_handler( DBUG_PRINT("info",("spider can not add a table")); goto skip_free_table_holder; } + /* Find all backends used by the current table */ memset(dbton_bitmap_tmp, 0, spider_bitmap_size(SPIDER_DBTON_SIZE)); for (roop_count = 0; roop_count < (int) share->use_dbton_count; ++roop_count) { @@ -1509,6 +1516,7 @@ group_by_handler *spider_create_group_by_handler( spider_set_bit(dbton_bitmap_tmp, dbton_id); } } + /* Intersect to get common backends used by all tables (so far) */ for (roop_count = 0; roop_count < spider_bitmap_size(SPIDER_DBTON_SIZE); ++roop_count) { @@ -1758,7 +1766,7 @@ group_by_handler *spider_create_group_by_handler( while ((from = from->next_local)) { - fields->clear_conn_holder_from_conn(); + fields->clear_conn_holder_checked(); if (from->table->part_info) { @@ -1799,10 +1807,13 @@ group_by_handler *spider_create_group_by_handler( DBUG_PRINT("info",("spider conn=%p", conn)); if (!fields->check_conn_same_conn(conn)) { - DBUG_PRINT("info",("spider connection %p can not be used for this query with locking", - conn)); if (lock_mode) + { + DBUG_PRINT("info", ("spider connection %p can not be used for this " + "query with locking", + conn)); goto skip_free_fields; + } continue; } if (fields->add_link_idx(conn->conn_holder_for_direct_join, spider, roop_count)) @@ -1820,6 +1831,10 @@ group_by_handler *spider_create_group_by_handler( goto skip_free_fields; } } + /* Do not create if all conn holders have been removed. This + happens if the current table does not share usable conns with + the first table. One typical example is when the current table + is located on a different server from the first table. */ if (!fields->has_conn_holder()) { goto skip_free_fields; From 4b5969bfdd2077dfac23c9eb9fe0a103339bca40 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Wed, 22 Oct 2025 13:27:46 +1100 Subject: [PATCH 02/54] MDEV-37113 spider: cleanup and documentation of spider active vs all links Add documentation, and rename variables --- storage/spider/ha_spider.h | 46 ++++++- storage/spider/spd_conn.cc | 206 +++++++++++++++---------------- storage/spider/spd_conn.h | 4 +- storage/spider/spd_db_include.h | 1 + storage/spider/spd_db_mysql.cc | 12 +- storage/spider/spd_include.h | 8 +- storage/spider/spd_ping_table.cc | 30 ++--- storage/spider/spd_ping_table.h | 4 +- storage/spider/spd_trx.cc | 34 ++--- 9 files changed, 196 insertions(+), 149 deletions(-) diff --git a/storage/spider/ha_spider.h b/storage/spider/ha_spider.h index 1353b932e53..0376407428b 100644 --- a/storage/spider/ha_spider.h +++ b/storage/spider/ha_spider.h @@ -65,12 +65,56 @@ public: char *conn_keys_first_ptr; char **conn_keys; SPIDER_CONN **conns; - /* array of indexes of active servers */ + /* + Array of indexes of active servers. + + For a spider table or partition with multiple remotes (HA), the + remotes are divided into n groups of active links, where n is the + number of "active link count", equal to share->link_count aka + share->active_link_count. For example, if a spider table has 11 + remotes (i.e. share->all_link_count == 11), and + share->active_link_count == 3, then we have 3 link groups with + group 0 consisting of the 0th, 3rd, 6th and 9th remotes and so on: + + group 0: 0, 3, 6, 9 + group 1: 1, 4, 7, 10 + group 2: 2, 5, 8 + + conn_link_idx[i] is the "current" remote chosen for the ith group, + and it can only take a value in the ith group. + + Continue with the example above, at some point, we could end up + with: + + conn_link_idx[0] == 3 + conn_link_idx[1] == 1 + conn_link_idx[2] == 8 + + conn_link_idx is set in spider_trx_set_link_idx_for_all(). + + By default, active_link_idx is the same number as all_link_count, + i.e. 11 in the above example. + + If spider HA is gone (MDEV-28862), this will be no longer needed. + + Typically, to distinguish the ith group and ith link, we use + variable names link_idx and all_link_idx respectively, so we often + have + + all_link_idx == conn_link_idx[link_idx] + + spider->conns[link_idx] is created using connection info of the + `conn_link_idx[link_idx]'th remote. + + When only one of the indexes is used, we simply use variable name + link_idx + */ uint *conn_link_idx; /* A bitmap indicating whether each active server have some higher numbered server in the same "group" left to try (can fail over) */ uchar *conn_can_fo; void **quick_targets; + /* indexed on active servers */ int *need_mons; query_id_t search_link_query_id; int search_link_idx; diff --git a/storage/spider/spd_conn.cc b/storage/spider/spd_conn.cc index 67515c25053..951fb497a9a 100644 --- a/storage/spider/spd_conn.cc +++ b/storage/spider/spd_conn.cc @@ -400,8 +400,8 @@ static inline void spider_memcpy_or_null(char **dest, char *alloced, SPIDER_CONN *spider_create_conn( SPIDER_SHARE *share, ha_spider *spider, + int all_link_idx, int link_idx, - int base_link_idx, int *error_num ) { int *need_mon; @@ -421,10 +421,10 @@ SPIDER_CONN *spider_create_conn( } bool tables_on_different_db_are_joinable; - if (share->sql_dbton_ids[link_idx] != SPIDER_DBTON_SIZE) + if (share->sql_dbton_ids[all_link_idx] != SPIDER_DBTON_SIZE) { tables_on_different_db_are_joinable = - spider_dbton[share->sql_dbton_ids[link_idx]].db_util-> + spider_dbton[share->sql_dbton_ids[all_link_idx]].db_util-> tables_on_different_db_are_joinable(); } else { tables_on_different_db_are_joinable = TRUE; @@ -432,36 +432,36 @@ SPIDER_CONN *spider_create_conn( if (!(conn = (SPIDER_CONN *) spider_bulk_malloc(spider_current_trx, SPD_MID_CREATE_CONN_1, MYF(MY_WME | MY_ZEROFILL), &conn, (uint) (sizeof(*conn)), - &tmp_name, (uint) (share->conn_keys_lengths[link_idx] + 1), - &tmp_host, (uint) (share->tgt_hosts_lengths[link_idx] + 1), + &tmp_name, (uint) (share->conn_keys_lengths[all_link_idx] + 1), + &tmp_host, (uint) (share->tgt_hosts_lengths[all_link_idx] + 1), &tmp_username, - (uint) (share->tgt_usernames_lengths[link_idx] + 1), + (uint) (share->tgt_usernames_lengths[all_link_idx] + 1), &tmp_password, - (uint) (share->tgt_passwords_lengths[link_idx] + 1), - &tmp_socket, (uint) (share->tgt_sockets_lengths[link_idx] + 1), + (uint) (share->tgt_passwords_lengths[all_link_idx] + 1), + &tmp_socket, (uint) (share->tgt_sockets_lengths[all_link_idx] + 1), &tmp_wrapper, - (uint) (share->tgt_wrappers_lengths[link_idx] + 1), + (uint) (share->tgt_wrappers_lengths[all_link_idx] + 1), &tmp_db, (uint) (tables_on_different_db_are_joinable ? - 0 : share->tgt_dbs_lengths[link_idx] + 1), - &tmp_ssl_ca, (uint) (share->tgt_ssl_cas_lengths[link_idx] + 1), + 0 : share->tgt_dbs_lengths[all_link_idx] + 1), + &tmp_ssl_ca, (uint) (share->tgt_ssl_cas_lengths[all_link_idx] + 1), &tmp_ssl_capath, - (uint) (share->tgt_ssl_capaths_lengths[link_idx] + 1), + (uint) (share->tgt_ssl_capaths_lengths[all_link_idx] + 1), &tmp_ssl_cert, - (uint) (share->tgt_ssl_certs_lengths[link_idx] + 1), + (uint) (share->tgt_ssl_certs_lengths[all_link_idx] + 1), &tmp_ssl_cipher, - (uint) (share->tgt_ssl_ciphers_lengths[link_idx] + 1), + (uint) (share->tgt_ssl_ciphers_lengths[all_link_idx] + 1), &tmp_ssl_key, - (uint) (share->tgt_ssl_keys_lengths[link_idx] + 1), + (uint) (share->tgt_ssl_keys_lengths[all_link_idx] + 1), &tmp_default_file, - (uint) (share->tgt_default_files_lengths[link_idx] + 1), + (uint) (share->tgt_default_files_lengths[all_link_idx] + 1), &tmp_default_group, - (uint) (share->tgt_default_groups_lengths[link_idx] + 1), + (uint) (share->tgt_default_groups_lengths[all_link_idx] + 1), &tmp_dsn, - (uint) (share->tgt_dsns_lengths[link_idx] + 1), + (uint) (share->tgt_dsns_lengths[all_link_idx] + 1), &tmp_filedsn, - (uint) (share->tgt_filedsns_lengths[link_idx] + 1), + (uint) (share->tgt_filedsns_lengths[all_link_idx] + 1), &tmp_driver, - (uint) (share->tgt_drivers_lengths[link_idx] + 1), + (uint) (share->tgt_drivers_lengths[all_link_idx] + 1), &need_mon, (uint) (sizeof(int)), NullS)) ) { @@ -470,76 +470,76 @@ SPIDER_CONN *spider_create_conn( } conn->default_database.init_calc_mem(SPD_MID_CREATE_CONN_2); - conn->conn_key_length = share->conn_keys_lengths[link_idx]; + conn->conn_key_length = share->conn_keys_lengths[all_link_idx]; conn->conn_key = tmp_name; - memcpy(conn->conn_key, share->conn_keys[link_idx], - share->conn_keys_lengths[link_idx]); - conn->conn_key_hash_value = share->conn_keys_hash_value[link_idx]; + memcpy(conn->conn_key, share->conn_keys[all_link_idx], + share->conn_keys_lengths[all_link_idx]); + conn->conn_key_hash_value = share->conn_keys_hash_value[all_link_idx]; spider_memcpy_or_null(&conn->tgt_host, tmp_host, - share->tgt_hosts[link_idx], &conn->tgt_host_length, - share->tgt_hosts_lengths[link_idx]); + share->tgt_hosts[all_link_idx], &conn->tgt_host_length, + share->tgt_hosts_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_username, tmp_username, - share->tgt_usernames[link_idx], + share->tgt_usernames[all_link_idx], &conn->tgt_username_length, - share->tgt_usernames_lengths[link_idx]); + share->tgt_usernames_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_password, tmp_password, - share->tgt_passwords[link_idx], + share->tgt_passwords[all_link_idx], &conn->tgt_password_length, - share->tgt_passwords_lengths[link_idx]); + share->tgt_passwords_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_socket, tmp_socket, - share->tgt_sockets[link_idx], + share->tgt_sockets[all_link_idx], &conn->tgt_socket_length, - share->tgt_sockets_lengths[link_idx]); + share->tgt_sockets_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_wrapper, tmp_wrapper, - share->tgt_wrappers[link_idx], + share->tgt_wrappers[all_link_idx], &conn->tgt_wrapper_length, - share->tgt_wrappers_lengths[link_idx]); + share->tgt_wrappers_lengths[all_link_idx]); if (!tables_on_different_db_are_joinable) { - spider_memcpy_or_null(&conn->tgt_db, tmp_db, share->tgt_dbs[link_idx], + spider_memcpy_or_null(&conn->tgt_db, tmp_db, share->tgt_dbs[all_link_idx], &conn->tgt_db_length, - share->tgt_dbs_lengths[link_idx]); + share->tgt_dbs_lengths[all_link_idx]); } spider_memcpy_or_null(&conn->tgt_ssl_ca, tmp_ssl_ca, - share->tgt_ssl_cas[link_idx], + share->tgt_ssl_cas[all_link_idx], &conn->tgt_ssl_ca_length, - share->tgt_ssl_cas_lengths[link_idx]); + share->tgt_ssl_cas_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_ssl_capath, tmp_ssl_capath, - share->tgt_ssl_capaths[link_idx], + share->tgt_ssl_capaths[all_link_idx], &conn->tgt_ssl_capath_length, - share->tgt_ssl_capaths_lengths[link_idx]); + share->tgt_ssl_capaths_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_ssl_cert, tmp_ssl_cert, - share->tgt_ssl_certs[link_idx], + share->tgt_ssl_certs[all_link_idx], &conn->tgt_ssl_cert_length, - share->tgt_ssl_certs_lengths[link_idx]); + share->tgt_ssl_certs_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_ssl_cipher, tmp_ssl_cipher, - share->tgt_ssl_ciphers[link_idx], + share->tgt_ssl_ciphers[all_link_idx], &conn->tgt_ssl_cipher_length, - share->tgt_ssl_ciphers_lengths[link_idx]); + share->tgt_ssl_ciphers_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_ssl_key, tmp_ssl_key, - share->tgt_ssl_keys[link_idx], + share->tgt_ssl_keys[all_link_idx], &conn->tgt_ssl_key_length, - share->tgt_ssl_keys_lengths[link_idx]); + share->tgt_ssl_keys_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_default_file, tmp_default_file, - share->tgt_default_files[link_idx], + share->tgt_default_files[all_link_idx], &conn->tgt_default_file_length, - share->tgt_default_files_lengths[link_idx]); + share->tgt_default_files_lengths[all_link_idx]); spider_memcpy_or_null(&conn->tgt_default_group, tmp_default_group, - share->tgt_default_groups[link_idx], + share->tgt_default_groups[all_link_idx], &conn->tgt_default_group_length, - share->tgt_default_groups_lengths[link_idx]); - spider_memcpy_or_null(&conn->tgt_dsn, tmp_dsn, share->tgt_dsns[link_idx], + share->tgt_default_groups_lengths[all_link_idx]); + spider_memcpy_or_null(&conn->tgt_dsn, tmp_dsn, share->tgt_dsns[all_link_idx], &conn->tgt_dsn_length, - share->tgt_dsns_lengths[link_idx]); - spider_memcpy_or_null(&conn->tgt_filedsn, tmp_filedsn, share->tgt_filedsns[link_idx], + share->tgt_dsns_lengths[all_link_idx]); + spider_memcpy_or_null(&conn->tgt_filedsn, tmp_filedsn, share->tgt_filedsns[all_link_idx], &conn->tgt_filedsn_length, - share->tgt_filedsns_lengths[link_idx]); - spider_memcpy_or_null(&conn->tgt_driver, tmp_driver, share->tgt_drivers[link_idx], + share->tgt_filedsns_lengths[all_link_idx]); + spider_memcpy_or_null(&conn->tgt_driver, tmp_driver, share->tgt_drivers[all_link_idx], &conn->tgt_driver_length, - share->tgt_drivers_lengths[link_idx]); - conn->tgt_port = share->tgt_ports[link_idx]; - conn->tgt_ssl_vsc = share->tgt_ssl_vscs[link_idx]; - conn->dbton_id = share->sql_dbton_ids[link_idx]; + share->tgt_drivers_lengths[all_link_idx]); + conn->tgt_port = share->tgt_ports[all_link_idx]; + conn->tgt_ssl_vsc = share->tgt_ssl_vscs[all_link_idx]; + conn->dbton_id = share->sql_dbton_ids[all_link_idx]; if (conn->dbton_id == SPIDER_DBTON_SIZE) { my_printf_error( @@ -564,10 +564,10 @@ SPIDER_CONN *spider_create_conn( conn->semi_trx_isolation = -2; conn->semi_trx_isolation_chk = FALSE; conn->semi_trx_chk = FALSE; - conn->link_idx = base_link_idx; + conn->link_idx = link_idx; conn->conn_need_mon = need_mon; if (spider) - conn->need_mon = &spider->need_mons[base_link_idx]; + conn->need_mon = &spider->need_mons[link_idx]; else conn->need_mon = need_mon; @@ -583,7 +583,7 @@ SPIDER_CONN *spider_create_conn( goto error_conn_init; } - spider_conn_queue_connect(share, conn, link_idx); + spider_conn_queue_connect(share, conn, all_link_idx); conn->ping_time = (time_t) time((time_t*) 0); conn->connect_error_time = conn->ping_time; pthread_mutex_lock(&spider_conn_id_mutex); @@ -654,13 +654,11 @@ SPIDER_CONN *spider_get_conn( int *error_num ) { SPIDER_CONN *conn = NULL; - int base_link_idx = link_idx; + int all_link_idx= link_idx; DBUG_ENTER("spider_get_conn"); if (spider) - link_idx = spider->conn_link_idx[base_link_idx]; - DBUG_PRINT("info",("spider link_idx=%u", link_idx)); - DBUG_PRINT("info",("spider base_link_idx=%u", base_link_idx)); + all_link_idx = spider->conn_link_idx[link_idx]; #ifdef DBUG_TRACE spider_print_keys(conn_key, share->conn_keys_lengths[link_idx]); @@ -669,13 +667,13 @@ SPIDER_CONN *spider_get_conn( (another && !(conn = (SPIDER_CONN*) my_hash_search_using_hash_value( &trx->trx_another_conn_hash, - share->conn_keys_hash_value[link_idx], - (uchar*) conn_key, share->conn_keys_lengths[link_idx]))) || + share->conn_keys_hash_value[all_link_idx], + (uchar*) conn_key, share->conn_keys_lengths[all_link_idx]))) || (!another && !(conn = (SPIDER_CONN*) my_hash_search_using_hash_value( &trx->trx_conn_hash, - share->conn_keys_hash_value[link_idx], - (uchar*) conn_key, share->conn_keys_lengths[link_idx]))) + share->conn_keys_hash_value[all_link_idx], + (uchar*) conn_key, share->conn_keys_lengths[all_link_idx]))) ) { if ( @@ -687,15 +685,15 @@ SPIDER_CONN *spider_get_conn( ) { pthread_mutex_lock(&spider_conn_mutex); if (!(conn = (SPIDER_CONN*) my_hash_search_using_hash_value( - &spider_open_connections, share->conn_keys_hash_value[link_idx], - (uchar*) share->conn_keys[link_idx], - share->conn_keys_lengths[link_idx]))) + &spider_open_connections, share->conn_keys_hash_value[all_link_idx], + (uchar*) share->conn_keys[all_link_idx], + share->conn_keys_lengths[all_link_idx]))) { pthread_mutex_unlock(&spider_conn_mutex); if (spider_param_max_connections()) { /* enable connection pool */ conn= spider_get_conn_from_idle_connection( - share, link_idx, conn_key, spider, base_link_idx, error_num); + share, all_link_idx, conn_key, spider, link_idx, error_num); /* failed get conn, goto error */ if (!conn) goto error; @@ -704,14 +702,14 @@ SPIDER_CONN *spider_get_conn( else { /* did not enable conncetion pool , create_conn */ DBUG_PRINT("info",("spider create new conn")); - if (!(conn= spider_create_conn(share, spider, link_idx, - base_link_idx, error_num))) + if (!(conn= spider_create_conn(share, spider, all_link_idx, + link_idx, error_num))) goto error; *conn->conn_key = *conn_key; if (spider) { - spider->conns[base_link_idx] = conn; - if (spider_bit_is_set(spider->conn_can_fo, base_link_idx)) + spider->conns[link_idx] = conn; + if (spider_bit_is_set(spider->conn_can_fo, link_idx)) conn->use_for_active_standby = TRUE; } } @@ -721,22 +719,22 @@ SPIDER_CONN *spider_get_conn( DBUG_PRINT("info",("spider get global conn")); if (spider) { - spider->conns[base_link_idx] = conn; - if (spider_bit_is_set(spider->conn_can_fo, base_link_idx)) + spider->conns[link_idx] = conn; + if (spider_bit_is_set(spider->conn_can_fo, link_idx)) conn->use_for_active_standby = TRUE; } } } else { DBUG_PRINT("info",("spider create new conn")); /* conn_recycle_strict = 0 and conn_recycle_mode = 0 or 2 */ - if (!(conn= spider_create_conn(share, spider, link_idx, base_link_idx, + if (!(conn= spider_create_conn(share, spider, all_link_idx, link_idx, error_num))) goto error; *conn->conn_key = *conn_key; if (spider) { - spider->conns[base_link_idx] = conn; - if (spider_bit_is_set(spider->conn_can_fo, base_link_idx)) + spider->conns[link_idx] = conn; + if (spider_bit_is_set(spider->conn_can_fo, link_idx)) conn->use_for_active_standby = TRUE; } } @@ -777,26 +775,26 @@ SPIDER_CONN *spider_get_conn( } } else if (spider) { - spider->conns[base_link_idx] = conn; - if (spider_bit_is_set(spider->conn_can_fo, base_link_idx)) + spider->conns[link_idx] = conn; + if (spider_bit_is_set(spider->conn_can_fo, link_idx)) conn->use_for_active_standby = TRUE; } - conn->link_idx = base_link_idx; + conn->link_idx = link_idx; if (conn->queued_connect) - spider_conn_queue_connect_rewrite(share, conn, link_idx); + spider_conn_queue_connect_rewrite(share, conn, all_link_idx); if (conn->queued_ping) { if (spider) - spider_conn_queue_ping_rewrite(spider, conn, base_link_idx); + spider_conn_queue_ping_rewrite(spider, conn, link_idx); else conn->queued_ping = FALSE; } if (unlikely(spider && spider->wide_handler->top_share && (*error_num = spider_conn_queue_loop_check( - conn, spider, base_link_idx)))) + conn, spider, link_idx)))) { goto error; } @@ -1218,7 +1216,7 @@ int spider_conn_queue_loop_check( int link_idx ) { int error_num = HA_ERR_OUT_OF_MEM; - uint conn_link_idx = spider->conn_link_idx[link_idx], buf_sz; + uint all_link_idx = spider->conn_link_idx[link_idx], buf_sz; char path[FN_REFLEN + 1]; char *tmp_name, *cur_name, *to_name, *full_name, *from_value, *merged_value; @@ -1322,8 +1320,8 @@ int spider_conn_queue_loop_check( is the remote data node table */ to_str.length = build_table_filename(path, FN_REFLEN, - share->tgt_dbs[conn_link_idx] ? share->tgt_dbs[conn_link_idx] : "", - share->tgt_table_names[conn_link_idx], "", 0); + share->tgt_dbs[all_link_idx] ? share->tgt_dbs[all_link_idx] : "", + share->tgt_table_names[all_link_idx], "", 0); to_str.str = path; DBUG_PRINT("info", ("spider to=%s", to_str.str)); buf_sz = from_str.length + top_share->path.length + to_str.length + 3; @@ -3908,10 +3906,10 @@ bool spider_conn_need_open_handler( SPIDER_CONN* spider_get_conn_from_idle_connection( SPIDER_SHARE *share, - int link_idx, + int all_link_idx, char *conn_key, ha_spider *spider, - int base_link_idx, + int link_idx, int *error_num ) { @@ -3930,8 +3928,8 @@ SPIDER_CONN* spider_get_conn_from_idle_connection( pthread_mutex_lock(&spider_ipport_conn_mutex); if ((ip_port_conn = (SPIDER_IP_PORT_CONN*) my_hash_search_using_hash_value( - &spider_ipport_conns, share->conn_keys_hash_value[link_idx], - (uchar*) share->conn_keys[link_idx], share->conn_keys_lengths[link_idx]))) + &spider_ipport_conns, share->conn_keys_hash_value[all_link_idx], + (uchar*) share->conn_keys[all_link_idx], share->conn_keys_lengths[all_link_idx]))) { /* exists */ pthread_mutex_unlock(&spider_ipport_conn_mutex); pthread_mutex_lock(&ip_port_conn->mutex); @@ -3971,9 +3969,9 @@ SPIDER_CONN* spider_get_conn_from_idle_connection( pthread_mutex_lock(&spider_conn_mutex); if ((conn = (SPIDER_CONN*) my_hash_search_using_hash_value( - &spider_open_connections, share->conn_keys_hash_value[link_idx], - (uchar*) share->conn_keys[link_idx], - share->conn_keys_lengths[link_idx]))) + &spider_open_connections, share->conn_keys_hash_value[all_link_idx], + (uchar*) share->conn_keys[all_link_idx], + share->conn_keys_lengths[all_link_idx]))) { /* get conn from spider_open_connections, then delete conn in spider_open_connections */ my_hash_delete(&spider_open_connections, (uchar*) conn); @@ -3981,8 +3979,8 @@ SPIDER_CONN* spider_get_conn_from_idle_connection( DBUG_PRINT("info",("spider get global conn")); if (spider) { - spider->conns[base_link_idx] = conn; - if (spider_bit_is_set(spider->conn_can_fo, base_link_idx)) + spider->conns[link_idx] = conn; + if (spider_bit_is_set(spider->conn_can_fo, link_idx)) conn->use_for_active_standby = TRUE; } DBUG_RETURN(conn); @@ -3998,14 +3996,14 @@ SPIDER_CONN* spider_get_conn_from_idle_connection( if (ip_port_conn) pthread_mutex_unlock(&ip_port_conn->mutex); DBUG_PRINT("info",("spider create new conn")); - if (!(conn= spider_create_conn(share, spider, link_idx, base_link_idx, + if (!(conn= spider_create_conn(share, spider, all_link_idx, link_idx, error_num))) DBUG_RETURN(conn); *conn->conn_key = *conn_key; if (spider) { - spider->conns[base_link_idx] = conn; - if (spider_bit_is_set(spider->conn_can_fo, base_link_idx)) + spider->conns[link_idx] = conn; + if (spider_bit_is_set(spider->conn_can_fo, link_idx)) conn->use_for_active_standby = TRUE; } } diff --git a/storage/spider/spd_conn.h b/storage/spider/spd_conn.h index ba3ca0ab62c..515fbdb7267 100644 --- a/storage/spider/spd_conn.h +++ b/storage/spider/spd_conn.h @@ -446,10 +446,10 @@ SPIDER_IP_PORT_CONN *spider_create_ipport_conn(SPIDER_CONN *conn); SPIDER_CONN* spider_get_conn_from_idle_connection ( SPIDER_SHARE *share, - int link_idx, + int all_link_idx, char *conn_key, ha_spider *spider, - int base_link_idx, + int link_idx, int *error_num ); void spider_free_ipport_conn(void *info); diff --git a/storage/spider/spd_db_include.h b/storage/spider/spd_db_include.h index 017b077f819..ff5d9915d5d 100644 --- a/storage/spider/spd_db_include.h +++ b/storage/spider/spd_db_include.h @@ -510,6 +510,7 @@ typedef struct spider_table_holder SPIDER_TABLE_HOLDER; typedef struct spider_link_idx_holder { spider_table_link_idx_holder *table_link_idx_holder; + /* The index of active link */ int link_idx; int link_status; spider_link_idx_holder *next_table; diff --git a/storage/spider/spd_db_mysql.cc b/storage/spider/spd_db_mysql.cc index 7883c63d9f0..dce7573567a 100644 --- a/storage/spider/spd_db_mysql.cc +++ b/storage/spider/spd_db_mysql.cc @@ -3050,7 +3050,7 @@ int spider_db_mbase::append_lock_tables( int error_num; ha_spider *tmp_spider; int lock_type; - uint conn_link_idx; + uint all_link_idx; int tmp_link_idx; SPIDER_LINK_FOR_HASH *tmp_link_for_hash; const char *db_name; @@ -3090,16 +3090,16 @@ int spider_db_mbase::append_lock_tables( tmp_spider->wide_handler->lock_type)); DBUG_RETURN(0); } - conn_link_idx = tmp_spider->conn_link_idx[tmp_link_idx]; + all_link_idx = tmp_spider->conn_link_idx[tmp_link_idx]; spider_mbase_share *db_share = (spider_mbase_share *) tmp_spider->share->dbton_share[conn->dbton_id]; - db_name = db_share->db_names_str[conn_link_idx].ptr(); - db_name_length = db_share->db_names_str[conn_link_idx].length(); + db_name = db_share->db_names_str[all_link_idx].ptr(); + db_name_length = db_share->db_names_str[all_link_idx].length(); db_name_charset = tmp_spider->share->access_charset; - table_name = db_share->table_names_str[conn_link_idx].ptr(); - table_name_length = db_share->table_names_str[conn_link_idx].length(); + table_name = db_share->table_names_str[all_link_idx].ptr(); + table_name_length = db_share->table_names_str[all_link_idx].length(); table_name_charset = tmp_spider->share->access_charset; if ((error_num = spider_db_mbase_utility-> diff --git a/storage/spider/spd_include.h b/storage/spider/spd_include.h index a99c40079f1..7e2f12b72ae 100644 --- a/storage/spider/spd_include.h +++ b/storage/spider/spd_include.h @@ -1004,8 +1004,12 @@ typedef struct st_spider_share FIXME: consider removing it and using `active_link_count` instead. */ uint link_count; - /* Number of all links, i.e. all remote servers for the spider - table. */ + /* + Number of all links, i.e. all remote servers for the spider + table or partition. + + There's also active_link_count + */ uint all_link_count; /* The bitmap size of ha_spider::conn_can_fo, where the ha_spider diff --git a/storage/spider/spd_ping_table.cc b/storage/spider/spd_ping_table.cc index 4aeba9d77d6..12b53722af1 100644 --- a/storage/spider/spd_ping_table.cc +++ b/storage/spider/spd_ping_table.cc @@ -1586,11 +1586,11 @@ int spider_ping_table_mon_from_table( SPIDER_TRX *trx, THD *thd, SPIDER_SHARE *share, - int base_link_idx, + int link_idx, /* TODO: unused */ uint32 server_id, char *conv_name, /* Usually fully qualified table name */ uint conv_name_length, - int link_idx, /* The link id to ping */ + int all_link_idx, /* The link id to ping */ char *where_clause, uint where_clause_length, long monitoring_kind, @@ -1634,14 +1634,14 @@ int spider_ping_table_mon_from_table( DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM); } - if (share->static_link_ids[link_idx]) + if (share->static_link_ids[all_link_idx]) { - memcpy(link_idx_str, share->static_link_ids[link_idx], - share->static_link_ids_lengths[link_idx] + 1); - link_idx_str_length = share->static_link_ids_lengths[link_idx]; + memcpy(link_idx_str, share->static_link_ids[all_link_idx], + share->static_link_ids_lengths[all_link_idx] + 1); + link_idx_str_length = share->static_link_ids_lengths[all_link_idx]; } else { link_idx_str_length = my_sprintf(link_idx_str, (link_idx_str, "%010d", - link_idx)); + all_link_idx)); } char *buf = (char *) my_alloca(conv_name_length + link_idx_str_length + 1); if (!buf) @@ -1670,9 +1670,9 @@ int spider_ping_table_mon_from_table( /* Get or create `table_mon_list' for `conv_name_str'. */ if (!(table_mon_list = spider_get_ping_table_mon_list(trx, thd, - &conv_name_str, conv_name_length, link_idx, - share->static_link_ids[link_idx], - share->static_link_ids_lengths[link_idx], + &conv_name_str, conv_name_length, all_link_idx, + share->static_link_ids[all_link_idx], + share->static_link_ids_lengths[all_link_idx], server_id, need_lock, &error_num))) { my_afree(buf); @@ -1684,7 +1684,7 @@ int spider_ping_table_mon_from_table( DBUG_PRINT("info", ("spider share->link_statuses[%d]=SPIDER_LINK_STATUS_NG", link_idx)); pthread_mutex_lock(&spider_udf_table_mon_mutexes[table_mon_list->mutex_hash]); - share->link_statuses[link_idx] = SPIDER_LINK_STATUS_NG; + share->link_statuses[all_link_idx] = SPIDER_LINK_STATUS_NG; pthread_mutex_unlock(&spider_udf_table_mon_mutexes[table_mon_list->mutex_hash]); error_num = ER_SPIDER_LINK_MON_NG_NUM; my_printf_error(error_num, @@ -1745,7 +1745,7 @@ int spider_ping_table_mon_from_table( ) { if (!spider_db_udf_ping_table_mon_next( thd, table_mon, mon_conn, &mon_table_result, conv_name, - conv_name_length, link_idx, + conv_name_length, all_link_idx, where_clause, where_clause_length, /*first_sid=*/-1, table_mon_list->list_size, 0, 0, 0, flags, monitoring_limit)) { @@ -1761,11 +1761,11 @@ int spider_ping_table_mon_from_table( DBUG_PRINT("info", ( "spider share->link_statuses[%d]=SPIDER_LINK_STATUS_NG", link_idx)); - share->link_statuses[link_idx] = SPIDER_LINK_STATUS_NG; + share->link_statuses[all_link_idx] = SPIDER_LINK_STATUS_NG; spider_sys_update_tables_link_status(thd, conv_name, - conv_name_length, link_idx, SPIDER_LINK_STATUS_NG, need_lock); + conv_name_length, all_link_idx, SPIDER_LINK_STATUS_NG, need_lock); spider_sys_log_tables_link_failed(thd, conv_name, - conv_name_length, link_idx, need_lock); + conv_name_length, all_link_idx, need_lock); } pthread_mutex_unlock(&spider_udf_table_mon_mutexes[table_mon_list->mutex_hash]); } diff --git a/storage/spider/spd_ping_table.h b/storage/spider/spd_ping_table.h index 586ee7afde2..d12976563dd 100644 --- a/storage/spider/spd_ping_table.h +++ b/storage/spider/spd_ping_table.h @@ -105,11 +105,11 @@ int spider_ping_table_mon_from_table( SPIDER_TRX *trx, THD *thd, SPIDER_SHARE *share, - int base_link_idx, + int link_idx, uint32 server_id, char *conv_name, uint conv_name_length, - int link_idx, + int all_link_idx, char *where_clause, uint where_clause_length, long monitoring_kind, diff --git a/storage/spider/spd_trx.cc b/storage/spider/spd_trx.cc index 9956f016673..39432d0f6d2 100644 --- a/storage/spider/spd_trx.cc +++ b/storage/spider/spd_trx.cc @@ -3638,43 +3638,43 @@ void spider_reuse_trx_ha( void spider_trx_set_link_idx_for_all( ha_spider *spider ) { - int roop_count, roop_count2; SPIDER_SHARE *share = spider->share; long *link_statuses = share->link_statuses; uint *conn_link_idx = spider->conn_link_idx; - int link_count = share->link_count; - int all_link_count = share->all_link_count; + uint link_count = share->link_count; + uint all_link_count = share->all_link_count; uchar *conn_can_fo = spider->conn_can_fo; DBUG_ENTER("spider_trx_set_link_idx_for_all"); DBUG_PRINT("info",("spider set link_count=%d", link_count)); DBUG_PRINT("info",("spider set all_link_count=%d", all_link_count)); memset(conn_can_fo, 0, sizeof(uchar) * share->link_bitmap_size); - for (roop_count = 0; roop_count < link_count; roop_count++) + for (uint link_idx = 0; link_idx < link_count; link_idx++) { - for (roop_count2 = roop_count; roop_count2 < all_link_count; - roop_count2 += link_count) + uint all_link_idx; + for (all_link_idx = link_idx; all_link_idx < all_link_count; + all_link_idx += link_count) { - if (link_statuses[roop_count2] <= SPIDER_LINK_STATUS_RECOVERY) + if (link_statuses[all_link_idx] <= SPIDER_LINK_STATUS_RECOVERY) break; } - if (roop_count2 < all_link_count) + if (all_link_idx < all_link_count) { - conn_link_idx[roop_count] = roop_count2; - if (roop_count2 + link_count < all_link_count) - spider_set_bit(conn_can_fo, roop_count); + conn_link_idx[link_idx] = all_link_idx; + if (all_link_idx + link_count < all_link_count) + spider_set_bit(conn_can_fo, link_idx); DBUG_PRINT("info",("spider set conn_link_idx[%d]=%d", - roop_count, roop_count2)); + link_idx, all_link_idx)); } else { - conn_link_idx[roop_count] = roop_count; + conn_link_idx[link_idx] = link_idx; DBUG_PRINT("info",("spider set2 conn_link_idx[%d]=%d", - roop_count, roop_count)); + link_idx, link_idx)); } - spider->conn_keys[roop_count] = + spider->conn_keys[link_idx] = ADD_TO_PTR(spider->conn_keys_first_ptr, - PTR_BYTE_DIFF(share->conn_keys[conn_link_idx[roop_count]], + PTR_BYTE_DIFF(share->conn_keys[conn_link_idx[link_idx]], share->conn_keys[0]), char*); DBUG_PRINT("info",("spider conn_keys[%d]=%s", - roop_count, spider->conn_keys[roop_count])); + link_idx, spider->conn_keys[link_idx])); } DBUG_VOID_RETURN; } From 31d97c3cda7363fa465c04cdb826aa72ff1b47ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 22 Oct 2025 09:24:54 +0300 Subject: [PATCH 03/54] MDEV-20203 assert_block_ahi_valid() fails in btr_search_update_hash_ref() btr_search_update_hash_ref(): Check the consistency of block->index and block->n_pointers only while holding the partition latch. Reviewed by: Thirunarayanan Balathandayuthapani Tested by: Saahil Alam --- storage/innobase/btr/btr0sea.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index c74b7fdfc3f..04a278dce05 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -687,7 +687,6 @@ btr_search_update_hash_ref( ut_ad(block->page.lock.have_x() || block->page.lock.have_s()); ut_ad(btr_cur_get_page(cursor) == block->page.frame); ut_ad(page_is_leaf(block->page.frame)); - assert_block_ahi_valid(block); dict_index_t* index = block->index; @@ -706,8 +705,9 @@ btr_search_update_hash_ref( ut_ad(!dict_index_is_ibuf(index)); auto part = btr_search_sys.get_part(*index); part->latch.wr_lock(SRW_LOCK_CALL); - ut_ad(!block->index || block->index == index); - +#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG + ut_a(block->index ? block->index == index : !block->n_pointers); +#endif if (block->index && (block->curr_n_fields == info->n_fields) && (block->curr_n_bytes == info->n_bytes) From 315b60e885f2e9fa5242dbc62b5f69d536665edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 22 Oct 2025 09:25:18 +0300 Subject: [PATCH 04/54] MDEV-26599 Assertion `!table->id' failed in btr_search_lazy_free btr_search_lazy_free(): Check for !table->id. It is possible that dict_sys_t::remove(table, ...) has started executing but has not reached the final part yet. If that is the case, let dict_sys_t::remove() observe that table->freed_indexes is empty and let it free the table object. Reviewed by: Thirunarayanan Balathandayuthapani Tested by: Saahil Alam --- storage/innobase/btr/btr0sea.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index 04a278dce05..ecec0331573 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -205,18 +205,16 @@ ATTRIBUTE_COLD static void btr_search_lazy_free(dict_index_t *index) UT_LIST_REMOVE(table->freed_indexes, index); index->lock.free(); dict_mem_index_free(index); + const bool destroy= !table->id && !UT_LIST_GET_LEN(table->freed_indexes) && + !UT_LIST_GET_LEN(table->indexes); + table->autoinc_mutex.wr_unlock(); - if (!UT_LIST_GET_LEN(table->freed_indexes) && - !UT_LIST_GET_LEN(table->indexes)) + if (destroy) { - ut_ad(!table->id); - table->autoinc_mutex.wr_unlock(); table->autoinc_mutex.destroy(); dict_mem_table_free(table); return; } - - table->autoinc_mutex.wr_unlock(); } /** Disable the adaptive hash search system and empty the index. */ From c083f191b4b1671f8ac10b7eed53caee8f128482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 22 Oct 2025 09:33:53 +0300 Subject: [PATCH 05/54] MDEV-37672: Remove innodb_trx_rseg_n_slots_debug The debug parameter innodb_trx_rseg_n_slots_debug is not compatible with the bug fix that was implemented in MDEV-30671 and last revised in MDEV-33213, which leads to bogus assertion failures in trx_assign_rseg_low(), regarding look_for_rollover. When needed, this parameter can be better simulated by adding a DBUG_EXECUTE_IF to trx_undo_seg_create() or one of its callers. --- .../suite/innodb/r/innodb_bug12400341.result | 18 ---- .../suite/innodb/t/innodb_bug12400341.test | 102 ------------------ .../suite/perfschema/t/show_sanity.test | 1 - ...innodb_trx_rseg_n_slots_debug_basic.result | 65 ----------- .../suite/sys_vars/r/sysvars_innodb.result | 12 --- .../innodb_trx_rseg_n_slots_debug_basic.test | 59 ---------- storage/innobase/handler/ha_innodb.cc | 6 -- storage/innobase/include/trx0sys.h | 5 - storage/innobase/trx/trx0purge.cc | 1 - storage/innobase/trx/trx0sys.cc | 3 - storage/innobase/trx/trx0trx.cc | 2 - storage/innobase/trx/trx0undo.cc | 5 - 12 files changed, 279 deletions(-) delete mode 100644 mysql-test/suite/innodb/r/innodb_bug12400341.result delete mode 100644 mysql-test/suite/innodb/t/innodb_bug12400341.test delete mode 100644 mysql-test/suite/sys_vars/r/innodb_trx_rseg_n_slots_debug_basic.result delete mode 100644 mysql-test/suite/sys_vars/t/innodb_trx_rseg_n_slots_debug_basic.test diff --git a/mysql-test/suite/innodb/r/innodb_bug12400341.result b/mysql-test/suite/innodb/r/innodb_bug12400341.result deleted file mode 100644 index f4114595819..00000000000 --- a/mysql-test/suite/innodb/r/innodb_bug12400341.result +++ /dev/null @@ -1,18 +0,0 @@ -call mtr.add_suppression("\\[Warning\\] InnoDB: Cannot find a free slot for an undo log. Do you have too"); -drop database if exists mysqltest; -create database mysqltest; -CREATE TABLE mysqltest.transtable (id int unsigned NOT NULL PRIMARY KEY, val int DEFAULT 0) ENGINE=InnoDB; -select count(*) from information_schema.processlist where command != 'Daemon'; -count(*) -33 -connection default; -CREATE TABLE mysqltest.testtable (id int unsigned not null primary key) ENGINE=InnoDB; -ERROR HY000: Can't create table `mysqltest`.`testtable` (errno: 177 "Too many active concurrent transactions") -select count(*) from information_schema.processlist where command != 'Daemon'; -count(*) -33 -connection default; -select count(*) from information_schema.processlist where command != 'Daemon'; -count(*) -33 -drop database mysqltest; diff --git a/mysql-test/suite/innodb/t/innodb_bug12400341.test b/mysql-test/suite/innodb/t/innodb_bug12400341.test deleted file mode 100644 index 13eadc70bee..00000000000 --- a/mysql-test/suite/innodb/t/innodb_bug12400341.test +++ /dev/null @@ -1,102 +0,0 @@ -# Test for bug #12400341: INNODB CAN LEAVE ORPHAN IBD FILES AROUND - --- source include/have_debug.inc --- source include/have_innodb.inc --- source include/have_innodb_16k.inc - -# Don't test under valgrind, undo slots of the previous test might exist still -# and cause unstable result. ---source include/not_valgrind.inc -# undo slots of the previous test might exist still ---source include/not_windows.inc - -call mtr.add_suppression("\\[Warning\\] InnoDB: Cannot find a free slot for an undo log. Do you have too"); - ---disable_query_log -set @old_innodb_trx_rseg_n_slots_debug = @@innodb_trx_rseg_n_slots_debug; -set global innodb_trx_rseg_n_slots_debug = 32; ---enable_query_log - ---disable_warnings -drop database if exists mysqltest; ---enable_warnings - -create database mysqltest; -CREATE TABLE mysqltest.transtable (id int unsigned NOT NULL PRIMARY KEY, val int DEFAULT 0) ENGINE=InnoDB; - ---disable_query_log -# -# Insert in 1 transaction which needs over 1 page undo record to avoid the insert_undo cached, -# because the cached insert_undo can be reused at "CREATE TABLE" statement later. -# -START TRANSACTION; -let $c = 1024; -while ($c) -{ - eval INSERT INTO mysqltest.transtable (id) VALUES ($c); - dec $c; -} -COMMIT; - -let $c = 32; -while ($c) -{ - # if failed at here, it might be shortage of file descriptors limit. - connect (con$c,localhost,root,,); - dec $c; -} ---enable_query_log - -select count(*) from information_schema.processlist where command != 'Daemon'; - -# -# fill the all undo slots -# ---disable_query_log -let $c = 32; -while ($c) -{ - connection con$c; - START TRANSACTION; - eval UPDATE mysqltest.transtable SET val = 1 WHERE id = 33 - $c; - dec $c; -} ---enable_query_log - -connection default; - ---error ER_CANT_CREATE_TABLE -CREATE TABLE mysqltest.testtable (id int unsigned not null primary key) ENGINE=InnoDB; - -select count(*) from information_schema.processlist where command != 'Daemon'; - ---disable_query_log -let $c = 32; -while ($c) -{ - connection con$c; - ROLLBACK; - dec $c; -} ---enable_query_log - -connection default; -select count(*) from information_schema.processlist where command != 'Daemon'; - ---disable_query_log -let $c = 32; -while ($c) -{ - disconnect con$c; - dec $c; -} ---enable_query_log - -# -# If the isolated .ibd file remained, the drop database should fail. -# -drop database mysqltest; - ---disable_query_log -set global innodb_trx_rseg_n_slots_debug = @old_innodb_trx_rseg_n_slots_debug; ---enable_query_log diff --git a/mysql-test/suite/perfschema/t/show_sanity.test b/mysql-test/suite/perfschema/t/show_sanity.test index 171bbfa8bd6..3f5a5ddfb62 100644 --- a/mysql-test/suite/perfschema/t/show_sanity.test +++ b/mysql-test/suite/perfschema/t/show_sanity.test @@ -491,7 +491,6 @@ insert into test.sanity values ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_SYNC_SPIN_LOOPS"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_TEMP_DATA_FILE_PATH"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_TRX_PURGE_VIEW_UPDATE_ONLY_DEBUG"), - ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_TRX_RSEG_N_SLOTS_DEBUG"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_UNDO_DIRECTORY"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_UNDO_LOG_TRUNCATE"), ("JUNK: GLOBAL-ONLY", "I_S.SESSION_VARIABLES", "INNODB_UNDO_TABLESPACES"), diff --git a/mysql-test/suite/sys_vars/r/innodb_trx_rseg_n_slots_debug_basic.result b/mysql-test/suite/sys_vars/r/innodb_trx_rseg_n_slots_debug_basic.result deleted file mode 100644 index 7e253c869e3..00000000000 --- a/mysql-test/suite/sys_vars/r/innodb_trx_rseg_n_slots_debug_basic.result +++ /dev/null @@ -1,65 +0,0 @@ -SET @start_global_value = @@global.innodb_trx_rseg_n_slots_debug; -SELECT @start_global_value; -@start_global_value -0 -select @@global.innodb_trx_rseg_n_slots_debug between 0 and 1024; -@@global.innodb_trx_rseg_n_slots_debug between 0 and 1024 -1 -select @@global.innodb_trx_rseg_n_slots_debug; -@@global.innodb_trx_rseg_n_slots_debug -0 -select @@session.innodb_trx_rseg_n_slots_debug; -ERROR HY000: Variable 'innodb_trx_rseg_n_slots_debug' is a GLOBAL variable -show global variables like 'innodb_trx_rseg_n_slots_debug'; -Variable_name Value -innodb_trx_rseg_n_slots_debug 0 -show session variables like 'innodb_trx_rseg_n_slots_debug'; -Variable_name Value -innodb_trx_rseg_n_slots_debug 0 -select * from information_schema.global_variables where variable_name='innodb_trx_rseg_n_slots_debug'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_TRX_RSEG_N_SLOTS_DEBUG 0 -select * from information_schema.session_variables where variable_name='innodb_trx_rseg_n_slots_debug'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_TRX_RSEG_N_SLOTS_DEBUG 0 -set global innodb_trx_rseg_n_slots_debug=1; -select @@global.innodb_trx_rseg_n_slots_debug; -@@global.innodb_trx_rseg_n_slots_debug -1 -select * from information_schema.global_variables where variable_name='innodb_trx_rseg_n_slots_debug'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_TRX_RSEG_N_SLOTS_DEBUG 1 -select * from information_schema.session_variables where variable_name='innodb_trx_rseg_n_slots_debug'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_TRX_RSEG_N_SLOTS_DEBUG 1 -set @@global.innodb_trx_rseg_n_slots_debug=0; -select @@global.innodb_trx_rseg_n_slots_debug; -@@global.innodb_trx_rseg_n_slots_debug -0 -select * from information_schema.global_variables where variable_name='innodb_trx_rseg_n_slots_debug'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_TRX_RSEG_N_SLOTS_DEBUG 0 -select * from information_schema.session_variables where variable_name='innodb_trx_rseg_n_slots_debug'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_TRX_RSEG_N_SLOTS_DEBUG 0 -set session innodb_trx_rseg_n_slots_debug='some'; -ERROR HY000: Variable 'innodb_trx_rseg_n_slots_debug' is a GLOBAL variable and should be set with SET GLOBAL -set @@session.innodb_trx_rseg_n_slots_debug='some'; -ERROR HY000: Variable 'innodb_trx_rseg_n_slots_debug' is a GLOBAL variable and should be set with SET GLOBAL -set global innodb_trx_rseg_n_slots_debug=1.1; -ERROR 42000: Incorrect argument type to variable 'innodb_trx_rseg_n_slots_debug' -set global innodb_trx_rseg_n_slots_debug='foo'; -ERROR 42000: Incorrect argument type to variable 'innodb_trx_rseg_n_slots_debug' -set global innodb_trx_rseg_n_slots_debug=-2; -Warnings: -Warning 1292 Truncated incorrect innodb_trx_rseg_n_slots_debug value: '-2' -set global innodb_trx_rseg_n_slots_debug=1e1; -ERROR 42000: Incorrect argument type to variable 'innodb_trx_rseg_n_slots_debug' -set global innodb_trx_rseg_n_slots_debug=1024; -set global innodb_trx_rseg_n_slots_debug=1025; -Warnings: -Warning 1292 Truncated incorrect innodb_trx_rseg_n_slots_debug value: '1025' -SET @@global.innodb_trx_rseg_n_slots_debug = @start_global_value; -SELECT @@global.innodb_trx_rseg_n_slots_debug; -@@global.innodb_trx_rseg_n_slots_debug -0 diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index 032dde519cf..3b95064abd3 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -1663,18 +1663,6 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST OFF,ON READ_ONLY NO COMMAND_LINE_ARGUMENT NULL -VARIABLE_NAME INNODB_TRX_RSEG_N_SLOTS_DEBUG -SESSION_VALUE NULL -DEFAULT_VALUE 0 -VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE INT UNSIGNED -VARIABLE_COMMENT Debug flags for InnoDB to limit TRX_RSEG_N_SLOTS for trx_rsegf_undo_find_free() -NUMERIC_MIN_VALUE 0 -NUMERIC_MAX_VALUE 1024 -NUMERIC_BLOCK_SIZE 0 -ENUM_VALUE_LIST NULL -READ_ONLY NO -COMMAND_LINE_ARGUMENT NULL VARIABLE_NAME INNODB_UNDO_DIRECTORY SESSION_VALUE NULL DEFAULT_VALUE diff --git a/mysql-test/suite/sys_vars/t/innodb_trx_rseg_n_slots_debug_basic.test b/mysql-test/suite/sys_vars/t/innodb_trx_rseg_n_slots_debug_basic.test deleted file mode 100644 index 858e1b63908..00000000000 --- a/mysql-test/suite/sys_vars/t/innodb_trx_rseg_n_slots_debug_basic.test +++ /dev/null @@ -1,59 +0,0 @@ ---source include/have_innodb.inc ---source include/have_debug.inc - -SET @start_global_value = @@global.innodb_trx_rseg_n_slots_debug; -SELECT @start_global_value; - -# -# exists as global only -# -select @@global.innodb_trx_rseg_n_slots_debug between 0 and 1024; -select @@global.innodb_trx_rseg_n_slots_debug; ---error ER_INCORRECT_GLOBAL_LOCAL_VAR -select @@session.innodb_trx_rseg_n_slots_debug; -show global variables like 'innodb_trx_rseg_n_slots_debug'; -show session variables like 'innodb_trx_rseg_n_slots_debug'; ---disable_warnings -select * from information_schema.global_variables where variable_name='innodb_trx_rseg_n_slots_debug'; -select * from information_schema.session_variables where variable_name='innodb_trx_rseg_n_slots_debug'; ---enable_warnings - -# -# show that it's writable -# -set global innodb_trx_rseg_n_slots_debug=1; -select @@global.innodb_trx_rseg_n_slots_debug; ---disable_warnings -select * from information_schema.global_variables where variable_name='innodb_trx_rseg_n_slots_debug'; -select * from information_schema.session_variables where variable_name='innodb_trx_rseg_n_slots_debug'; ---enable_warnings -set @@global.innodb_trx_rseg_n_slots_debug=0; -select @@global.innodb_trx_rseg_n_slots_debug; ---disable_warnings -select * from information_schema.global_variables where variable_name='innodb_trx_rseg_n_slots_debug'; -select * from information_schema.session_variables where variable_name='innodb_trx_rseg_n_slots_debug'; ---enable_warnings ---error ER_GLOBAL_VARIABLE -set session innodb_trx_rseg_n_slots_debug='some'; ---error ER_GLOBAL_VARIABLE -set @@session.innodb_trx_rseg_n_slots_debug='some'; - -# -# incorrect types -# ---error ER_WRONG_TYPE_FOR_VAR -set global innodb_trx_rseg_n_slots_debug=1.1; ---error ER_WRONG_TYPE_FOR_VAR -set global innodb_trx_rseg_n_slots_debug='foo'; -set global innodb_trx_rseg_n_slots_debug=-2; ---error ER_WRONG_TYPE_FOR_VAR -set global innodb_trx_rseg_n_slots_debug=1e1; -set global innodb_trx_rseg_n_slots_debug=1024; -set global innodb_trx_rseg_n_slots_debug=1025; - -# -# Cleanup -# - -SET @@global.innodb_trx_rseg_n_slots_debug = @start_global_value; -SELECT @@global.innodb_trx_rseg_n_slots_debug; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 19582b79b2e..7ce5b4983fc 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -19623,11 +19623,6 @@ static MYSQL_SYSVAR_ENUM(default_row_format, innodb_default_row_format, &innodb_default_row_format_typelib); #ifdef UNIV_DEBUG -static MYSQL_SYSVAR_UINT(trx_rseg_n_slots_debug, trx_rseg_n_slots_debug, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_NOCMDOPT, - "Debug flags for InnoDB to limit TRX_RSEG_N_SLOTS for trx_rsegf_undo_find_free()", - NULL, NULL, 0, 0, 1024, 0); - static MYSQL_SYSVAR_UINT(limit_optimistic_insert_debug, btr_cur_limit_optimistic_insert_debug, PLUGIN_VAR_RQCMDARG, "Artificially limit the number of records per B-tree page (0=unlimited).", @@ -19900,7 +19895,6 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(compression_pad_pct_max), MYSQL_SYSVAR(default_row_format), #ifdef UNIV_DEBUG - MYSQL_SYSVAR(trx_rseg_n_slots_debug), MYSQL_SYSVAR(limit_optimistic_insert_debug), MYSQL_SYSVAR(trx_purge_view_update_only_debug), MYSQL_SYSVAR(evict_tables_on_commit_debug), diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 3ae2e0b5305..8a72199284d 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -70,11 +70,6 @@ inline buf_block_t *trx_sysf_get(mtr_t* mtr, bool rw= true) 0, rw ? RW_X_LATCH : RW_S_LATCH, mtr); } -#ifdef UNIV_DEBUG -/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ -extern uint trx_rseg_n_slots_debug; -#endif - /** Write DB_TRX_ID. @param[out] db_trx_id the DB_TRX_ID field to be written to @param[in] id transaction ID */ diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 9e8b256ffb6..8ac3f93cd15 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -437,7 +437,6 @@ loop: rollback segment. */ if (!(rseg.SKIP & rseg_ref) && !freed && - ut_d(!trx_rseg_n_slots_debug &&) &rseg == &trx_sys.rseg_array[purge_sys.skipped_rseg]) /* If rseg.space == purge_sys.truncate_undo_space.current the following will be a no-op. A possible conflict diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 68c3e79a3d1..0bd9a06bd44 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -45,9 +45,6 @@ Created 3/26/1996 Heikki Tuuri trx_sys_t trx_sys; #ifdef UNIV_DEBUG -/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ -uint trx_rseg_n_slots_debug = 0; - void rw_trx_hash_t::validate_element(trx_t *trx) { ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg); diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 560489cd9d0..e2adc085c53 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -802,7 +802,6 @@ static void trx_assign_rseg_low(trx_t *trx) undo tablespaces that are scheduled for truncation. */ static Atomic_counter rseg_slot; unsigned slot = rseg_slot++ % TRX_SYS_N_RSEGS; - ut_d(if (trx_rseg_n_slots_debug) slot = 0); ut_d(const auto start_scan_slot = slot); ut_d(bool look_for_rollover = false); trx_rseg_t* rseg; @@ -814,7 +813,6 @@ static void trx_assign_rseg_low(trx_t *trx) rseg = &trx_sys.rseg_array[slot]; ut_ad(!look_for_rollover || start_scan_slot != slot); ut_d(look_for_rollover = true); - ut_d(if (!trx_rseg_n_slots_debug)) slot = (slot + 1) % TRX_SYS_N_RSEGS; if (!rseg->space) { diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 1751bba49e1..7c855bf2044 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -434,11 +434,6 @@ static ulint trx_rsegf_undo_find_free(const buf_block_t *rseg_header) { ulint max_slots= TRX_RSEG_N_SLOTS; -#ifdef UNIV_DEBUG - if (trx_rseg_n_slots_debug) - max_slots= std::min(trx_rseg_n_slots_debug, TRX_RSEG_N_SLOTS); -#endif - for (ulint i= 0; i < max_slots; i++) if (trx_rsegf_get_nth_undo(rseg_header, i) == FIL_NULL) return i; From 14720ec444855585c9f905d40fab4886a4ac950a Mon Sep 17 00:00:00 2001 From: Oleg Smirnov Date: Wed, 15 Oct 2025 00:00:58 +0700 Subject: [PATCH 06/54] MDEV-29874: FederatedX error 10000 on multi-table UPDATE/DELETE Multi-table UPDATE and DELETE statements employ mysql_select() calls during their processing, so the server may try to instantiate `select_handler` in an attempt to push down the statement to a foreign engine. However, the current implementation of `select_handler` for FederatedX pushes down the whole query and not only its select part (`thd->query()`, see `int ha_federatedx_select_handler::init_scan()`). FederatedX engine does not support execution of DML statements on the remote side, that is why the error occured. Solution: - Add an extra check to only allow SELECT statements pushdown to FederatedX --- .../federatedx_create_handlers.result | 35 +++++++++++++++ .../federated/federatedx_create_handlers.test | 44 +++++++++++++++++++ storage/federatedx/federatedx_pushdown.cc | 8 +++- 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/federated/federatedx_create_handlers.result b/mysql-test/suite/federated/federatedx_create_handlers.result index d402bd5ccb1..4c8f2ac68bb 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.result +++ b/mysql-test/suite/federated/federatedx_create_handlers.result @@ -606,6 +606,41 @@ id name 4 xxx 5 yyy DEALLOCATE PREPARE stmt; +# +# FederatedX error 10000 on multi-table UPDATE/DELETE +# +connection slave; +DROP TABLE IF EXISTS federated.t1, federated.t2; +CREATE TABLE federated.t1 (a int, b int); +INSERT INTO federated.t1 VALUES (1,1), (2,2), (3,3); +CREATE TABLE federated.t2 (a int, b int); +INSERT INTO federated.t2 VALUES (1,1), (2,2), (4,4); +connection master; +DROP TABLE IF EXISTS federated.t1, federated.t2; +CREATE TABLE federated.t1 (a int, b int) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +CREATE TABLE federated.t2 (a int, b int) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t2'; +use federated; +# Multi-table UPDATE +UPDATE t1, t2 SET t1.a = 2 WHERE t1.a=t2.a; +# Check the result +SELECT * FROM t1; +a b +2 1 +2 2 +3 3 +# Multi-table DELETE +DELETE FROM t1 USING t1 JOIN t2 ON t1.a = t2.a WHERE t2.b > 1; +SELECT * FROM t1; +a b +3 3 +# Another form of multi-table DELETE +DELETE FROM a1 USING t1 AS a1; +SELECT * FROM t1; +a b set global federated_pushdown=0; connection master; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/suite/federated/federatedx_create_handlers.test b/mysql-test/suite/federated/federatedx_create_handlers.test index 4d6a43377b8..0b3167b2ae1 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.test +++ b/mysql-test/suite/federated/federatedx_create_handlers.test @@ -431,6 +431,50 @@ EXECUTE stmt; EXECUTE stmt; DEALLOCATE PREPARE stmt; +--echo # +--echo # FederatedX error 10000 on multi-table UPDATE/DELETE +--echo # + +connection slave; +DROP TABLE IF EXISTS federated.t1, federated.t2; + +CREATE TABLE federated.t1 (a int, b int); +INSERT INTO federated.t1 VALUES (1,1), (2,2), (3,3); + +CREATE TABLE federated.t2 (a int, b int); +INSERT INTO federated.t2 VALUES (1,1), (2,2), (4,4); + +connection master; +DROP TABLE IF EXISTS federated.t1, federated.t2; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +CREATE TABLE federated.t1 (a int, b int) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +CREATE TABLE federated.t2 (a int, b int) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2'; + +use federated; + +--echo # Multi-table UPDATE +UPDATE t1, t2 SET t1.a = 2 WHERE t1.a=t2.a; + +--echo # Check the result +SELECT * FROM t1; + +--echo # Multi-table DELETE +DELETE FROM t1 USING t1 JOIN t2 ON t1.a = t2.a WHERE t2.b > 1; + +SELECT * FROM t1; + +--echo # Another form of multi-table DELETE +DELETE FROM a1 USING t1 AS a1; + +SELECT * FROM t1; set global federated_pushdown=0; diff --git a/storage/federatedx/federatedx_pushdown.cc b/storage/federatedx/federatedx_pushdown.cc index e9a9791a859..e60331e8a62 100644 --- a/storage/federatedx/federatedx_pushdown.cc +++ b/storage/federatedx/federatedx_pushdown.cc @@ -227,10 +227,16 @@ void ha_federatedx_derived_handler::print_error(int, unsigned long) } +static bool is_supported_by_select_handler(enum_sql_command sql_command) +{ + return sql_command == SQLCOM_SELECT || sql_command == SQLCOM_INSERT_SELECT; +} + + static select_handler* create_federatedx_select_handler(THD* thd, SELECT_LEX *sel) { - if (!use_pushdown) + if (!use_pushdown || !is_supported_by_select_handler(thd->lex->sql_command)) return 0; ha_federatedx_select_handler* handler = NULL; From 11f61d9232144c9c5ee5da8ef3c254ba93368708 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Fri, 17 Oct 2025 15:21:45 +1100 Subject: [PATCH 07/54] MDEV-37568 Fix remote table key direction in spider/bugfix.index Ideally spider should throw an error when local and remote tables have conflict definitions. This fixes the test for --view-protocol and --mysqld=--loose-spider-disable-group-by-handler --- .../mysql-test/spider/bugfix/r/index.result | 20 +++++++++++++------ .../mysql-test/spider/bugfix/t/index.test | 6 ++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/storage/spider/mysql-test/spider/bugfix/r/index.result b/storage/spider/mysql-test/spider/bugfix/r/index.result index 7116a29eed8..396362ba404 100644 --- a/storage/spider/mysql-test/spider/bugfix/r/index.result +++ b/storage/spider/mysql-test/spider/bugfix/r/index.result @@ -10,19 +10,27 @@ set global spider_same_server_link= on; select @@spider_auto_increment_mode; @@spider_auto_increment_mode 0 -create or replace table auto_test_local.t (id int primary key) engine=InnoDB; +create or replace table auto_test_local.t (id int, primary key(id desc)) engine=InnoDB; create or replace table t_sp1 (id int auto_increment, primary key(id desc)) engine=Spider COMMENT='wrapper "mysql", srv "s_1", table "t"'; insert into t_sp1 () values (),(),(); insert into t_sp1 () values (),(),(); +select * from auto_test_local.t; +id +6 +5 +4 +3 +2 +1 select * from t_sp1; id -1 -2 -3 -4 -5 6 +5 +4 +3 +2 +1 drop table t_sp1, auto_test_local.t; # # MDEV-27581 Wrong result with DESC key on partitioned Spider table diff --git a/storage/spider/mysql-test/spider/bugfix/t/index.test b/storage/spider/mysql-test/spider/bugfix/t/index.test index 28c25fab7c9..16e6e473fcf 100644 --- a/storage/spider/mysql-test/spider/bugfix/t/index.test +++ b/storage/spider/mysql-test/spider/bugfix/t/index.test @@ -12,15 +12,13 @@ set global spider_same_server_link= on; --echo # select @@spider_auto_increment_mode; -create or replace table auto_test_local.t (id int primary key) engine=InnoDB; +create or replace table auto_test_local.t (id int, primary key(id desc)) engine=InnoDB; create or replace table t_sp1 (id int auto_increment, primary key(id desc)) engine=Spider COMMENT='wrapper "mysql", srv "s_1", table "t"'; insert into t_sp1 () values (),(),(); insert into t_sp1 () values (),(),(); -# MDEV-37568 ---disable_view_protocol +select * from auto_test_local.t; select * from t_sp1; ---enable_view_protocol drop table t_sp1, auto_test_local.t; --echo # From 4d8429256977e724c1b3102e612ca71633dffa54 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Fri, 17 Oct 2025 14:15:16 +1100 Subject: [PATCH 08/54] MDEV-36325 MDEV-36357 Call limit_mode on spider_db_conn instead of spider_db_result in spider_db_store_result This prevents segv on NULL result_list->current->result on handler calls that are not the first. Reasons supporting this change: - spider_db_result::limit_mode is not called anywhere else. The only calls to limit_mode method are on spider_db_conn - it is very unlikely (impossible?) for the connection to change from one backend to another between execution of sql statements and storing result: /* in spider_bg_conn_action: */ if (dbton_handler->execute_sql( sql_type, conn, result_list->quick_mode, &spider->need_mons[conn->link_idx]) // [... 9 lines elided] if (!(result_list->bgs_error = spider_db_store_result(spider, conn->link_idx, result_list->table))) this also means it is very unlikely (impossible?) for the backend type (dbton_id) to differ between conn->db_conn and result_list->current->result, also considering that spider_db_result::dbton_id comes from spider_db_conn::dbton_id: spider_db_result::spider_db_result( SPIDER_DB_CONN *in_db_conn ) : db_conn(in_db_conn), dbton_id(in_db_conn->dbton_id) Since this was the only call to spider_db_result::limit_mode, we also remove the method altogether. --- storage/spider/mysql-test/spider/bg/t/basic_sql.test | 3 --- storage/spider/spd_db_conn.cc | 2 +- storage/spider/spd_db_include.cc | 7 ------- storage/spider/spd_db_include.h | 1 - 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/storage/spider/mysql-test/spider/bg/t/basic_sql.test b/storage/spider/mysql-test/spider/bg/t/basic_sql.test index 7b3ec715f86..0c9f6ce660d 100644 --- a/storage/spider/mysql-test/spider/bg/t/basic_sql.test +++ b/storage/spider/mysql-test/spider/bg/t/basic_sql.test @@ -476,11 +476,8 @@ SELECT count(*) FROM ta_l ORDER BY a; --enable_query_log --enable_result_log --connection master_1 -# MDEV-36357 ---disable_view_protocol SELECT a.a, a.b, date_format(a.c, '%Y-%m-%d %H:%i:%s') FROM tb_l a WHERE EXISTS (SELECT * FROM ta_l b WHERE b.b = a.b) ORDER BY a.a; ---enable_view_protocol --disable_query_log --disable_result_log --connection child2_1 diff --git a/storage/spider/spd_db_conn.cc b/storage/spider/spd_db_conn.cc index f55458ab1e1..667f97e0dd0 100644 --- a/storage/spider/spd_db_conn.cc +++ b/storage/spider/spd_db_conn.cc @@ -3104,7 +3104,7 @@ int spider_db_store_result( result_list->quick_phase == 2 ) { if (result_list->low_mem_read && - result_list->current->result->limit_mode() == 0) + conn->db_conn->limit_mode() == 0) { do { spider_db_free_one_result(result_list, diff --git a/storage/spider/spd_db_include.cc b/storage/spider/spd_db_include.cc index 0531f8a8ed9..8f3f6721ba6 100644 --- a/storage/spider/spd_db_include.cc +++ b/storage/spider/spd_db_include.cc @@ -47,13 +47,6 @@ int spider_db_result::fetch_table_checksum( DBUG_RETURN(0); } -uint spider_db_result::limit_mode() -{ - DBUG_ENTER("spider_db_result::limit_mode"); - DBUG_PRINT("info",("spider this=%p", this)); - DBUG_RETURN(spider_dbton[dbton_id].db_util->limit_mode()); -} - spider_db_conn::spider_db_conn( SPIDER_CONN *in_conn ) : conn(in_conn), dbton_id(in_conn->dbton_id) diff --git a/storage/spider/spd_db_include.h b/storage/spider/spd_db_include.h index fe014468f5c..cb2e2b18489 100644 --- a/storage/spider/spd_db_include.h +++ b/storage/spider/spd_db_include.h @@ -883,7 +883,6 @@ public: SPIDER_SHARE *spider_share, CHARSET_INFO *access_charset ) = 0; - virtual uint limit_mode(); }; class spider_db_conn From 41725b4cee671fecf091616a1cfc8ee37d67a00f Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Wed, 22 Oct 2025 23:08:50 +1100 Subject: [PATCH 09/54] MDEV-37810 Introduce combinations of gbh and usual handlers for all spider tests This also has the side benefits of catching --view-protocol failures in CI, as --view-protocol often causes spider gbh not to be created --- .../spider/mysql-test/spider/bg/combinations | 1 + .../bg/r/direct_aggregate,usual_handler.rdiff | 39 ++++++++ .../mysql-test/spider/bugfix/combinations | 1 + .../mysql-test/spider/bugfix/disabled.def | 1 - .../r/insert_select,usual_handler.rdiff | 29 ++++++ .../bugfix/r/mdev_20100,usual_handler.rdiff | 23 +++++ .../bugfix/r/mdev_20502,usual_handler.rdiff | 21 ++++ .../bugfix/r/mdev_27172,usual_handler.rdiff | 12 +++ .../bugfix/r/mdev_29008,usual_handler.rdiff | 15 +++ .../bugfix/r/mdev_29502,usual_handler.rdiff | 36 +++++++ .../spider/bugfix/r/mdev_34659.result | 1 + .../select_with_backquote,usual_handler.rdiff | 11 +++ .../r/wrapper_mariadb,usual_handler.rdiff | 11 +++ .../spider/bugfix/t/mdev_34659.test | 2 + storage/spider/mysql-test/spider/combinations | 5 + storage/spider/mysql-test/spider/disabled.def | 1 + .../mysql-test/spider/feature/combinations | 1 + .../r/pushdown_case,usual_handler.rdiff | 38 ++++++++ ...ushdown_timestamp_diff,usual_handler.rdiff | 83 ++++++++++++++++ .../r/auto_increment,usual_handler.rdiff | 11 +++ .../r/direct_aggregate,usual_handler.rdiff | 48 +++++++++ .../spider/r/direct_join,usual_handler.rdiff | 30 ++++++ .../r/direct_join_using,usual_handler.rdiff | 21 ++++ .../r/direct_left_join,usual_handler.rdiff | 17 ++++ ...ect_left_join_nullable,usual_handler.rdiff | 14 +++ ...ft_right_join_nullable,usual_handler.rdiff | 41 ++++++++ ...ght_left_join_nullable,usual_handler.rdiff | 19 ++++ .../r/direct_right_join,usual_handler.rdiff | 21 ++++ ...ct_right_join_nullable,usual_handler.rdiff | 23 +++++ ...ght_left_join_nullable,usual_handler.rdiff | 19 ++++ ...ft_right_join_nullable,usual_handler.rdiff | 46 +++++++++ .../r/pushdown_not_like,usual_handler.rdiff | 11 +++ .../spider/r/timestamp,usual_handler.rdiff | 97 +++++++++++++++++++ .../spider/r/udf_pushdown,usual_handler.rdiff | 13 +++ .../spider/regression/e1121/combinations | 1 + ...irect_join_by_pkey_key,usual_handler.rdiff | 11 +++ .../spider/regression/e112122/combinations | 1 + .../spider/t/direct_join_using.test | 4 +- 38 files changed, 776 insertions(+), 3 deletions(-) create mode 120000 storage/spider/mysql-test/spider/bg/combinations create mode 100644 storage/spider/mysql-test/spider/bg/r/direct_aggregate,usual_handler.rdiff create mode 120000 storage/spider/mysql-test/spider/bugfix/combinations create mode 100644 storage/spider/mysql-test/spider/bugfix/r/insert_select,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_20100,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_20502,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_27172,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_29008,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_29502,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/bugfix/r/select_with_backquote,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/bugfix/r/wrapper_mariadb,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/combinations create mode 100644 storage/spider/mysql-test/spider/disabled.def create mode 120000 storage/spider/mysql-test/spider/feature/combinations create mode 100644 storage/spider/mysql-test/spider/feature/r/pushdown_case,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/feature/r/pushdown_timestamp_diff,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/auto_increment,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_aggregate,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_join,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_join_using,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_left_join,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_left_join_nullable,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_left_right_join_nullable,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_left_right_left_join_nullable,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_right_join,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_right_join_nullable,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_right_left_join_nullable,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/direct_right_left_right_join_nullable,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/pushdown_not_like,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/timestamp,usual_handler.rdiff create mode 100644 storage/spider/mysql-test/spider/r/udf_pushdown,usual_handler.rdiff create mode 120000 storage/spider/mysql-test/spider/regression/e1121/combinations create mode 100644 storage/spider/mysql-test/spider/regression/e1121/r/direct_join_by_pkey_key,usual_handler.rdiff create mode 120000 storage/spider/mysql-test/spider/regression/e112122/combinations diff --git a/storage/spider/mysql-test/spider/bg/combinations b/storage/spider/mysql-test/spider/bg/combinations new file mode 120000 index 00000000000..ae8bc75d267 --- /dev/null +++ b/storage/spider/mysql-test/spider/bg/combinations @@ -0,0 +1 @@ +/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/bg/r/direct_aggregate,usual_handler.rdiff b/storage/spider/mysql-test/spider/bg/r/direct_aggregate,usual_handler.rdiff new file mode 100644 index 00000000000..2ba8144bc16 --- /dev/null +++ b/storage/spider/mysql-test/spider/bg/r/direct_aggregate,usual_handler.rdiff @@ -0,0 +1,39 @@ +--- ../src/storage/spider/mysql-test/spider/bg/r/direct_aggregate.result 2024-06-21 13:50:21.429397065 +1000 ++++ ../src/storage/spider/mysql-test/spider/bg/r/direct_aggregate.reject 2025-10-22 17:39:27.706744886 +1100 +@@ -54,31 +54,31 @@ + 5 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SELECT MAX(a) FROM ta_l; + MAX(a) + 5 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SELECT MIN(a) FROM ta_l; + MIN(a) + 1 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SELECT MAX(a) FROM ta_l WHERE a < 5; + MAX(a) + 4 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SELECT MIN(a) FROM ta_l WHERE a > 1; + MIN(a) + 2 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + + deinit + connection master_1; diff --git a/storage/spider/mysql-test/spider/bugfix/combinations b/storage/spider/mysql-test/spider/bugfix/combinations new file mode 120000 index 00000000000..ae8bc75d267 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/combinations @@ -0,0 +1 @@ +/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/bugfix/disabled.def b/storage/spider/mysql-test/spider/bugfix/disabled.def index 530b2825400..f591a3940e0 100644 --- a/storage/spider/mysql-test/spider/bugfix/disabled.def +++ b/storage/spider/mysql-test/spider/bugfix/disabled.def @@ -1,4 +1,3 @@ wait_timeout : MDEV-26045 mdev_27239: MDEV-32046 mdev_27575 : MDEV-32997 -mdev_28739_simple : MDEV-33343 diff --git a/storage/spider/mysql-test/spider/bugfix/r/insert_select,usual_handler.rdiff b/storage/spider/mysql-test/spider/bugfix/r/insert_select,usual_handler.rdiff new file mode 100644 index 00000000000..a5dc96572eb --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/insert_select,usual_handler.rdiff @@ -0,0 +1,29 @@ +--- ../src/storage/spider/mysql-test/spider/bugfix/r/insert_select.result 2024-05-01 14:39:20.114241787 +1000 ++++ ../src/storage/spider/mysql-test/spider/bugfix/r/insert_select.reject 2025-10-22 17:39:54.450930274 +1100 +@@ -60,16 +60,16 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 4) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 3) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 2) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 1) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 0) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 9) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 8) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 7) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 6) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode +-select t0.`skey` `skey`,cast((concat(t0.`dt` , _latin1' ' , t0.`tm`)) as datetime) `CAST(CONCAT(dt, ' ', tm) AS datetime)` from `auto_test_remote`.`tbl_a` t0 where ((t0.`skey` = 5) and (t0.`dt` > _latin1'2012-11-21')) lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 4 and `dt` > _latin1'2012-11-21' and ((`skey` = 4) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 3 and `dt` > _latin1'2012-11-21' and ((`skey` = 3) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 2 and `dt` > _latin1'2012-11-21' and ((`skey` = 2) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 1 and `dt` > _latin1'2012-11-21' and ((`skey` = 1) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 0 and `dt` > _latin1'2012-11-21' and ((`skey` = 0) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 9 and `dt` > _latin1'2012-11-21' and ((`skey` = 9) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 8 and `dt` > _latin1'2012-11-21' and ((`skey` = 8) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 7 and `dt` > _latin1'2012-11-21' and ((`skey` = 7) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 6 and `dt` > _latin1'2012-11-21' and ((`skey` = 6) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode ++select `skey`,`dt`,`tm` from `auto_test_remote`.`tbl_a` where `skey` = 5 and `dt` > _latin1'2012-11-21' and ((`skey` = 5) and (`dt` > _latin1'2012-11-21')) order by `dt`,`tm` lock in share mode + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT pkey, dt FROM tbl_b ORDER BY pkey; + pkey dt diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_20100,usual_handler.rdiff b/storage/spider/mysql-test/spider/bugfix/r/mdev_20100,usual_handler.rdiff new file mode 100644 index 00000000000..abfab37f8cb --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_20100,usual_handler.rdiff @@ -0,0 +1,23 @@ +--- ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.result 2024-05-01 14:39:20.114241787 +1000 ++++ ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_20100.reject 2025-10-22 17:39:55.494937566 +1100 +@@ -78,16 +78,16 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r3` t0 where (t0.`b` = 'c') ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` where (`b` = 'c') + select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` + select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +-select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r4` t0 where (t0.`b` = 'c') ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` where (`b` = 'c') + select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` + select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` +-select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r2` t0 where (t0.`b` = 'c') ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` where (`b` = 'c') + select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` + select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` +-select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r2` t0 where (t0.`b` = 'c') ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r2` where (`b` = 'c') + select `a`,`b`,`c` from `auto_test_remote`.`ta_r3` + select `a`,`b`,`c` from `auto_test_remote`.`ta_r4` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_20502,usual_handler.rdiff b/storage/spider/mysql-test/spider/bugfix/r/mdev_20502,usual_handler.rdiff new file mode 100644 index 00000000000..fd264d7d9a5 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_20502,usual_handler.rdiff @@ -0,0 +1,21 @@ +--- ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_20502.result 2025-08-01 15:07:36.416896406 +1000 ++++ ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_20502.reject 2025-10-22 17:39:57.398950875 +1100 +@@ -54,14 +54,14 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`id` `id`,0 `const`,t0.`val` `val` from `auto_test_remote`.`tbl_a` t0 + select `id`,`val` from `auto_test_remote`.`tbl_a` +-select (t0.`val` + 1) `tbl_a.val+1` from `auto_test_remote`.`tbl_a` t0 ++select `id`,`val` from `auto_test_remote`.`tbl_a` ++select `val` from `auto_test_remote`.`tbl_a` + select `id`,`val` from `auto_test_remote`.`tbl_a` order by `id` desc limit 1 for update + select `val` from `auto_test_remote`.`tbl_a` group by `val` +-select (t0.`val` + 1) `tbl_a.val+1` from `auto_test_remote`.`tbl_a` t0 limit 1 ++select `val` from `auto_test_remote`.`tbl_a` limit 2 + select max(`id`),min(`id`),`val` from `auto_test_remote`.`tbl_a` group by `val` +-select (t0.`val` + 1) `tbl_a.val+1` from `auto_test_remote`.`tbl_a` t0 limit 1 ++select `val` from `auto_test_remote`.`tbl_a` limit 2 + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT id, val FROM tbl_a ORDER BY id; + id val diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_27172,usual_handler.rdiff b/storage/spider/mysql-test/spider/bugfix/r/mdev_27172,usual_handler.rdiff new file mode 100644 index 00000000000..194eecf3b37 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_27172,usual_handler.rdiff @@ -0,0 +1,12 @@ +--- ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_27172.result 2024-11-15 17:14:27.541903833 +1100 ++++ ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_27172.reject 2025-10-22 17:40:25.831151167 +1100 +@@ -66,6 +66,9 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE argument LIKE 'select `id`,`greeting` from %'; + argument ++select `id`,`greeting` from `auto_test_remote`.`tbl_a` where `greeting` = 'Aloha!' and ((`greeting` = 'Aloha!') and ((case `greeting` when 'Aloha!' then _latin1'one' else _latin1'more' end) = _latin1'one')) ++select `id`,`greeting` from `auto_test_remote`.`tbl_b` where `greeting` like 'Aloha%' and ((`greeting` = 'Aloha!') and ((case `greeting` when 'Aloha!' then _latin1'one' else _latin1'more' end) = _latin1'one')) ++select `id`,`greeting` from `auto_test_remote`.`tbl_c` where `greeting` like 'Aloha%' and ((`greeting` = 'Aloha!') and ((case `greeting` when 'Aloha!' then _latin1'one' else _latin1'more' end) = _latin1'one')) + connection child2_1; + SET @@global.general_log = @general_log_backup; + SET @@global.log_output = @log_output_backup; diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_29008,usual_handler.rdiff b/storage/spider/mysql-test/spider/bugfix/r/mdev_29008,usual_handler.rdiff new file mode 100644 index 00000000000..a5dbf0cd49c --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_29008,usual_handler.rdiff @@ -0,0 +1,15 @@ +--- ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_29008.result 2025-08-01 15:07:36.416896406 +1000 ++++ ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_29008.reject 2025-10-22 17:40:29.191175025 +1100 +@@ -39,8 +39,10 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE argument LIKE 'select %'; + argument +-select min(t1.`a`) `f1`,t0.`b` `f2` from `auto_test_remote`.`tbl_a` t0 join `auto_test_remote`.`tbl_a` t1 group by `f2` order by `f1`,`f2` +-select min(t1.`a`) `f1`,t0.`b` `f2` from `auto_test_remote`.`tbl_a` t0 join `auto_test_remote`.`tbl_a` t1 group by `f2` order by min(t1.`a`),max(t1.`a`),`f2` ++select `b` from `auto_test_remote`.`tbl_a` ++select `a` from `auto_test_remote`.`tbl_a` ++select `b` from `auto_test_remote`.`tbl_a` ++select `a` from `auto_test_remote`.`tbl_a` + SELECT argument FROM mysql.general_log WHERE argument LIKE 'select %' + set global log_output=@old_log_output; + set global general_log=@old_general_log; diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_29502,usual_handler.rdiff b/storage/spider/mysql-test/spider/bugfix/r/mdev_29502,usual_handler.rdiff new file mode 100644 index 00000000000..737f5f70c5a --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_29502,usual_handler.rdiff @@ -0,0 +1,36 @@ +--- ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_29502.result 2025-08-01 15:07:36.416896406 +1000 ++++ ../src/storage/spider/mysql-test/spider/bugfix/r/mdev_29502.reject 2025-10-22 17:40:28.295168659 +1100 +@@ -35,7 +35,7 @@ + 48 48 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 8 + DROP TABLE t, t1; + CREATE TABLE t (a INT, b INT); + INSERT INTO t VALUES (23, -1),(48, 97); +@@ -45,7 +45,7 @@ + 145 -25 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 10 + DROP TABLE t, t1; + CREATE TABLE t (a INT); + INSERT INTO t VALUES (23),(97),(42); +@@ -55,13 +55,13 @@ + Y 97 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 2 ++Spider_direct_aggregate 12 + SELECT MAX(a), IF(COUNT(a > 0),'Y','N') FROM t1; + MAX(a) IF(COUNT(a > 0),'Y','N') + 97 Y + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 4 ++Spider_direct_aggregate 14 + DROP TABLE t, t1; + set spider_direct_aggregate=@old_spider_direct_aggregate; + DROP SERVER srv_mdev_29502; diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_34659.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_34659.result index e0f8b25d3c1..c38cfcc1d1c 100644 --- a/storage/spider/mysql-test/spider/bugfix/r/mdev_34659.result +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_34659.result @@ -2,6 +2,7 @@ for master_1 for child2 for child3 SET spider_same_server_link= on; +SET spider_disable_group_by_handler= 0; SET sql_mode=''; CREATE SERVER srv FOREIGN DATA WRAPPER mysql OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); diff --git a/storage/spider/mysql-test/spider/bugfix/r/select_with_backquote,usual_handler.rdiff b/storage/spider/mysql-test/spider/bugfix/r/select_with_backquote,usual_handler.rdiff new file mode 100644 index 00000000000..3e6380683ea --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/select_with_backquote,usual_handler.rdiff @@ -0,0 +1,11 @@ +--- ../src/storage/spider/mysql-test/spider/bugfix/r/select_with_backquote.result 2025-08-01 15:07:36.416896406 +1000 ++++ ../src/storage/spider/mysql-test/spider/bugfix/r/select_with_backquote.reject 2025-10-22 17:40:45.799293526 +1100 +@@ -44,7 +44,7 @@ + SET NAMES utf8; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`pkey` `pkey`,(left(t0.`txt_utf8` , 4)) `LEFT(``txt_utf8``, 4)` from `auto_test_remote`.`tbl_a` t0 order by (left(`txt_utf8` , 4)) limit 3 ++select `pkey`,`txt_utf8` from `auto_test_remote`.`tbl_a` order by (left(`txt_utf8` , 4)) limit 3 + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT pkey, txt_utf8 FROM tbl_a ORDER BY pkey; + pkey txt_utf8 diff --git a/storage/spider/mysql-test/spider/bugfix/r/wrapper_mariadb,usual_handler.rdiff b/storage/spider/mysql-test/spider/bugfix/r/wrapper_mariadb,usual_handler.rdiff new file mode 100644 index 00000000000..e1745600f98 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/wrapper_mariadb,usual_handler.rdiff @@ -0,0 +1,11 @@ +--- ../src/storage/spider/mysql-test/spider/bugfix/r/wrapper_mariadb.result 2024-05-01 14:39:20.118241872 +1000 ++++ ../src/storage/spider/mysql-test/spider/bugfix/r/wrapper_mariadb.reject 2025-10-22 17:40:53.351347717 +1100 +@@ -47,7 +47,7 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`pkey` `pkey` from `auto_test_remote`.`tbl_a` t0 order by `pkey` ++select `pkey` from `auto_test_remote`.`tbl_a` order by `pkey` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT pkey FROM tbl_a ORDER BY pkey; + pkey diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_34659.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_34659.test index 330b96db6f9..072252eba66 100644 --- a/storage/spider/mysql-test/spider/bugfix/t/mdev_34659.test +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_34659.test @@ -5,6 +5,8 @@ --enable_query_log SET spider_same_server_link= on; +# TODO(MDEV-37923) +SET spider_disable_group_by_handler= 0; SET sql_mode=''; evalp CREATE SERVER srv FOREIGN DATA WRAPPER mysql OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); diff --git a/storage/spider/mysql-test/spider/combinations b/storage/spider/mysql-test/spider/combinations new file mode 100644 index 00000000000..cad4d107176 --- /dev/null +++ b/storage/spider/mysql-test/spider/combinations @@ -0,0 +1,5 @@ +[group_by_handler] +loose_spider_disable_group_by_handler=0 + +[usual_handler] +loose_spider_disable_group_by_handler=1 diff --git a/storage/spider/mysql-test/spider/disabled.def b/storage/spider/mysql-test/spider/disabled.def new file mode 100644 index 00000000000..0c0fe4583e1 --- /dev/null +++ b/storage/spider/mysql-test/spider/disabled.def @@ -0,0 +1 @@ +alter_server : MDEV-37787 diff --git a/storage/spider/mysql-test/spider/feature/combinations b/storage/spider/mysql-test/spider/feature/combinations new file mode 120000 index 00000000000..ae8bc75d267 --- /dev/null +++ b/storage/spider/mysql-test/spider/feature/combinations @@ -0,0 +1 @@ +/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/feature/r/pushdown_case,usual_handler.rdiff b/storage/spider/mysql-test/spider/feature/r/pushdown_case,usual_handler.rdiff new file mode 100644 index 00000000000..d88ddf7ad2a --- /dev/null +++ b/storage/spider/mysql-test/spider/feature/r/pushdown_case,usual_handler.rdiff @@ -0,0 +1,38 @@ +--- ../src/storage/spider/mysql-test/spider/feature/r/pushdown_case.result 2025-08-01 15:07:36.420896283 +1000 ++++ ../src/storage/spider/mysql-test/spider/feature/r/pushdown_case.reject 2025-10-22 17:40:55.815365439 +1100 +@@ -13,7 +13,7 @@ + insert into t1 values (42), (3), (848), (100); + explain select case c when 3 then "three" when 42 then "answer" else "other" end as exp from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select case c when 3 then "three" when 42 then "answer" else "other" end as exp from t1; + exp + answer +@@ -22,7 +22,7 @@ + other + explain select case c when 3 then "three" when 42 then "answer" end from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select case c when 3 then "three" when 42 then "answer" end from t1; + case c when 3 then "three" when 42 then "answer" end + answer +@@ -31,7 +31,7 @@ + NULL + explain select case when c = 3 then "three" when c = 42 then "answer" else "other" end as exp from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select case when c = 3 then "three" when c = 42 then "answer" else "other" end as exp from t1; + exp + answer +@@ -40,7 +40,7 @@ + other + explain select case when c = 3 then "three" when c = 42 then "answer" end from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select case when c = 3 then "three" when c = 42 then "answer" end from t1; + case when c = 3 then "three" when c = 42 then "answer" end + answer diff --git a/storage/spider/mysql-test/spider/feature/r/pushdown_timestamp_diff,usual_handler.rdiff b/storage/spider/mysql-test/spider/feature/r/pushdown_timestamp_diff,usual_handler.rdiff new file mode 100644 index 00000000000..a0a92747a15 --- /dev/null +++ b/storage/spider/mysql-test/spider/feature/r/pushdown_timestamp_diff,usual_handler.rdiff @@ -0,0 +1,83 @@ +--- ../src/storage/spider/mysql-test/spider/feature/r/pushdown_timestamp_diff.result 2024-11-15 17:14:27.545903808 +1100 ++++ ../src/storage/spider/mysql-test/spider/feature/r/pushdown_timestamp_diff.reject 2025-10-22 17:40:58.047381510 +1100 +@@ -26,7 +26,7 @@ + interval year + explain select a, b, timestampdiff(year, '2000-01-01 00:00:00', c) from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select a, b, timestampdiff(year, '2000-01-01 00:00:00', c) from t1; + a b timestampdiff(year, '2000-01-01 00:00:00', c) + 1 a 18 +@@ -35,7 +35,7 @@ + interval quarter + explain select a, b, timestampdiff(quarter, '2000-01-01 00:00:00', c) from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select a, b, timestampdiff(quarter, '2000-01-01 00:00:00', c) from t1; + a b timestampdiff(quarter, '2000-01-01 00:00:00', c) + 1 a 75 +@@ -44,7 +44,7 @@ + interval month + explain select a, b, timestampdiff(month, '2000-01-01 00:00:00', c) from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select a, b, timestampdiff(month, '2000-01-01 00:00:00', c) from t1; + a b timestampdiff(month, '2000-01-01 00:00:00', c) + 1 a 226 +@@ -53,7 +53,7 @@ + interval week + explain select a, b, timestampdiff(week, '2000-01-01 00:00:00', c) from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select a, b, timestampdiff(week, '2000-01-01 00:00:00', c) from t1; + a b timestampdiff(week, '2000-01-01 00:00:00', c) + 1 a 982 +@@ -62,7 +62,7 @@ + interval day + explain select a, b, timestampdiff(day, '2000-01-01 00:00:00', c) from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select a, b, timestampdiff(day, '2000-01-01 00:00:00', c) from t1; + a b timestampdiff(day, '2000-01-01 00:00:00', c) + 1 a 6879 +@@ -71,7 +71,7 @@ + internal hour + explain select a, b, timestampdiff(hour, '2000-01-01 00:00:00', c) from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select a, b, timestampdiff(hour, '2000-01-01 00:00:00', c) from t1; + a b timestampdiff(hour, '2000-01-01 00:00:00', c) + 1 a 165106 +@@ -80,7 +80,7 @@ + internal minute + explain select a, b, timestampdiff(minute, '2000-01-01 00:00:00', c) from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select a, b, timestampdiff(minute, '2000-01-01 00:00:00', c) from t1; + a b timestampdiff(minute, '2000-01-01 00:00:00', c) + 1 a 9906381 +@@ -89,7 +89,7 @@ + internal second + explain select a, b, timestampdiff(second, '2000-01-01 00:00:00', c) from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select a, b, timestampdiff(second, '2000-01-01 00:00:00', c) from t1; + a b timestampdiff(second, '2000-01-01 00:00:00', c) + 1 a 594382899 +@@ -98,7 +98,7 @@ + internal microsecond + explain select a, b, timestampdiff(microsecond, '2000-01-01 00:00:00', c) from t1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Storage engine handles GROUP BY ++1 SIMPLE t1 ALL NULL NULL NULL NULL 2 + select a, b, timestampdiff(microsecond, '2000-01-01 00:00:00', c) from t1; + a b timestampdiff(microsecond, '2000-01-01 00:00:00', c) + 1 a 594382899000000 diff --git a/storage/spider/mysql-test/spider/r/auto_increment,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/auto_increment,usual_handler.rdiff new file mode 100644 index 00000000000..cd378103942 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/auto_increment,usual_handler.rdiff @@ -0,0 +1,11 @@ +--- ../src/storage/spider/mysql-test/spider/r/auto_increment.result 2024-06-21 13:39:03.368040208 +1000 ++++ ../src/storage/spider/mysql-test/spider/r/auto_increment.reject 2025-10-22 17:41:24.231571237 +1100 +@@ -154,7 +154,7 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`col_a` `col_a`,t0.`col_b` `col_b`,t0.`col_c` `col_c` from `auto_test_remote`.`tbl_a` t0 ++select `col_a`,`col_b`,`col_c` from `auto_test_remote`.`tbl_a` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT col_a, col_b, col_c FROM tbl_a ORDER BY col_a; + col_a col_b col_c diff --git a/storage/spider/mysql-test/spider/r/direct_aggregate,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_aggregate,usual_handler.rdiff new file mode 100644 index 00000000000..f7662986ab8 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_aggregate,usual_handler.rdiff @@ -0,0 +1,48 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_aggregate.result 2024-06-21 13:50:21.433397029 +1000 ++++ ../src/storage/spider/mysql-test/spider/r/direct_aggregate.reject 2025-10-22 17:42:04.239865208 +1100 +@@ -54,31 +54,31 @@ + 5 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SELECT MAX(a) FROM ta_l; + MAX(a) + 5 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SELECT MIN(a) FROM ta_l; + MIN(a) + 1 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SELECT MAX(a) FROM ta_l WHERE a < 5; + MAX(a) + 4 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SELECT MIN(a) FROM ta_l WHERE a > 1; + MIN(a) + 2 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SET spider_direct_aggregate=0; + SELECT COUNT(*) FROM ta_l; + COUNT(*) +@@ -97,7 +97,7 @@ + 2 + SHOW STATUS LIKE 'Spider_direct_aggregate'; + Variable_name Value +-Spider_direct_aggregate 0 ++Spider_direct_aggregate 1 + SET spider_direct_aggregate=1; + + deinit diff --git a/storage/spider/mysql-test/spider/r/direct_join,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_join,usual_handler.rdiff new file mode 100644 index 00000000000..6d48a46c8a9 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_join,usual_handler.rdiff @@ -0,0 +1,30 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_join.result 2025-08-01 15:07:36.420896283 +1000 ++++ ../src/storage/spider/mysql-test/spider/r/direct_join.reject 2025-10-22 17:42:14.703942870 +1100 +@@ -76,7 +76,17 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c` from `auto_test_remote`.`ta_r` t0 join `auto_test_remote`.`ta_r_3` t1 join `auto_test_remote`.`ta_r_int` t2 where ((t0.`a` = t1.`a`) and (t2.`a` = t1.`a`)) order by t0.`b` desc limit 1,2 ++select `a` from `auto_test_remote`.`ta_r_3` where (`a` is not null) limit 6 ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 1 limit 6 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 1 limit 6 ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 2 limit 6 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 2 limit 6 ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 3 limit 6 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 3 limit 6 ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 4 limit 6 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 4 limit 6 ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 5 limit 6 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 5 limit 6 + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') +@@ -167,7 +177,7 @@ + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument + select `id`,`hr_status`,`region_code`,`region` from `auto_test_remote`.`tbl_person` where `id` = '24FC3F0A5119432BAE13DD65AABAA39C' and `region` = 510411 +-select count(0) `count(0)` from (select 1) t0 join `auto_test_remote`.`tbl_ncd_cm_person` t1 where ((t1.`person_id` = '24FC3F0A5119432BAE13DD65AABAA39C') and (t1.`diseaseKind_id` = '52A0328740914BCE86ED10A4D2521816')) ++select `person_id`,`diseaseKind_id` from `auto_test_remote`.`tbl_ncd_cm_person` where ((`person_id` = '24FC3F0A5119432BAE13DD65AABAA39C') and (`diseaseKind_id` = '52A0328740914BCE86ED10A4D2521816')) + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT * FROM tbl_person; + id hr_status region_code region diff --git a/storage/spider/mysql-test/spider/r/direct_join_using,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_join_using,usual_handler.rdiff new file mode 100644 index 00000000000..e3c098240be --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_join_using,usual_handler.rdiff @@ -0,0 +1,21 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_join_using.result 2025-08-01 15:07:36.420896283 +1000 ++++ ../src/storage/spider/mysql-test/spider/r/direct_join_using.reject 2025-10-22 17:42:20.207983843 +1100 +@@ -79,7 +79,17 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c` from `auto_test_remote`.`ta_r` t0 join `auto_test_remote`.`ta_r_3` t1 join `auto_test_remote`.`ta_r_int` t2 where ((t0.`a` = t1.`a`) and (t2.`a` = t1.`a`)) order by t0.`b` desc ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_3` where (`a` is not null) ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 1 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 2 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 3 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r` where `a` = 4 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 4 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r` where `a` = 5 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 5 + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/direct_left_join,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_left_join,usual_handler.rdiff new file mode 100644 index 00000000000..93dc364387d --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_left_join,usual_handler.rdiff @@ -0,0 +1,17 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_left_join.result 2025-08-01 15:07:36.420896283 +1000 ++++ ../src/storage/spider/mysql-test/spider/r/direct_left_join.reject 2025-10-22 17:42:25.256021497 +1100 +@@ -79,7 +79,13 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c` from `auto_test_remote`.`ta_r` t0 left join `auto_test_remote`.`ta_r_3` t1 on (t1.`a` = t0.`a`) left join `auto_test_remote`.`ta_r_int` t2 on (t2.`a` = t0.`a`) where 1 order by t0.`b` desc ++select `a`,`b` from `auto_test_remote`.`ta_r` ++select `a` from `auto_test_remote`.`ta_r_3` ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 1 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 2 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 3 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 4 ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` where `a` = 5 + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/direct_left_join_nullable,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_left_join_nullable,usual_handler.rdiff new file mode 100644 index 00000000000..524e9f7ba21 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_left_join_nullable,usual_handler.rdiff @@ -0,0 +1,14 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_left_join_nullable.result 2024-05-01 14:39:20.122241957 +1000 ++++ ../src/storage/spider/mysql-test/spider/r/direct_left_join_nullable.reject 2025-10-22 17:42:31.592068856 +1100 +@@ -87,7 +87,10 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c`,t3.`a` `a` from `auto_test_remote`.`ta_r_no_idx` t0 left join `auto_test_remote`.`ta_r_auto_inc` t1 on (t1.`a` = t0.`a`) left join `auto_test_remote`.`ta_r_3` t2 on (t2.`c` = t1.`c`) left join `auto_test_remote`.`ta_r` t3 on (t3.`b` = t2.`b`) where 1 order by t0.`a` desc ++select `a` from `auto_test_remote`.`ta_r_no_idx` ++select `a`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `b`,`c` from `auto_test_remote`.`ta_r_3` ++select `a`,`b` from `auto_test_remote`.`ta_r` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/direct_left_right_join_nullable,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_left_right_join_nullable,usual_handler.rdiff new file mode 100644 index 00000000000..8d883d535ea --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_left_right_join_nullable,usual_handler.rdiff @@ -0,0 +1,41 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_left_right_join_nullable.result 2024-11-14 13:59:27.762081104 +1100 ++++ ../src/storage/spider/mysql-test/spider/r/direct_left_right_join_nullable.reject 2025-10-22 17:42:33.452082780 +1100 +@@ -87,7 +87,37 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c`,t3.`a` `a` from `auto_test_remote`.`ta_r_no_idx` t3 left join (`auto_test_remote`.`ta_r` t0 join `auto_test_remote`.`ta_r_3` t1 join `auto_test_remote`.`ta_r_auto_inc` t2) on ((t2.`b` = t3.`b`) and (t2.`c` = t1.`c`) and (t0.`a` = t1.`a`) and (t1.`a` is not null)) where 1 order by t3.`a` desc ++select `a`,`b` from `auto_test_remote`.`ta_r_no_idx` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/direct_left_right_left_join_nullable,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_left_right_left_join_nullable,usual_handler.rdiff new file mode 100644 index 00000000000..e7c3dee5203 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_left_right_left_join_nullable,usual_handler.rdiff @@ -0,0 +1,19 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_left_right_left_join_nullable.result 2024-11-14 13:59:27.762081104 +1100 ++++ ../src/storage/spider/mysql-test/spider/r/direct_left_right_left_join_nullable.reject 2025-10-22 17:42:33.560083588 +1100 +@@ -86,7 +86,15 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c`,t3.`a` `a` from `auto_test_remote`.`ta_r_auto_inc` t2 left join (`auto_test_remote`.`ta_r` t0 join `auto_test_remote`.`ta_r_3` t1) on ((t1.`c` = t2.`c`) and (t0.`a` = t1.`a`) and (t1.`a` is not null)) left join `auto_test_remote`.`ta_r_no_idx` t3 on (t3.`b` = t2.`b`) where 1 order by t3.`a` desc ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a`,`b` from `auto_test_remote`.`ta_r_no_idx` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/direct_right_join,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_right_join,usual_handler.rdiff new file mode 100644 index 00000000000..97e9bc28bb9 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_right_join,usual_handler.rdiff @@ -0,0 +1,21 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_right_join.result 2025-08-01 15:07:36.420896283 +1000 ++++ ../src/storage/spider/mysql-test/spider/r/direct_right_join.reject 2025-10-22 17:42:42.744152477 +1100 +@@ -79,7 +79,17 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c` from `auto_test_remote`.`ta_r_int` t2 left join (`auto_test_remote`.`ta_r_3` t1 join `auto_test_remote`.`ta_r` t0) on ((t0.`a` = t2.`a`) and (t1.`a` = t2.`a`)) where 1 order by t0.`b` desc ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r_int` ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `a` from `auto_test_remote`.`ta_r_3` ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `a` from `auto_test_remote`.`ta_r_3` ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `a` from `auto_test_remote`.`ta_r_3` ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 4 ++select `a` from `auto_test_remote`.`ta_r_3` ++select `a`,`b` from `auto_test_remote`.`ta_r` where `a` = 5 ++select `a` from `auto_test_remote`.`ta_r_3` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/direct_right_join_nullable,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_right_join_nullable,usual_handler.rdiff new file mode 100644 index 00000000000..d419df10166 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_right_join_nullable,usual_handler.rdiff @@ -0,0 +1,23 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_right_join_nullable.result 2024-11-14 13:59:27.762081104 +1100 ++++ ../src/storage/spider/mysql-test/spider/r/direct_right_join_nullable.reject 2025-10-22 17:41:24.255571412 +1100 +@@ -87,7 +87,19 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c`,t3.`a` `a` from `auto_test_remote`.`ta_r_no_idx` t3 left join (`auto_test_remote`.`ta_r_auto_inc` t2 left join (`auto_test_remote`.`ta_r_3` t1 left join `auto_test_remote`.`ta_r` t0 on ((t0.`a` = t1.`a`) and (t1.`a` is not null))) on (t1.`c` = t2.`c`)) on (t2.`b` = t3.`b`) where 1 order by t3.`a` desc ++select `a`,`b` from `auto_test_remote`.`ta_r_no_idx` ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/direct_right_left_join_nullable,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_right_left_join_nullable,usual_handler.rdiff new file mode 100644 index 00000000000..3797ee142f6 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_right_left_join_nullable,usual_handler.rdiff @@ -0,0 +1,19 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_right_left_join_nullable.result 2024-11-14 13:59:27.762081104 +1100 ++++ ../src/storage/spider/mysql-test/spider/r/direct_right_left_join_nullable.reject 2025-10-22 17:41:31.051621007 +1100 +@@ -86,7 +86,15 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c`,t3.`a` `a` from `auto_test_remote`.`ta_r_auto_inc` t2 left join (`auto_test_remote`.`ta_r_3` t1 left join `auto_test_remote`.`ta_r` t0 on ((t0.`a` = t1.`a`) and (t1.`a` is not null))) on (t1.`c` = t2.`c`) left join `auto_test_remote`.`ta_r_no_idx` t3 on (t3.`b` = t2.`b`) where 1 order by t3.`a` desc ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a`,`b` from `auto_test_remote`.`ta_r_no_idx` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/direct_right_left_right_join_nullable,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/direct_right_left_right_join_nullable,usual_handler.rdiff new file mode 100644 index 00000000000..e34c75625cb --- /dev/null +++ b/storage/spider/mysql-test/spider/r/direct_right_left_right_join_nullable,usual_handler.rdiff @@ -0,0 +1,46 @@ +--- ../src/storage/spider/mysql-test/spider/r/direct_right_left_right_join_nullable.result 2024-11-14 13:59:27.762081104 +1100 ++++ ../src/storage/spider/mysql-test/spider/r/direct_right_left_right_join_nullable.reject 2025-10-22 17:41:38.127672798 +1100 +@@ -87,7 +87,42 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`a` `a`,t2.`b` `b`,t2.`c` `c`,t3.`a` `a` from `auto_test_remote`.`ta_r_no_idx` t3 left join (`auto_test_remote`.`ta_r_3` t1 left join `auto_test_remote`.`ta_r` t0 on ((t0.`a` = t1.`a`) and (t1.`a` is not null)) join `auto_test_remote`.`ta_r_auto_inc` t2) on ((t2.`b` = t3.`b`) and (t2.`c` = t1.`c`)) where 1 order by t3.`a` desc ++select `a`,`b` from `auto_test_remote`.`ta_r_no_idx` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a`,`c` from `auto_test_remote`.`ta_r_3` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 1 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 2 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` ++select `a` from `auto_test_remote`.`ta_r` where `a` = 3 ++select `b`,`c` from `auto_test_remote`.`ta_r_auto_inc` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; + a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/pushdown_not_like,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/pushdown_not_like,usual_handler.rdiff new file mode 100644 index 00000000000..c1bdac735cd --- /dev/null +++ b/storage/spider/mysql-test/spider/r/pushdown_not_like,usual_handler.rdiff @@ -0,0 +1,11 @@ +--- ../src/storage/spider/mysql-test/spider/r/pushdown_not_like.result 2024-05-01 14:39:20.122241957 +1000 ++++ ../src/storage/spider/mysql-test/spider/r/pushdown_not_like.reject 2025-10-22 17:41:34.179643884 +1100 +@@ -41,7 +41,7 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select%'; + argument +-select t0.`a` `a`,t0.`b` `b`,t0.`c` `c` from `auto_test_remote`.`ta_r` t0 where (t0.`b` not like 'a%') ++select `a`,`b`,`c` from `auto_test_remote`.`ta_r` where (`b` not like 'a%') + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select%' + + deinit diff --git a/storage/spider/mysql-test/spider/r/timestamp,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/timestamp,usual_handler.rdiff new file mode 100644 index 00000000000..df0f554f43a --- /dev/null +++ b/storage/spider/mysql-test/spider/r/timestamp,usual_handler.rdiff @@ -0,0 +1,97 @@ +--- ../src/storage/spider/mysql-test/spider/r/timestamp.result 2025-08-01 15:07:36.420896283 +1000 ++++ ../src/storage/spider/mysql-test/spider/r/timestamp.reject 2025-10-22 17:41:31.819626622 +1100 +@@ -114,7 +114,7 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a; + col_a col_dt col_ts unix_timestamp(col_ts) +@@ -140,7 +140,7 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a; + col_a col_dt col_ts unix_timestamp(col_ts) +@@ -166,7 +166,7 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a; + col_a col_dt col_ts unix_timestamp(col_ts) +@@ -194,7 +194,7 @@ + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument + select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` for update +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a; + col_a col_dt col_ts unix_timestamp(col_ts) +@@ -252,13 +252,13 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > _latin1'2017-12-31 23:00:00') +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` < _latin1'2018-10-28 01:30:00') +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (_latin1'2018-10-28 01:30:00' > t0.`col_ts`) +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` between _latin1'2018-10-28 00:30:00' and _latin1'2018-10-28 01:30:00') +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where ((t0.`col_ts` >= _latin1'2018-10-28 00:30:00') and (t0.`col_ts` <= _latin1'2018-10-28 01:30:00')) +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '2018-03-25 01:00:00') +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '1970-01-01 00:00:01') ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (`col_ts` > _latin1'2017-12-31 23:00:00') order by `col_ts` ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (`col_ts` < _latin1'2018-10-28 01:30:00') order by `col_ts` ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (_latin1'2018-10-28 01:30:00' > `col_ts`) order by `col_ts` ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where `col_ts` >= _latin1'2018-10-28 00:30:00' and `col_ts` <= _latin1'2018-10-28 01:30:00' and (`col_ts` between _latin1'2018-10-28 00:30:00' and _latin1'2018-10-28 01:30:00') order by `col_ts` ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where `col_ts` >= _latin1'2018-10-28 00:30:00' and `col_ts` <= _latin1'2018-10-28 01:30:00' and ((`col_ts` >= _latin1'2018-10-28 00:30:00') and (`col_ts` <= _latin1'2018-10-28 01:30:00')) order by `col_ts` ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (`col_ts` > '2018-03-25 01:00:00') order by `col_ts` ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (`col_ts` > '1970-01-01 00:00:01') order by `col_ts` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a; + col_a col_dt col_ts unix_timestamp(col_ts) +@@ -339,13 +339,13 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > _latin1'2017-12-31 23:00:00') +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` < _latin1'2018-10-28 01:30:00') +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (_latin1'2018-10-28 01:30:00' > t0.`col_ts`) +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` between _latin1'2018-10-28 00:30:00' and _latin1'2018-10-28 01:30:00') +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where ((t0.`col_ts` >= _latin1'2018-10-28 00:30:00') and (t0.`col_ts` <= _latin1'2018-10-28 01:30:00')) +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '2018-03-25 01:00:00') +-select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '1970-01-01 00:00:01') ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (`col_ts` > _latin1'2017-12-31 23:00:00') ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (`col_ts` < _latin1'2018-10-28 01:30:00') ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (_latin1'2018-10-28 01:30:00' > `col_ts`) ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (`col_ts` between _latin1'2018-10-28 00:30:00' and _latin1'2018-10-28 01:30:00') ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where ((`col_ts` >= _latin1'2018-10-28 00:30:00') and (`col_ts` <= _latin1'2018-10-28 01:30:00')) ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (`col_ts` > '2018-03-25 01:00:00') ++select `col_a`,`col_dt`,`col_ts` from `ts_test_remote`.`tbl_a` where (`col_ts` > '1970-01-01 00:00:01') + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a; + col_a col_dt col_ts unix_timestamp(col_ts) +@@ -392,11 +392,11 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; + argument +-select t0.`col_d` `col_d`,t0.`col_t` `col_t` from `ts_test_remote`.`tbl_f` t0 +-select (timestamp(t0.`col_d` , t0.`col_t`)) `TIMESTAMP(col_d, col_t)` from `ts_test_remote`.`tbl_f` t0 +-select (timestamp('2018-06-25' , t0.`col_t`)) `TIMESTAMP('2018-06-25', col_t)` from `ts_test_remote`.`tbl_f` t0 +-select (timestamp(t0.`col_d` , '10:43:21')) `TIMESTAMP(col_d, '10:43:21')` from `ts_test_remote`.`tbl_f` t0 +-select (timestamp('2018-06-25' , '10:43:21')) `TIMESTAMP('2018-06-25', '10:43:21')` from `ts_test_remote`.`tbl_f` t0 ++select `col_d`,`col_t` from `ts_test_remote`.`tbl_f` ++select `col_d`,`col_t` from `ts_test_remote`.`tbl_f` ++select `col_t` from `ts_test_remote`.`tbl_f` ++select `col_d` from `ts_test_remote`.`tbl_f` ++select 1 from `ts_test_remote`.`tbl_f` + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' + SELECT col_d, col_t FROM tbl_f; + col_d col_t diff --git a/storage/spider/mysql-test/spider/r/udf_pushdown,usual_handler.rdiff b/storage/spider/mysql-test/spider/r/udf_pushdown,usual_handler.rdiff new file mode 100644 index 00000000000..820599b8280 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/udf_pushdown,usual_handler.rdiff @@ -0,0 +1,13 @@ +--- ../src/storage/spider/mysql-test/spider/r/udf_pushdown.result 2022-12-05 17:51:57.843152110 +1100 ++++ ../src/storage/spider/mysql-test/spider/r/udf_pushdown.reject 2025-10-22 17:41:38.167673091 +1100 +@@ -148,8 +148,8 @@ + connection child2_1; + SELECT argument FROM mysql.general_log WHERE argument LIKE "%select%" AND argument NOT LIKE "%argument%"; + argument +-select t0.`id` `id`,t0.`a` `a` from `auto_test_remote`.`ta_r` t0 where (t0.`id` = (`plusone`(1))) +-select t0.`id` `id`,t0.`a` `a` from `auto_test_remote`.`ta_r` t0 where ((t0.`id` in( (`plusone`(1)) , (`plusone`(2)))) and (t0.`a` = (`plusone`(32)))) ++select `id`,`a` from `auto_test_remote`.`ta_r` where (`id` = (`plusone`(1))) ++select `id`,`a` from `auto_test_remote`.`ta_r` where ((`id` in( (`plusone`(1)) , (`plusone`(2)))) and (`a` = (`plusone`(32)))) + + ##### test UPDATEs ##### + connection master_1; diff --git a/storage/spider/mysql-test/spider/regression/e1121/combinations b/storage/spider/mysql-test/spider/regression/e1121/combinations new file mode 120000 index 00000000000..ae8bc75d267 --- /dev/null +++ b/storage/spider/mysql-test/spider/regression/e1121/combinations @@ -0,0 +1 @@ +/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/regression/e1121/r/direct_join_by_pkey_key,usual_handler.rdiff b/storage/spider/mysql-test/spider/regression/e1121/r/direct_join_by_pkey_key,usual_handler.rdiff new file mode 100644 index 00000000000..378474bd8d4 --- /dev/null +++ b/storage/spider/mysql-test/spider/regression/e1121/r/direct_join_by_pkey_key,usual_handler.rdiff @@ -0,0 +1,11 @@ +--- ../src/storage/spider/mysql-test/spider/regression/e1121/r/direct_join_by_pkey_key.result 2024-11-14 13:59:27.762081104 +1100 ++++ ../src/storage/spider/mysql-test/spider/regression/e1121/r/direct_join_by_pkey_key.reject 2025-10-22 17:41:34.943649475 +1100 +@@ -46,7 +46,7 @@ + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%`tbl_a`%' ; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%`tbl_b`%'; + argument +-select t0.`val` `val`,t0.`akey` `akey` from `auto_test_remote`.`tbl_a` t0 join (select 1) t1 where (t0.`akey` = '4') ++select `akey`,`val` from `auto_test_remote`.`tbl_a` where `akey` = 4 + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%`tbl_a`%' ; + SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%`tbl_b`%' + argument diff --git a/storage/spider/mysql-test/spider/regression/e112122/combinations b/storage/spider/mysql-test/spider/regression/e112122/combinations new file mode 120000 index 00000000000..ae8bc75d267 --- /dev/null +++ b/storage/spider/mysql-test/spider/regression/e112122/combinations @@ -0,0 +1 @@ +/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/t/direct_join_using.test b/storage/spider/mysql-test/spider/t/direct_join_using.test index 059990e874a..5985e3a4a02 100644 --- a/storage/spider/mysql-test/spider/t/direct_join_using.test +++ b/storage/spider/mysql-test/spider/t/direct_join_using.test @@ -124,7 +124,7 @@ insert into tbl_c values (1,10,100),(2,20,200),(3,30,300),(4,40,400),(5,50,500); TRUNCATE TABLE mysql.general_log; --connection master_1 ---disable_ps2_protocol +--disable_ps_protocol --disable_view_protocol SELECT a.a, c.b, c.c FROM tbl_a a join tbl_b b using(a) join tbl_c c using(a) ORDER BY a.b DESC; --enable_view_protocol @@ -133,7 +133,7 @@ SELECT a.a, c.b, c.c FROM tbl_a a join tbl_b b using(a) join tbl_c c using(a) OR SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'; --enable_view_protocol SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; ---enable_ps2_protocol +--enable_ps_protocol --echo --echo deinit From 3a70dc378f4530fba0a778c26d3b44e361d36f29 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Wed, 15 Oct 2025 15:52:24 +1100 Subject: [PATCH 10/54] MDEV-30265 Spider: Add CODING_STANDARDS --- storage/spider/CODING_STADNARDS.org | 81 +++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 storage/spider/CODING_STADNARDS.org diff --git a/storage/spider/CODING_STADNARDS.org b/storage/spider/CODING_STADNARDS.org new file mode 100644 index 00000000000..445b92fe42b --- /dev/null +++ b/storage/spider/CODING_STADNARDS.org @@ -0,0 +1,81 @@ +#+title Spider Development Documentation + +** Testing + :PROPERTIES: + :UPDATED: [2025-10-15 Wed 15:33] + :END: + +*** Run spider test suites + :PROPERTIES: + :UPDATED: [2025-10-15 Wed 15:39] + :END: + +Spider has sub-suites. Assuming temporary WIP spider tests are placed +under the spider/temp suite, to run a test on all spider tests, do + +#+begin_src sh +./mysql-test/mtr --suite spider,spider/*,spider/*/* \ +--skip-test="spider/temp.*|.*/t\..*" --parallel=auto --big-test \ +--force --max-test-fail=0 +#+end_src + +Tests should be run normally, but also with --ps-protocol, +--view-protocol and ASAN. + +For 10.11+ tests should also be run with +--mysqld=--loose-disable-spider-group-by-handler. This will be done +automatically after MDEV-37810. + +*** Where to place new tests + :PROPERTIES: + :UPDATED: [2025-10-15 Wed 15:35] + :END: + +- spider/bugfix suite for bugfixes +- spider/feature suite for new features +- spider suite for all else, such as generic tests to improve coverage + +*** Use engine defined attributes in tests whenever possible + :PROPERTIES: + :UPDATED: [2025-10-15 Wed 15:52] + :END: + +In versions of at least 10.11, when writing new tests or updating +existing tests, use engine defined attributes for spider table +connection info instead of table comments + +#+begin_src sql +# Do this for 10.11+ +CREATE TABLE t (c int) ENGINE=SPIDER REMOTE_SERVER=s1 REMOTE_TABLE=t1; +# Do this for 10.6 +CREATE TABLE t (c int) ENGINE=SPIDER COMMENT='srv "s1", table "t1"'; +#+end_src + +However, if the spider table has connection info that is not +REMOTE_SERVER, REMOTE_TABLE, or REMOTE_DATABASE, comments are still +needed for 10.11: + +#+begin_src sql +# Do this for 10.6 and 10.11 +CREATE TABLE t (c int) ENGINE=SPIDER COMMENT='srv "s1", table "t1", read_only_mode "1"'; +# Do this for 11.4+ +CREATE TABLE t (c int) ENGINE=SPIDER REMOTE_SERVER=s1 REMOTE_TABLE=t1 READ_ONLY=1; +#+end_src + +Don't mix engine defined attributes with COMMENT, unless the mixing is +part of the test. + +#+begin_src sql +# Don't do this +CREATE TABLE t (c int) ENGINE=SPIDER REMOTE_SERVER=s1 REMOTE_TABLE=t1 COMMENT='read_only_mode "1"'; +#+end_src + +WRAPPER by default is mysql, so it is ok to do the following +conversion in 10.11+: + +#+begin_src sql +# From +CREATE TABLE t (c int) ENGINE=SPIDER COMMENT='wrapper "mysql", srv "s1", table "t1"'; +# to +CREATE TABLE t (c int) ENGINE=SPIDER REMOTE_SERVER=s1 REMOTE_TABLE=t1; +#+end_src From bb5597a25107942467a36544f7e3966f1f20b783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 22 Oct 2025 19:14:20 +0300 Subject: [PATCH 11/54] MDEV-37902: buf_read_page_low() may miss a call to thd_wait_end() buf_read_page_low(): Implement separate code paths for synchronous and asynchronous read, similar to commit b2c1ba820b6cda723c58f2ba01ccf2e379b7f313 (MDEV-37860), and always invoke thd_wait_begin() and thd_wait_end() the same number of times. This fixes a regression that affects the non-default setting thread_handling=pool-of-threads and had been introduced in commit b1ab211dee599eabd9a5b886fafa3adea29ae041 (MDEV-15053). Reviewed by: Vladislav Vaintroub --- storage/innobase/buf/buf0rea.cc | 55 ++++++++++++++++----------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index 09c30504f52..c0e69b42c40 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -302,41 +302,40 @@ buf_read_page_low( } ut_ad(bpage->in_file()); - ulonglong mariadb_timer = 0; - - if (sync) { - thd_wait_begin(nullptr, THD_WAIT_DISKIO); - if (const ha_handler_stats *stats = mariadb_stats) { - if (stats->active) { - mariadb_timer = mariadb_measure(); - } - } - } - - DBUG_LOG("ib_buf", - "read page " << page_id << " zip_size=" << zip_size - << " unzip=" << unzip << ',' << (sync ? "sync" : "async")); - void* dst = zip_size ? bpage->zip.data : bpage->frame; const ulint len = zip_size ? zip_size : srv_page_size; + fil_io_t fio; - auto fio = space->io(IORequest(sync - ? IORequest::READ_SYNC - : IORequest::READ_ASYNC), - os_offset_t{page_id.page_no()} * len, len, - dst, bpage); + if (sync) { + ulonglong start_time = 0; + THD* const thd = current_thd; + thd_wait_begin(thd, THD_WAIT_DISKIO); + ha_handler_stats *stats = mariadb_stats; + if (stats && stats->active) { + start_time = mariadb_measure(); + } + fio = space->io(IORequest(IORequest::READ_SYNC), + os_offset_t{page_id.page_no()} * len, len, + dst, bpage); + thd_wait_end(thd); + if (start_time) { + stats->pages_read_time + += (mariadb_measure() - start_time); + } + if (UNIV_LIKELY(fio.err == DB_SUCCESS)) { + dberr_t err{bpage->read_complete(*fio.node)}; + space->release(); + return err; + } + } else { + fio = space->io(IORequest(IORequest::READ_ASYNC), + os_offset_t{page_id.page_no()} * len, len, + dst, bpage); + } if (UNIV_UNLIKELY(fio.err != DB_SUCCESS)) { recv_sys.free_corrupted_page(page_id, *space->chain.start); buf_pool.corrupted_evict(bpage, buf_page_t::READ_FIX); - } else if (sync) { - thd_wait_end(nullptr); - /* The i/o was already completed in space->io() */ - fio.err = bpage->read_complete(*fio.node); - space->release(); - if (mariadb_timer) { - mariadb_increment_pages_read_time(mariadb_timer); - } } return fio.err; From 23af68bbbfa7dcdcd01025dbec4d59469e87c15b Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Wed, 1 Oct 2025 23:27:17 +0530 Subject: [PATCH 12/54] MDEV-36319: Wrong result json_table Analysis: Json path comparison logic was incorrect. --- mysql-test/main/func_json.result | 71 +++++++++++++++++++++++++++++++ mysql-test/main/func_json.test | 72 ++++++++++++++++++++++++++++++++ sql/item_jsonfunc.cc | 29 +++++++------ 3 files changed, 157 insertions(+), 15 deletions(-) diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index de77e7aa4a7..dc11f93b1fb 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -2692,4 +2692,75 @@ json_detailed('[[123],456]') SELECT JSON_VALUE(JSON_OBJECT("a", ""), '$.a') = "" AS not_null; not_null 1 +# +# MDEV-36319: Wrong result json_table +# +SET @JSON=' +{ + "SZ": [ + { + "NAME": "S0", + "OFFERS": [ + { + "NAME": "S0A0" + } + ] + }, + { + "NAME": "S1", + "OFFERS": [ + { + "NAME": "S1A0" + }, + { + "NAME": "S1A1" + } + ] + }, + { + "NAME": "S2", + "OFFERS": [ + { + "NAME": "S2A0" + } + ] + }, + { + "NAME": "S3", + "OFFERS": [ + { + "NAME": "S3A0" + } + ] + }, + { + "NAME": "S4", + "OFFERS": [ + { + "NAME": "S4A0" + } + ] + }, + { + "NAME": "S5", + "OFFERS": [ + { + "NAME": "S5A0" + } + ] + } + ] +} + +' +; +# Should return EMPTY result +SELECT * FROM json_table(@JSON, '$.SZ[0].OFFERS[1]' +COLUMNS(NAME VARCHAR(30) PATH '$.NAME')) AS t_sz; +NAME +# Should return S1A1 +SELECT * FROM json_table(@JSON, '$.SZ[1].OFFERS[1]' +COLUMNS(NAME VARCHAR(30) PATH '$.NAME')) AS t_sz; +NAME +S1A1 # End of 10.11 Test diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index c488c63f06b..28c8e923207 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -1953,4 +1953,76 @@ select json_detailed('[[123],456]'); SELECT JSON_VALUE(JSON_OBJECT("a", ""), '$.a') = "" AS not_null; +--echo # +--echo # MDEV-36319: Wrong result json_table +--echo # + +SET @JSON=' +{ + "SZ": [ + { + "NAME": "S0", + "OFFERS": [ + { + "NAME": "S0A0" + } + ] + }, + { + "NAME": "S1", + "OFFERS": [ + { + "NAME": "S1A0" + }, + { + "NAME": "S1A1" + } + ] + }, + { + "NAME": "S2", + "OFFERS": [ + { + "NAME": "S2A0" + } + ] + }, + { + "NAME": "S3", + "OFFERS": [ + { + "NAME": "S3A0" + } + ] + }, + { + "NAME": "S4", + "OFFERS": [ + { + "NAME": "S4A0" + } + ] + }, + { + "NAME": "S5", + "OFFERS": [ + { + "NAME": "S5A0" + } + ] + } + ] +} + +' +; + +--echo # Should return EMPTY result +SELECT * FROM json_table(@JSON, '$.SZ[0].OFFERS[1]' +COLUMNS(NAME VARCHAR(30) PATH '$.NAME')) AS t_sz; + +--echo # Should return S1A1 +SELECT * FROM json_table(@JSON, '$.SZ[1].OFFERS[1]' +COLUMNS(NAME VARCHAR(30) PATH '$.NAME')) AS t_sz; + --echo # End of 10.11 Test diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 5090ae1d2f7..61ee2bd2493 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -206,24 +206,23 @@ int json_path_parts_compare( { if (b->type & JSON_PATH_ARRAY) { - int res= 0, corrected_n_item_a= 0; - if (array_sizes) - corrected_n_item_a= a->n_item < 0 ? - array_sizes[b-temp_b] + a->n_item : a->n_item; - if (a->type & JSON_PATH_ARRAY_RANGE) + int res = 0; + if (a->type & JSON_PATH_WILD) + res = 1; + else if (a->type & JSON_PATH_ARRAY_RANGE && array_sizes) { - int corrected_n_item_end_a= 0; - if (array_sizes) - corrected_n_item_end_a= a->n_item_end < 0 ? - array_sizes[b-temp_b] + a->n_item_end : - a->n_item_end; - res= b->n_item >= corrected_n_item_a && - b->n_item <= corrected_n_item_end_a; + int start = (a->n_item >= 0) ? a->n_item + : array_sizes[b - temp_b] + a->n_item; + int end = (a->n_item_end >= 0) ? a->n_item_end + : array_sizes[b - temp_b] + a->n_item_end; + res = (b->n_item >= start && b->n_item <= end); } - else - res= corrected_n_item_a == b->n_item; + else if (a->n_item >= 0) + res = (a->n_item == b->n_item); + else if (a->n_item < 0 && array_sizes) + res = (a->n_item == b->n_item - array_sizes[b - temp_b]); - if ((a->type & JSON_PATH_WILD) || res) + if (res) goto step_fits; goto step_failed; } From 85567aba450dcd5efe2506c67222ef7b82b6ceda Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Thu, 9 Oct 2025 11:58:58 +0530 Subject: [PATCH 13/54] MDEV-34081: View containing JSON_TABLE does not return JSON Analysis: While writing the view to .FRM file, we check the datatype of each column and append the appropriate type to the string (which will be written to the frm). This is where the conversion from JSON to longtext happens because that is how it is stored internally. Now, while SELECT, when the frm is read it has longtext instead of JSON which also results in changing the handler type. Since the handler types dont match, m_format_json becomes false for that specific column. Now, when filling the values, since the format is not json, it does not get added in the result. Hence the output is NULL. Fix: Before writing the view to the FRM file, check if the datatype for the column is JSON (which means the m_format_json will be true). If it is JSON append JSON. --- mysql-test/suite/json/r/json_table.result | 54 ++++++++++++++++++++++- mysql-test/suite/json/t/json_table.test | 42 +++++++++++++++++- sql/json_table.cc | 5 ++- sql/json_table.h | 1 + 4 files changed, 98 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/json/r/json_table.result b/mysql-test/suite/json/r/json_table.result index 3bee1e06abb..9f874d6264e 100644 --- a/mysql-test/suite/json/r/json_table.result +++ b/mysql-test/suite/json/r/json_table.result @@ -1216,6 +1216,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp # # MDEV-27898 CREATE VIEW AS SELECT FROM JSON_TABLE column requires global privileges # +# Beginning of 10.11 tests create view v1 as (select * from json_table('[{"a":"1"}]', '$[*]' columns(a int path '$.a') ) as jt); create user u1@localhost; @@ -1228,4 +1229,55 @@ connection default; DROP VIEW v2; DROP VIEW v1; DROP USER u1@localhost; -# End of 10.11 tests +# +# MDEV-34081: View containing JSON_TABLE does not return JSON +# +CREATE OR REPLACE VIEW test_view AS SELECT * FROM JSON_TABLE(' +[ + { + "caption": "First Element", + "value": 1 + }, + { + "caption": "Second Element", + "value": 2 + } +] +', '$[*]' COLUMNS( +caption VARCHAR(200) PATH '$.caption', +whole_block JSON PATH '$')) t; +SELECT * FROM test_view; +caption whole_block +First Element { + "caption": "First Element", + "value": 1 + } +Second Element { + "caption": "Second Element", + "value": 2 + } +SELECT * FROM JSON_TABLE(' +[ + { + "caption": "First Element", + "value": 1 + }, + { + "caption": "Second Element", + "value": 2 + } +] +', '$[*]' COLUMNS( +caption VARCHAR(200) PATH '$.caption', +whole_block JSON PATH '$')) t; +caption whole_block +First Element { + "caption": "First Element", + "value": 1 + } +Second Element { + "caption": "Second Element", + "value": 2 + } +DROP VIEW test_view; +# End of 10.11 test diff --git a/mysql-test/suite/json/t/json_table.test b/mysql-test/suite/json/t/json_table.test index bbb6db9cc7b..aac9005cbd6 100644 --- a/mysql-test/suite/json/t/json_table.test +++ b/mysql-test/suite/json/t/json_table.test @@ -1046,6 +1046,8 @@ COLUMNS --echo # MDEV-27898 CREATE VIEW AS SELECT FROM JSON_TABLE column requires global privileges --echo # +--echo # Beginning of 10.11 tests + create view v1 as (select * from json_table('[{"a":"1"}]', '$[*]' columns(a int path '$.a') ) as jt); @@ -1063,4 +1065,42 @@ DROP VIEW v2; DROP VIEW v1; DROP USER u1@localhost; ---echo # End of 10.11 tests +--echo # +--echo # MDEV-34081: View containing JSON_TABLE does not return JSON +--echo # + +CREATE OR REPLACE VIEW test_view AS SELECT * FROM JSON_TABLE(' +[ + { + "caption": "First Element", + "value": 1 + }, + { + "caption": "Second Element", + "value": 2 + } +] +', '$[*]' COLUMNS( + caption VARCHAR(200) PATH '$.caption', + whole_block JSON PATH '$')) t; + +SELECT * FROM test_view; + +SELECT * FROM JSON_TABLE(' +[ + { + "caption": "First Element", + "value": 1 + }, + { + "caption": "Second Element", + "value": 2 + } +] +', '$[*]' COLUMNS( + caption VARCHAR(200) PATH '$.caption', + whole_block JSON PATH '$')) t; + +DROP VIEW test_view; + +--echo # End of 10.11 test diff --git a/sql/json_table.cc b/sql/json_table.cc index bb126f36b85..d3a81cc61d1 100644 --- a/sql/json_table.cc +++ b/sql/json_table.cc @@ -970,8 +970,9 @@ int Json_table_column::print(THD *thd, Field **f, String *str) (*f)->sql_type(column_type); - if (str->append(column_type) || - ((*f)->has_charset() && m_explicit_cs && + if ((m_format_json ? str->append(STRING_WITH_LEN(" JSON ")) : str->append(column_type))) + return 1; + if (((*f)->has_charset() && m_explicit_cs && (str->append(STRING_WITH_LEN(" CHARSET ")) || str->append(&m_explicit_cs->cs_name) || (Charset(m_explicit_cs).can_have_collate_clause() && diff --git a/sql/json_table.h b/sql/json_table.h index f588b6e08b0..01b97377e4a 100644 --- a/sql/json_table.h +++ b/sql/json_table.h @@ -167,6 +167,7 @@ public: { m_on_error.m_response= RESPONSE_NOT_SPECIFIED; m_on_empty.m_response= RESPONSE_NOT_SPECIFIED; + m_format_json= false; } int print(THD *tnd, Field **f, String *str); }; From f0c1477c6ac63c71c6b82750a86bf84953da2e87 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 8 Sep 2025 23:19:49 +0400 Subject: [PATCH 14/54] MDEV-7451 Server audit: Table events for partitioned tables are duplicated for each partition. Don't send notifications when partition is created. --- mysql-test/suite/plugins/r/server_audit.result | 2 ++ mysql-test/suite/plugins/t/server_audit.test | 9 +++++++++ sql/handler.cc | 7 ++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index 06b60448942..6c9a9e0ff2e 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -237,6 +237,8 @@ insert delayed into t1 values (1); connection default; # Waiting until INSERT DELAYED thread does the insert. drop table t1; +create table test_partitions (i int) partition by hash (i) partitions 4; +drop table test_partitions; set global server_audit_logging= off; set global server_audit_incl_users='root'; set global server_audit_logging= on; diff --git a/mysql-test/suite/plugins/t/server_audit.test b/mysql-test/suite/plugins/t/server_audit.test index 673bc7ff221..8ba38a521e7 100644 --- a/mysql-test/suite/plugins/t/server_audit.test +++ b/mysql-test/suite/plugins/t/server_audit.test @@ -1,5 +1,6 @@ --source include/have_plugin_auth.inc --source include/not_embedded.inc +--source include/have_partition.inc if (!$SERVER_AUDIT_SO) { skip No SERVER_AUDIT plugin; @@ -178,12 +179,20 @@ connection cn1; create table t1(id int) engine=myisam; insert delayed into t1 values (1); + connection default; + --echo # Waiting until INSERT DELAYED thread does the insert. let $wait_condition= SELECT COUNT(*) = 1 FROM t1; --source include/wait_condition.inc drop table t1; +# +# MDEV-7451 Server audit: Table events for partitioned tables are duplicated for each partition. +# +create table test_partitions (i int) partition by hash (i) partitions 4; +drop table test_partitions; + set global server_audit_logging= off; set global server_audit_incl_users='root'; set global server_audit_logging= on; diff --git a/sql/handler.cc b/sql/handler.cc index 45eb3ce5238..6219569b429 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5648,7 +5648,12 @@ handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info_arg) info_arg->options|= HA_LEX_CREATE_GLOBAL_TMP_TABLE; int error= create(name, form, info_arg); if (!error && - !(info_arg->options & (HA_LEX_CREATE_TMP_TABLE | HA_CREATE_TMP_ALTER))) + !(info_arg->options & (HA_LEX_CREATE_TMP_TABLE | HA_CREATE_TMP_ALTER)) && + /* + DO not notify if not main handler. + So skip notifications for partitions. + */ + form->file == this) mysql_audit_create_table(form); return error; } From e436481523aa43f6e6a5948862c5b6d8ac0b497c Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Thu, 23 Oct 2025 12:38:31 +1100 Subject: [PATCH 15/54] MDEV-37810 Fixup spider test combinations This is a fixup of 41725b4cee671fecf091616a1cfc8ee37d67a00f where the symlinks were incorrectly created using absolute paths. Also fix ps protocol for spider/bugfix.mdev_29502,usual_handler --- storage/spider/mysql-test/spider/bg/combinations | 6 +++++- storage/spider/mysql-test/spider/bugfix/combinations | 6 +++++- storage/spider/mysql-test/spider/bugfix/t/mdev_29502.test | 4 ++++ storage/spider/mysql-test/spider/feature/combinations | 6 +++++- .../spider/mysql-test/spider/regression/e1121/combinations | 6 +++++- .../mysql-test/spider/regression/e112122/combinations | 6 +++++- 6 files changed, 29 insertions(+), 5 deletions(-) mode change 120000 => 100644 storage/spider/mysql-test/spider/bg/combinations mode change 120000 => 100644 storage/spider/mysql-test/spider/bugfix/combinations mode change 120000 => 100644 storage/spider/mysql-test/spider/feature/combinations mode change 120000 => 100644 storage/spider/mysql-test/spider/regression/e1121/combinations mode change 120000 => 100644 storage/spider/mysql-test/spider/regression/e112122/combinations diff --git a/storage/spider/mysql-test/spider/bg/combinations b/storage/spider/mysql-test/spider/bg/combinations deleted file mode 120000 index ae8bc75d267..00000000000 --- a/storage/spider/mysql-test/spider/bg/combinations +++ /dev/null @@ -1 +0,0 @@ -/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/bg/combinations b/storage/spider/mysql-test/spider/bg/combinations new file mode 100644 index 00000000000..cad4d107176 --- /dev/null +++ b/storage/spider/mysql-test/spider/bg/combinations @@ -0,0 +1,5 @@ +[group_by_handler] +loose_spider_disable_group_by_handler=0 + +[usual_handler] +loose_spider_disable_group_by_handler=1 diff --git a/storage/spider/mysql-test/spider/bugfix/combinations b/storage/spider/mysql-test/spider/bugfix/combinations deleted file mode 120000 index ae8bc75d267..00000000000 --- a/storage/spider/mysql-test/spider/bugfix/combinations +++ /dev/null @@ -1 +0,0 @@ -/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/bugfix/combinations b/storage/spider/mysql-test/spider/bugfix/combinations new file mode 100644 index 00000000000..cad4d107176 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/combinations @@ -0,0 +1,5 @@ +[group_by_handler] +loose_spider_disable_group_by_handler=0 + +[usual_handler] +loose_spider_disable_group_by_handler=1 diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_29502.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_29502.test index 7e0bcc61df9..22633dc433f 100644 --- a/storage/spider/mysql-test/spider/bugfix/t/mdev_29502.test +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_29502.test @@ -21,6 +21,7 @@ set spider_direct_aggregate=1; eval CREATE TABLE t1 (a INT KEY) ENGINE=Spider COMMENT='WRAPPER "mysql",srv "$srv",TABLE "t"'; +--disable_ps2_protocol SELECT MAX(a) FROM t1; SELECT SUM(a) FROM t1; SELECT COUNT(a) FROM t1; @@ -32,6 +33,7 @@ SELECT COUNT(a), MAX(a), SUM(a) FROM t1; SELECT MAX(a), COUNT(a), SUM(a) FROM t1; SELECT MAX(a), MAX(COALESCE(a)) FROM t1; --enable_view_protocol +--enable_ps2_protocol SHOW STATUS LIKE 'Spider_direct_aggregate'; DROP TABLE t, t1; @@ -41,7 +43,9 @@ INSERT INTO t VALUES (23, -1),(48, 97); eval CREATE TABLE t1 (a INT, b INT) ENGINE=Spider COMMENT='WRAPPER "mysql",srv "$srv",TABLE "t"'; +--disable_ps2_protocol SELECT MAX(a + b), SUM(a - b) FROM t1; +--enable_ps2_protocol SHOW STATUS LIKE 'Spider_direct_aggregate'; DROP TABLE t, t1; diff --git a/storage/spider/mysql-test/spider/feature/combinations b/storage/spider/mysql-test/spider/feature/combinations deleted file mode 120000 index ae8bc75d267..00000000000 --- a/storage/spider/mysql-test/spider/feature/combinations +++ /dev/null @@ -1 +0,0 @@ -/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/feature/combinations b/storage/spider/mysql-test/spider/feature/combinations new file mode 100644 index 00000000000..cad4d107176 --- /dev/null +++ b/storage/spider/mysql-test/spider/feature/combinations @@ -0,0 +1,5 @@ +[group_by_handler] +loose_spider_disable_group_by_handler=0 + +[usual_handler] +loose_spider_disable_group_by_handler=1 diff --git a/storage/spider/mysql-test/spider/regression/e1121/combinations b/storage/spider/mysql-test/spider/regression/e1121/combinations deleted file mode 120000 index ae8bc75d267..00000000000 --- a/storage/spider/mysql-test/spider/regression/e1121/combinations +++ /dev/null @@ -1 +0,0 @@ -/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/regression/e1121/combinations b/storage/spider/mysql-test/spider/regression/e1121/combinations new file mode 100644 index 00000000000..cad4d107176 --- /dev/null +++ b/storage/spider/mysql-test/spider/regression/e1121/combinations @@ -0,0 +1,5 @@ +[group_by_handler] +loose_spider_disable_group_by_handler=0 + +[usual_handler] +loose_spider_disable_group_by_handler=1 diff --git a/storage/spider/mysql-test/spider/regression/e112122/combinations b/storage/spider/mysql-test/spider/regression/e112122/combinations deleted file mode 120000 index ae8bc75d267..00000000000 --- a/storage/spider/mysql-test/spider/regression/e112122/combinations +++ /dev/null @@ -1 +0,0 @@ -/home/ycp/source/mariadb-server/10.11/src/storage/spider/mysql-test/spider/combinations \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/regression/e112122/combinations b/storage/spider/mysql-test/spider/regression/e112122/combinations new file mode 100644 index 00000000000..cad4d107176 --- /dev/null +++ b/storage/spider/mysql-test/spider/regression/e112122/combinations @@ -0,0 +1,5 @@ +[group_by_handler] +loose_spider_disable_group_by_handler=0 + +[usual_handler] +loose_spider_disable_group_by_handler=1 From 413c59db32276d5912b703cedaaa768d242d12cb Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Sun, 19 Oct 2025 15:08:53 +0530 Subject: [PATCH 16/54] MDEV-27675 Incorrect r-tree split after group assignment causes page overflow Problem: ======== - When an R-tree root page becomes full and requires splitting, InnoDB follows a specific root-raising procedure to maintain tree integrity. The process involves allocating a new page (Page X) to hold the current root's content, preserving the original root page number as the tree's entry point, and migrating all existing records to Page X. The root page is then cleared and reconstructed as an internal node containing a single node pointer with an MBR that encompasses all spatial objects on Page X. Subsequently, InnoDB should split the records on Page X into two spatially optimized groups using the pick_seeds() and pick_next() algorithms, creating a second page (Page Y) for Group B records while retaining Group A records on Page X. After records are redistributed between Page X and Page Y, the recalculated MBR for Page X must remain within or be smaller than the original MBR stored in the root page's node pointer. Bug scenario: ============ - When root page 4 becomes full, it triggers a split operation where the content is copied to page 7 and root page 4 is cleared to become an internal node. - During the first split attempt on page 7, Group 1 overflows and remaining entries are reassigned to Group 2. - A new page 8 is created and the remaining entry record is inserted, but the combined size of the remaining entry record and new record exceeds the page size limit. - This triggers a second split operation on page 7, where Group 2 overflows again and entries are moved back to Group 1. - When the new record is finally inserted into page 7, it causes the MBR (Minimum Bounding Rectangle) for page 7 to expand beyond its original boundaries. - Subsequently, when InnoDB attempts to update the parent page 4 with the new MBR information, it fails to locate the corresponding internal node, leading to spatial index corruption and the reported failure. Problem: ======== - Second split operation should happen on page 8, not on page 7. - split_rtree_node() considers key_size to estimate record sizes during the splitting algorithm, which fails to account for variable-length fields in spatial records. - In rtr_page_split_and_insert(), when reorganization succeeds, InnoDB doesn't attempt the insert the entry Solution: ======== rtr_page_split_and_insert(): InnoDB should do insert the tuple when btr_page_reorganize() is successful. rtr_page_split_and_insert(): Use the overflow page for consecutive split operation. split_rtree_node(): Store the record length for each record in r-tree node. This should give proper estimation while determining the group entries and also helpful in overflow validation --- .../suite/innodb_gis/r/rtree_split.result | 104 +++++++++++++++++ .../suite/innodb_gis/t/rtree_split.test | 105 ++++++++++++++++++ storage/innobase/gis/gis0geo.cc | 8 +- storage/innobase/gis/gis0rtree.cc | 19 ++-- storage/innobase/include/gis0geo.h | 1 + 5 files changed, 225 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/innodb_gis/r/rtree_split.result b/mysql-test/suite/innodb_gis/r/rtree_split.result index 97027bde865..c5caef7f903 100644 --- a/mysql-test/suite/innodb_gis/r/rtree_split.result +++ b/mysql-test/suite/innodb_gis/r/rtree_split.result @@ -72,4 +72,108 @@ INSERT INTO t1 SELECT POINTFROMTEXT ('POINT(0 0)') FROM seq_1_to_6; ROLLBACK; SET GLOBAL innodb_limit_optimistic_insert_debug=@save_limit; DROP TABLE t1; +# +# MDEV-27675 Incorrect r-tree split after group +# assignment causes page overflow +# +CREATE TABLE t1 (f1 INT, f2 INT, f3 VARCHAR(2500), +f4 MULTIPOLYGON NOT NULL, +PRIMARY KEY (f1,f2,f3), SPATIAL(f4)) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(1,1,'id',MULTIPOLYGONFromText('MULTIPOLYGON(((0.12 0.53,0.23 0.92,0.12 0.53)))')), +(2,2,REPEAT('s',853),MULTIPOLYGONFromText('MULTIPOLYGON(((0.09 0.71,0.92 0.49,0.09 0.71)))')), +(3,3,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.62 0.71,0.62 0.71)))')), +(4,4,'j',MULTIPOLYGONFromText('MULTIPOLYGON(((0.00 0.06,0.40 0.39,0.61 0.20,0.69 0.91,0.13 0.45,0.71 0.49,0.81 0.52,0.08 0.02,0.00 0.06)))')), +(5,5,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.05 0.20,0.45 0.96,0.59 0.46,0.26 0.12,0.45 0.68,0.41 0.10,0.05 0.20)))')), +(6,6,'j',MULTIPOLYGONFromText('MULTIPOLYGON(((0.30 0.09,0.42 0.27,0.96 0.83,0.81 0.89,0.42 0.16,0.89 0.64,0.30 0.09)))')), +(7,7,'f',MULTIPOLYGONFromText('MULTIPOLYGON(((0.62 0.42,0.12 0.70,0.07 0.24,0.10 0.07,0.92 0.29,0.20 0.52,0.62 0.42)))')), +(8,8,'a',MULTIPOLYGONFromText('MULTIPOLYGON(((0.74 0.96,0.80 0.93,0.61 0.40,0.23 0.49,0.79 0.96,0.67 0.30,0.67 0.25,0.74 0.96)))')), +(9,9,'j',MULTIPOLYGONFromText('MULTIPOLYGON(((0.18 0.56,0.03 0.48,0.89 0.30,0.79 0.85,0.40 0.92,0.47 0.34,0.38 0.48,0.18 0.56)))')), +(10,10,'ko',MULTIPOLYGONFromText('MULTIPOLYGON(((0.60 0.23,0.03 0.43,0.33 0.94,0.20 0.37,0.60 0.23)))')), +(11,11,'o',MULTIPOLYGONFromText('MULTIPOLYGON(((0.94 0.33,0.16 0.47,0.94 0.33)))')), +(12,12,'bs',MULTIPOLYGONFromText('MULTIPOLYGON(((0.78 0.81,0.71 0.29,0.03 0.85,0.54 0.16,0.23 0.20,0.86 0.77,0.41 0.96,0.85 0.67,0.78 0.81)))')), +(13,13,'z',MULTIPOLYGONFromText('MULTIPOLYGON(((0.70 0.92,0.61 0.64,0.05 0.75,0.60 1.00,0.47 0.14,0.70 0.92)))')), +(14,14,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.03 0.78,0.83 0.08,0.18 0.49,0.02 0.88,0.62 0.46,0.25 0.53,0.03 0.78)))')), +(15,15,'oaz',MULTIPOLYGONFromText('MULTIPOLYGON(((0.12 0.22,0.73 0.35,0.08 0.39,0.23 0.31,0.84 0.19,0.46 0.77,0.63 0.69,0.12 0.22)))')), +(16,16,'a',MULTIPOLYGONFromText('MULTIPOLYGON(((0.50 0.49,0.48 0.69,0.25 0.87,0.85 0.62,0.96 0.28,0.07 0.70,0.45 0.79,0.87 0.36,0.50 0.49)))')), +(17,17,'cj',MULTIPOLYGONFromText('MULTIPOLYGON(((0.72 0.93,0.03 0.94,0.77 0.06,0.29 0.76,0.82 0.68,0.16 0.59,0.15 0.73,0.72 0.93)))')), +(18,18,REPEAT('r',149),MULTIPOLYGONFromText('MULTIPOLYGON(((0.02 0.67,0.05 0.90,0.68 0.02,0.02 0.67)))')), +(19,19,'ihb',MULTIPOLYGONFromText('MULTIPOLYGON(((0.61 0.40,0.77 0.06,0.61 0.40)),((0.43 0.52,0.77 0.27,0.31 0.49,0.43 0.52)))')), +(20,20,'h',MULTIPOLYGONFromText('MULTIPOLYGON(((0.37 0.98,0.88 0.84,0.18 0.47,0.15 0.77,0.82 0.92,0.66 0.55,0.60 0.02,0.17 0.09,0.37 0.98)))')), +(21,21,'i',MULTIPOLYGONFromText('MULTIPOLYGON(((0.89 0.55,0.85 0.85,0.68 0.24,0.20 0.42,0.67 0.36,0.35 0.25,0.48 0.20,0.89 0.55)))')), +(22,22,'q',MULTIPOLYGONFromText('MULTIPOLYGON(((0.67 0.40,0.63 0.18,0.80 0.66,0.65 0.47,0.66 0.56,0.64 0.97,0.00 0.92,0.66 0.18,0.67 0.40)))')), +(23,23,'kh',MULTIPOLYGONFromText('MULTIPOLYGON(((0.89 0.31,0.33 0.68,0.75 0.35,0.40 0.57,0.94 0.91,0.88 0.23,0.89 0.31)))')), +(24,24,'hbtgc',MULTIPOLYGONFromText('MULTIPOLYGON(((0.99 0.12,0.73 0.75,0.46 0.85,0.55 0.92,0.12 0.44,0.22 0.13,0.11 0.61,0.99 0.12)))')), +(25,25,REPEAT('t',71),MULTIPOLYGONFromText('MULTIPOLYGON(((0.72 0.06,0.31 0.98,0.95 0.02,0.84 0.77,0.46 0.09,0.63 0.92,0.35 0.90,0.72 0.06)))')), +(26,26,'g',MULTIPOLYGONFromText('MULTIPOLYGON(((0.18 0.27,0.28 0.15,0.18 0.27)),((0.22 0.55,0.22 0.55)),((0.28 0.70,0.28 0.70)))')), +(27,27,'c',MULTIPOLYGONFromText('MULTIPOLYGON(((0.72 0.28,0.62 0.71,0.04 1.00,0.12 0.57,0.72 0.28)))')), +(28,28,REPEAT('q',885),MULTIPOLYGONFromText('MULTIPOLYGON(((0.70 0.04,0.62 0.29,0.42 0.82,0.90 0.87,0.79 0.69,0.59 0.99,0.24 0.24,0.69 0.96,0.70 0.04)))')), +(29,29,'oy',MULTIPOLYGONFromText('MULTIPOLYGON(((0.23 0.87,0.51 0.65,0.70 0.97,0.44 0.14,0.25 0.83,0.23 0.87)))')), +(30,30,REPEAT('k',1684),MULTIPOLYGONFromText('MULTIPOLYGON(((0.99 0.78,0.78 0.99,0.76 0.51,0.25 0.31,0.13 0.86,0.16 0.11,0.45 0.94,0.23 0.98,0.99 0.78)))')), +(31,31,'ylsmiix',MULTIPOLYGONFromText('MULTIPOLYGON(((0.85 0.35,0.03 0.75,0.18 0.31,0.84 0.36,0.92 0.72,0.52 0.93,0.65 0.10,0.55 0.80,0.85 0.35)))')), +(32,32,'ojouw',MULTIPOLYGONFromText('MULTIPOLYGON(((0.72 0.00,0.83 0.45,0.32 0.62,0.36 0.40,0.19 0.95,0.50 0.38,0.30 0.76,0.72 0.00)))')), +(33,33,'ou',MULTIPOLYGONFromText('MULTIPOLYGON(((0.98 0.02,0.01 0.23,0.27 0.11,0.98 0.02)),((0.44 0.54,0.44 0.54)),((0.86 0.97,0.86 0.97)))')), +(34,34,'u',MULTIPOLYGONFromText('MULTIPOLYGON(((0.13 0.07,0.29 0.09,0.53 0.79,0.85 0.66,0.64 0.17,0.22 0.18,0.35 0.39,0.30 0.28,0.13 0.07)))')), +(35,35,'sax',MULTIPOLYGONFromText('MULTIPOLYGON(((0.26 0.03,0.24 0.93,0.15 0.48,0.26 0.03)),((0.73 0.46,0.35 0.63,0.73 0.46)))')), +(36,36,'xmet',MULTIPOLYGONFromText('MULTIPOLYGON(((0.23 0.35,0.35 0.82,0.23 0.35)),((0.29 0.61,0.82 0.54,0.29 0.61)))')), +(37,37,REPEAT('e',276),MULTIPOLYGONFromText('MULTIPOLYGON(((0.65 0.67,0.65 0.67)))')), +(38,38,'ty',MULTIPOLYGONFromText('MULTIPOLYGON(((0.43 0.44,0.64 0.76,0.92 0.59,0.73 0.23,0.43 0.44)))')), +(39,39,'yq',MULTIPOLYGONFromText('MULTIPOLYGON(((0.84 0.27,0.19 0.67,0.84 0.27)),((0.55 0.13,0.39 0.64,0.21 0.70,0.18 0.45,0.55 0.13)))')), +(40,40,'hcsv',MULTIPOLYGONFromText('MULTIPOLYGON(((0.61 0.79,0.83 0.16,0.63 0.80,0.78 0.28,0.88 0.66,0.61 0.79)))')), +(41,41,'csvhlr',MULTIPOLYGONFromText('MULTIPOLYGON(((0.82 0.24,0.31 0.52,0.61 0.67,0.99 0.90,0.05 0.73,0.52 0.18,0.71 0.87,0.82 0.24)))')), +(42,42,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.09 0.21,0.37 0.57,0.81 0.75,0.61 0.16,0.48 0.17,0.29 0.28,0.72 0.46,0.09 0.21)))')), +(43,43,'wd',MULTIPOLYGONFromText('MULTIPOLYGON(((0.06 0.25,0.52 0.23,0.02 0.05,0.06 0.25)),((0.70 0.52,0.44 0.46,0.95 0.47,0.70 0.52)))')), +(44,44,'dg',MULTIPOLYGONFromText('MULTIPOLYGON(((0.81 0.28,0.19 0.17,0.81 0.28)))')), +(45,45,'qtqkyyhkayeoopxmexd',MULTIPOLYGONFromText('MULTIPOLYGON(((0.80 0.66,0.81 0.12,0.83 0.31,0.52 0.29,0.08 0.04,0.80 0.66)))')), +(46,46,'tqk',MULTIPOLYGONFromText('MULTIPOLYGON(((0.95 0.08,0.95 0.08)),((0.09 0.31,0.09 0.31)),((0.38 0.75,0.30 0.04,0.38 0.75)))')), +(47,47,REPEAT('q',925),MULTIPOLYGONFromText('MULTIPOLYGON(((0.56 0.73,0.87 0.11,0.37 0.86,0.48 0.05,0.82 0.55,0.25 0.06,0.19 0.85,0.10 0.75,0.56 0.73)))')), +(48,48,'yhk',MULTIPOLYGONFromText('MULTIPOLYGON(((0.06 0.67,0.41 0.51,0.03 0.83,0.40 0.20,0.16 0.87,0.16 0.07,0.29 0.52,0.06 0.67)))')), +(49,49,'k',MULTIPOLYGONFromText('MULTIPOLYGON(((0.16 0.14,0.16 0.14)),((0.97 0.69,0.45 0.32,0.45 0.38,0.97 0.69)))')), +(50,50,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.70 0.00,0.70 0.00)),((0.88 0.53,0.90 0.16,0.88 0.53)))')), +(51,51,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.48 0.06,0.45 0.05,0.03 0.12,0.27 0.80,0.22 0.75,0.53 0.55,0.48 0.06)))')), +(52,52,'o',MULTIPOLYGONFromText('MULTIPOLYGON(((0.32 0.76,0.17 0.43,0.32 0.76)),((0.40 0.79,0.40 0.79)),((0.42 0.34,0.42 0.34)))')), +(53,53,'pxme',MULTIPOLYGONFromText('MULTIPOLYGON(((0.44 0.08,0.02 0.74,0.26 0.21,0.75 0.42,0.91 0.32,0.24 0.65,0.67 0.50,0.44 0.08)))')), +(54,54,'m',MULTIPOLYGONFromText('MULTIPOLYGON(((0.86 0.13,0.21 0.34,0.00 0.87,0.76 0.23,0.69 0.73,0.13 0.63,0.86 0.13)))')), +(55,55,'mex',MULTIPOLYGONFromText('MULTIPOLYGON(((0.84 0.11,0.63 0.13,0.51 0.81,0.58 0.25,0.53 0.29,0.53 0.42,0.84 0.11)))')), +(56,56,REPEAT('e',504),MULTIPOLYGONFromText('MULTIPOLYGON(((0.27 0.84,0.65 0.26,0.75 0.44,0.29 0.52,0.27 0.84)))')), +(57,57,'i',MULTIPOLYGONFromText('MULTIPOLYGON(((0.71 0.84,0.77 0.27,0.45 0.71,0.91 0.01,0.84 0.35,0.71 0.84)))')), +(58,58,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.12 0.36,0.02 0.47,0.57 0.76,0.15 0.54,0.12 0.36)))')), +(59,59,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.77 0.80,0.25 0.69,0.34 0.68,0.77 0.80)))')), +(60,60,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.57 0.30,0.58 0.81,0.57 0.30)))')), +(61,61,'nh',MULTIPOLYGONFromText('MULTIPOLYGON(((0.42 0.99,0.42 0.99)))')), +(62,62,'hwi',MULTIPOLYGONFromText('MULTIPOLYGON(((0.40 0.50,0.97 0.34,0.60 0.75,0.26 0.74,0.40 0.50)))')), +(63,63,'id',MULTIPOLYGONFromText('MULTIPOLYGON(((0.30 0.67,0.13 0.43,0.16 0.64,0.04 0.72,0.95 0.87,0.83 0.24,0.17 0.82,0.30 0.67)))')), +(64,64,'toy',MULTIPOLYGONFromText('MULTIPOLYGON(((0.68 0.75,0.92 0.90,0.68 0.75)),((0.58 0.03,0.41 0.09,0.62 0.05,0.58 0.03)))')), +(65,65,'yhawdptl',MULTIPOLYGONFromText('MULTIPOLYGON(((0.95 0.50,0.61 0.35,0.78 0.07,0.67 0.43,0.50 0.70,0.48 0.98,0.95 0.50)))')), +(66,66,'gs',MULTIPOLYGONFromText('MULTIPOLYGON(((0.59 0.06,0.12 0.94,0.05 0.90,0.99 0.22,0.13 0.55,0.59 0.06)))')), +(67,67,'bplb',MULTIPOLYGONFromText('MULTIPOLYGON(((0.33 0.90,0.54 0.11,0.05 0.04,0.59 0.66,0.33 0.90)))')), +(68,68,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.50 0.52,0.23 0.54,0.80 0.14,0.88 0.70,0.13 0.67,0.68 0.66,0.50 0.52)))')), +(69,69,'p',MULTIPOLYGONFromText('MULTIPOLYGON(((0.07 0.99,0.11 0.79,0.07 0.99)),((0.50 0.22,0.77 0.58,0.50 0.22)))')), +(70,70,'l',MULTIPOLYGONFromText('MULTIPOLYGON(((0.21 0.75,0.21 0.75)))')), +(71,71,'rwkqhip',MULTIPOLYGONFromText('MULTIPOLYGON(((0.99 0.89,0.25 0.77,0.99 0.89)))')), +(72,72,'n',MULTIPOLYGONFromText('MULTIPOLYGON(((0.01 0.10,0.01 0.20,0.01 0.10)),((0.83 0.75,0.29 0.21,0.83 0.75)))')), +(73,73,'q',MULTIPOLYGONFromText('MULTIPOLYGON(((0.12 0.03,0.51 0.05,0.27 0.77,0.74 0.06,0.12 0.03)))')), +(74,74,'hipd',MULTIPOLYGONFromText('MULTIPOLYGON(((0.89 0.94,0.54 0.92,0.37 0.71,0.89 0.94)))')), +(75,75,'ipdec',MULTIPOLYGONFromText('MULTIPOLYGON(((0.50 0.48,0.07 0.31,0.19 0.23,0.51 0.74,0.50 0.48)))')), +(76,76,'pde',MULTIPOLYGONFromText('MULTIPOLYGON(((0.79 0.42,0.61 0.98,0.13 0.85,0.52 0.16,0.79 0.42)))')), +(77,77,REPEAT('e',1432),MULTIPOLYGONFromText('MULTIPOLYGON(((0.78 0.29,0.42 0.20,0.88 0.86,0.99 0.81,0.78 0.29)))')), +(78,78,'cyhr',MULTIPOLYGONFromText('MULTIPOLYGON(((0.61 0.16,0.62 0.19,0.61 0.16)),((0.62 0.94,0.65 0.53,0.15 0.25,0.71 0.41,0.62 0.94)),((0.67 0.63,0.86 0.60,0.67 0.63)))')), +(79,79,'n',MULTIPOLYGONFromText('MULTIPOLYGON(((0.39 0.89,0.25 0.77,0.22 0.21,0.51 0.19,0.71 0.51,0.39 0.89)))')), +(80,80,'y',MULTIPOLYGONFromText('MULTIPOLYGON(((0.29 0.36,0.29 0.36)))')), +(81,81,'r',MULTIPOLYGONFromText('MULTIPOLYGON(((0.05 0.94,0.93 0.37,0.22 0.07,0.73 0.75,0.99 0.35,0.05 0.94)))')), +(82,82,'w',MULTIPOLYGONFromText('MULTIPOLYGON(((0.33 0.37,0.06 0.59,0.34 0.82,0.73 0.86,0.18 0.78,0.99 0.03,0.33 0.37)))')), +(83,83,REPEAT('g',74),MULTIPOLYGONFromText('MULTIPOLYGON(((0.60 0.54,0.25 0.31,0.60 0.54)))')), +(84,84,REPEAT('s',214),MULTIPOLYGONFromText('MULTIPOLYGON(((0.80 0.34,0.09 0.74,0.47 0.96,0.55 0.19,0.80 0.34)))')), +(85,85,REPEAT('h',223),MULTIPOLYGONFromText('MULTIPOLYGON(((0.76 0.26,0.16 0.85,0.91 0.75,0.64 0.83,0.47 0.02,0.92 0.58,0.76 0.26)))')), +(86,86,'l',MULTIPOLYGONFromText('MULTIPOLYGON(((0.11 0.64,0.41 0.64,0.64 0.64,0.11 0.64)))')), +(87,87,'hj',MULTIPOLYGONFromText('MULTIPOLYGON(((0.66 1.00,0.21 0.96,0.52 0.44,0.94 0.06,0.80 0.39,0.33 0.57,0.30 0.89,0.66 1.00)))')), +(88,88,'axcs',MULTIPOLYGONFromText('MULTIPOLYGON(((0.20 0.66,0.71 0.41,0.32 0.94,0.30 0.66,0.50 0.49,0.60 0.67,0.20 0.66)))')), +(89,89,'cs',MULTIPOLYGONFromText('MULTIPOLYGON(((0.02 0.69,0.80 0.21,0.09 0.23,0.45 0.66,0.10 0.72,0.02 0.69)))')), +(90,90,'f',MULTIPOLYGONFromText('MULTIPOLYGON(((0.87 0.14,0.54 0.83,0.87 0.42,0.36 0.58,0.87 0.14)))')), +(91,91,'icq',MULTIPOLYGONFromText('MULTIPOLYGON(((0.73 0.57,0.36 0.41,0.86 0.33,0.76 0.49,0.44 0.83,0.73 0.57)))')), +(92,92,REPEAT('z',783),MULTIPOLYGONFromText('MULTIPOLYGON(((0.28 0.98,0.05 0.26,0.09 0.59,1.00 0.17,0.55 0.68,0.12 0.04,0.28 0.98)))')), +(93,93,'z',MULTIPOLYGONFromText('MULTIPOLYGON(((0.05 0.89,0.05 0.89)))')), +(94,94,REPEAT('x',1412),MULTIPOLYGONFromText('MULTIPOLYGON(((0.79 0.83,0.12 0.49,0.54 0.63,0.79 0.83)))')), +(95,95,REPEAT('u',2500),MULTIPOLYGONFromText('MULTIPOLYGON(((0.50 0.55,0.13 0.19,0.72 0.06,0.50 0.55)),((0.73 0.92,0.02 0.48,0.73 0.92)))')); +DROP TABLE t1; # End of 10.6 tests diff --git a/mysql-test/suite/innodb_gis/t/rtree_split.test b/mysql-test/suite/innodb_gis/t/rtree_split.test index a23315dc3f3..e21d5dd02dc 100644 --- a/mysql-test/suite/innodb_gis/t/rtree_split.test +++ b/mysql-test/suite/innodb_gis/t/rtree_split.test @@ -87,4 +87,109 @@ ROLLBACK; SET GLOBAL innodb_limit_optimistic_insert_debug=@save_limit; DROP TABLE t1; +--echo # +--echo # MDEV-27675 Incorrect r-tree split after group +--echo # assignment causes page overflow +--echo # +CREATE TABLE t1 (f1 INT, f2 INT, f3 VARCHAR(2500), + f4 MULTIPOLYGON NOT NULL, + PRIMARY KEY (f1,f2,f3), SPATIAL(f4)) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(1,1,'id',MULTIPOLYGONFromText('MULTIPOLYGON(((0.12 0.53,0.23 0.92,0.12 0.53)))')), +(2,2,REPEAT('s',853),MULTIPOLYGONFromText('MULTIPOLYGON(((0.09 0.71,0.92 0.49,0.09 0.71)))')), +(3,3,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.62 0.71,0.62 0.71)))')), +(4,4,'j',MULTIPOLYGONFromText('MULTIPOLYGON(((0.00 0.06,0.40 0.39,0.61 0.20,0.69 0.91,0.13 0.45,0.71 0.49,0.81 0.52,0.08 0.02,0.00 0.06)))')), +(5,5,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.05 0.20,0.45 0.96,0.59 0.46,0.26 0.12,0.45 0.68,0.41 0.10,0.05 0.20)))')), +(6,6,'j',MULTIPOLYGONFromText('MULTIPOLYGON(((0.30 0.09,0.42 0.27,0.96 0.83,0.81 0.89,0.42 0.16,0.89 0.64,0.30 0.09)))')), +(7,7,'f',MULTIPOLYGONFromText('MULTIPOLYGON(((0.62 0.42,0.12 0.70,0.07 0.24,0.10 0.07,0.92 0.29,0.20 0.52,0.62 0.42)))')), +(8,8,'a',MULTIPOLYGONFromText('MULTIPOLYGON(((0.74 0.96,0.80 0.93,0.61 0.40,0.23 0.49,0.79 0.96,0.67 0.30,0.67 0.25,0.74 0.96)))')), +(9,9,'j',MULTIPOLYGONFromText('MULTIPOLYGON(((0.18 0.56,0.03 0.48,0.89 0.30,0.79 0.85,0.40 0.92,0.47 0.34,0.38 0.48,0.18 0.56)))')), +(10,10,'ko',MULTIPOLYGONFromText('MULTIPOLYGON(((0.60 0.23,0.03 0.43,0.33 0.94,0.20 0.37,0.60 0.23)))')), +(11,11,'o',MULTIPOLYGONFromText('MULTIPOLYGON(((0.94 0.33,0.16 0.47,0.94 0.33)))')), +(12,12,'bs',MULTIPOLYGONFromText('MULTIPOLYGON(((0.78 0.81,0.71 0.29,0.03 0.85,0.54 0.16,0.23 0.20,0.86 0.77,0.41 0.96,0.85 0.67,0.78 0.81)))')), +(13,13,'z',MULTIPOLYGONFromText('MULTIPOLYGON(((0.70 0.92,0.61 0.64,0.05 0.75,0.60 1.00,0.47 0.14,0.70 0.92)))')), +(14,14,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.03 0.78,0.83 0.08,0.18 0.49,0.02 0.88,0.62 0.46,0.25 0.53,0.03 0.78)))')), +(15,15,'oaz',MULTIPOLYGONFromText('MULTIPOLYGON(((0.12 0.22,0.73 0.35,0.08 0.39,0.23 0.31,0.84 0.19,0.46 0.77,0.63 0.69,0.12 0.22)))')), +(16,16,'a',MULTIPOLYGONFromText('MULTIPOLYGON(((0.50 0.49,0.48 0.69,0.25 0.87,0.85 0.62,0.96 0.28,0.07 0.70,0.45 0.79,0.87 0.36,0.50 0.49)))')), +(17,17,'cj',MULTIPOLYGONFromText('MULTIPOLYGON(((0.72 0.93,0.03 0.94,0.77 0.06,0.29 0.76,0.82 0.68,0.16 0.59,0.15 0.73,0.72 0.93)))')), +(18,18,REPEAT('r',149),MULTIPOLYGONFromText('MULTIPOLYGON(((0.02 0.67,0.05 0.90,0.68 0.02,0.02 0.67)))')), +(19,19,'ihb',MULTIPOLYGONFromText('MULTIPOLYGON(((0.61 0.40,0.77 0.06,0.61 0.40)),((0.43 0.52,0.77 0.27,0.31 0.49,0.43 0.52)))')), +(20,20,'h',MULTIPOLYGONFromText('MULTIPOLYGON(((0.37 0.98,0.88 0.84,0.18 0.47,0.15 0.77,0.82 0.92,0.66 0.55,0.60 0.02,0.17 0.09,0.37 0.98)))')), +(21,21,'i',MULTIPOLYGONFromText('MULTIPOLYGON(((0.89 0.55,0.85 0.85,0.68 0.24,0.20 0.42,0.67 0.36,0.35 0.25,0.48 0.20,0.89 0.55)))')), +(22,22,'q',MULTIPOLYGONFromText('MULTIPOLYGON(((0.67 0.40,0.63 0.18,0.80 0.66,0.65 0.47,0.66 0.56,0.64 0.97,0.00 0.92,0.66 0.18,0.67 0.40)))')), +(23,23,'kh',MULTIPOLYGONFromText('MULTIPOLYGON(((0.89 0.31,0.33 0.68,0.75 0.35,0.40 0.57,0.94 0.91,0.88 0.23,0.89 0.31)))')), +(24,24,'hbtgc',MULTIPOLYGONFromText('MULTIPOLYGON(((0.99 0.12,0.73 0.75,0.46 0.85,0.55 0.92,0.12 0.44,0.22 0.13,0.11 0.61,0.99 0.12)))')), +(25,25,REPEAT('t',71),MULTIPOLYGONFromText('MULTIPOLYGON(((0.72 0.06,0.31 0.98,0.95 0.02,0.84 0.77,0.46 0.09,0.63 0.92,0.35 0.90,0.72 0.06)))')), +(26,26,'g',MULTIPOLYGONFromText('MULTIPOLYGON(((0.18 0.27,0.28 0.15,0.18 0.27)),((0.22 0.55,0.22 0.55)),((0.28 0.70,0.28 0.70)))')), +(27,27,'c',MULTIPOLYGONFromText('MULTIPOLYGON(((0.72 0.28,0.62 0.71,0.04 1.00,0.12 0.57,0.72 0.28)))')), +(28,28,REPEAT('q',885),MULTIPOLYGONFromText('MULTIPOLYGON(((0.70 0.04,0.62 0.29,0.42 0.82,0.90 0.87,0.79 0.69,0.59 0.99,0.24 0.24,0.69 0.96,0.70 0.04)))')), +(29,29,'oy',MULTIPOLYGONFromText('MULTIPOLYGON(((0.23 0.87,0.51 0.65,0.70 0.97,0.44 0.14,0.25 0.83,0.23 0.87)))')), +(30,30,REPEAT('k',1684),MULTIPOLYGONFromText('MULTIPOLYGON(((0.99 0.78,0.78 0.99,0.76 0.51,0.25 0.31,0.13 0.86,0.16 0.11,0.45 0.94,0.23 0.98,0.99 0.78)))')), +(31,31,'ylsmiix',MULTIPOLYGONFromText('MULTIPOLYGON(((0.85 0.35,0.03 0.75,0.18 0.31,0.84 0.36,0.92 0.72,0.52 0.93,0.65 0.10,0.55 0.80,0.85 0.35)))')), +(32,32,'ojouw',MULTIPOLYGONFromText('MULTIPOLYGON(((0.72 0.00,0.83 0.45,0.32 0.62,0.36 0.40,0.19 0.95,0.50 0.38,0.30 0.76,0.72 0.00)))')), +(33,33,'ou',MULTIPOLYGONFromText('MULTIPOLYGON(((0.98 0.02,0.01 0.23,0.27 0.11,0.98 0.02)),((0.44 0.54,0.44 0.54)),((0.86 0.97,0.86 0.97)))')), +(34,34,'u',MULTIPOLYGONFromText('MULTIPOLYGON(((0.13 0.07,0.29 0.09,0.53 0.79,0.85 0.66,0.64 0.17,0.22 0.18,0.35 0.39,0.30 0.28,0.13 0.07)))')), +(35,35,'sax',MULTIPOLYGONFromText('MULTIPOLYGON(((0.26 0.03,0.24 0.93,0.15 0.48,0.26 0.03)),((0.73 0.46,0.35 0.63,0.73 0.46)))')), +(36,36,'xmet',MULTIPOLYGONFromText('MULTIPOLYGON(((0.23 0.35,0.35 0.82,0.23 0.35)),((0.29 0.61,0.82 0.54,0.29 0.61)))')), +(37,37,REPEAT('e',276),MULTIPOLYGONFromText('MULTIPOLYGON(((0.65 0.67,0.65 0.67)))')), +(38,38,'ty',MULTIPOLYGONFromText('MULTIPOLYGON(((0.43 0.44,0.64 0.76,0.92 0.59,0.73 0.23,0.43 0.44)))')), +(39,39,'yq',MULTIPOLYGONFromText('MULTIPOLYGON(((0.84 0.27,0.19 0.67,0.84 0.27)),((0.55 0.13,0.39 0.64,0.21 0.70,0.18 0.45,0.55 0.13)))')), +(40,40,'hcsv',MULTIPOLYGONFromText('MULTIPOLYGON(((0.61 0.79,0.83 0.16,0.63 0.80,0.78 0.28,0.88 0.66,0.61 0.79)))')), +(41,41,'csvhlr',MULTIPOLYGONFromText('MULTIPOLYGON(((0.82 0.24,0.31 0.52,0.61 0.67,0.99 0.90,0.05 0.73,0.52 0.18,0.71 0.87,0.82 0.24)))')), +(42,42,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.09 0.21,0.37 0.57,0.81 0.75,0.61 0.16,0.48 0.17,0.29 0.28,0.72 0.46,0.09 0.21)))')), +(43,43,'wd',MULTIPOLYGONFromText('MULTIPOLYGON(((0.06 0.25,0.52 0.23,0.02 0.05,0.06 0.25)),((0.70 0.52,0.44 0.46,0.95 0.47,0.70 0.52)))')), +(44,44,'dg',MULTIPOLYGONFromText('MULTIPOLYGON(((0.81 0.28,0.19 0.17,0.81 0.28)))')), +(45,45,'qtqkyyhkayeoopxmexd',MULTIPOLYGONFromText('MULTIPOLYGON(((0.80 0.66,0.81 0.12,0.83 0.31,0.52 0.29,0.08 0.04,0.80 0.66)))')), +(46,46,'tqk',MULTIPOLYGONFromText('MULTIPOLYGON(((0.95 0.08,0.95 0.08)),((0.09 0.31,0.09 0.31)),((0.38 0.75,0.30 0.04,0.38 0.75)))')), +(47,47,REPEAT('q',925),MULTIPOLYGONFromText('MULTIPOLYGON(((0.56 0.73,0.87 0.11,0.37 0.86,0.48 0.05,0.82 0.55,0.25 0.06,0.19 0.85,0.10 0.75,0.56 0.73)))')), +(48,48,'yhk',MULTIPOLYGONFromText('MULTIPOLYGON(((0.06 0.67,0.41 0.51,0.03 0.83,0.40 0.20,0.16 0.87,0.16 0.07,0.29 0.52,0.06 0.67)))')), +(49,49,'k',MULTIPOLYGONFromText('MULTIPOLYGON(((0.16 0.14,0.16 0.14)),((0.97 0.69,0.45 0.32,0.45 0.38,0.97 0.69)))')), +(50,50,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.70 0.00,0.70 0.00)),((0.88 0.53,0.90 0.16,0.88 0.53)))')), +(51,51,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.48 0.06,0.45 0.05,0.03 0.12,0.27 0.80,0.22 0.75,0.53 0.55,0.48 0.06)))')), +(52,52,'o',MULTIPOLYGONFromText('MULTIPOLYGON(((0.32 0.76,0.17 0.43,0.32 0.76)),((0.40 0.79,0.40 0.79)),((0.42 0.34,0.42 0.34)))')), +(53,53,'pxme',MULTIPOLYGONFromText('MULTIPOLYGON(((0.44 0.08,0.02 0.74,0.26 0.21,0.75 0.42,0.91 0.32,0.24 0.65,0.67 0.50,0.44 0.08)))')), +(54,54,'m',MULTIPOLYGONFromText('MULTIPOLYGON(((0.86 0.13,0.21 0.34,0.00 0.87,0.76 0.23,0.69 0.73,0.13 0.63,0.86 0.13)))')), +(55,55,'mex',MULTIPOLYGONFromText('MULTIPOLYGON(((0.84 0.11,0.63 0.13,0.51 0.81,0.58 0.25,0.53 0.29,0.53 0.42,0.84 0.11)))')), +(56,56,REPEAT('e',504),MULTIPOLYGONFromText('MULTIPOLYGON(((0.27 0.84,0.65 0.26,0.75 0.44,0.29 0.52,0.27 0.84)))')), +(57,57,'i',MULTIPOLYGONFromText('MULTIPOLYGON(((0.71 0.84,0.77 0.27,0.45 0.71,0.91 0.01,0.84 0.35,0.71 0.84)))')), +(58,58,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.12 0.36,0.02 0.47,0.57 0.76,0.15 0.54,0.12 0.36)))')), +(59,59,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.77 0.80,0.25 0.69,0.34 0.68,0.77 0.80)))')), +(60,60,'',MULTIPOLYGONFromText('MULTIPOLYGON(((0.57 0.30,0.58 0.81,0.57 0.30)))')), +(61,61,'nh',MULTIPOLYGONFromText('MULTIPOLYGON(((0.42 0.99,0.42 0.99)))')), +(62,62,'hwi',MULTIPOLYGONFromText('MULTIPOLYGON(((0.40 0.50,0.97 0.34,0.60 0.75,0.26 0.74,0.40 0.50)))')), +(63,63,'id',MULTIPOLYGONFromText('MULTIPOLYGON(((0.30 0.67,0.13 0.43,0.16 0.64,0.04 0.72,0.95 0.87,0.83 0.24,0.17 0.82,0.30 0.67)))')), +(64,64,'toy',MULTIPOLYGONFromText('MULTIPOLYGON(((0.68 0.75,0.92 0.90,0.68 0.75)),((0.58 0.03,0.41 0.09,0.62 0.05,0.58 0.03)))')), +(65,65,'yhawdptl',MULTIPOLYGONFromText('MULTIPOLYGON(((0.95 0.50,0.61 0.35,0.78 0.07,0.67 0.43,0.50 0.70,0.48 0.98,0.95 0.50)))')), +(66,66,'gs',MULTIPOLYGONFromText('MULTIPOLYGON(((0.59 0.06,0.12 0.94,0.05 0.90,0.99 0.22,0.13 0.55,0.59 0.06)))')), +(67,67,'bplb',MULTIPOLYGONFromText('MULTIPOLYGON(((0.33 0.90,0.54 0.11,0.05 0.04,0.59 0.66,0.33 0.90)))')), +(68,68,'b',MULTIPOLYGONFromText('MULTIPOLYGON(((0.50 0.52,0.23 0.54,0.80 0.14,0.88 0.70,0.13 0.67,0.68 0.66,0.50 0.52)))')), +(69,69,'p',MULTIPOLYGONFromText('MULTIPOLYGON(((0.07 0.99,0.11 0.79,0.07 0.99)),((0.50 0.22,0.77 0.58,0.50 0.22)))')), +(70,70,'l',MULTIPOLYGONFromText('MULTIPOLYGON(((0.21 0.75,0.21 0.75)))')), +(71,71,'rwkqhip',MULTIPOLYGONFromText('MULTIPOLYGON(((0.99 0.89,0.25 0.77,0.99 0.89)))')), +(72,72,'n',MULTIPOLYGONFromText('MULTIPOLYGON(((0.01 0.10,0.01 0.20,0.01 0.10)),((0.83 0.75,0.29 0.21,0.83 0.75)))')), +(73,73,'q',MULTIPOLYGONFromText('MULTIPOLYGON(((0.12 0.03,0.51 0.05,0.27 0.77,0.74 0.06,0.12 0.03)))')), +(74,74,'hipd',MULTIPOLYGONFromText('MULTIPOLYGON(((0.89 0.94,0.54 0.92,0.37 0.71,0.89 0.94)))')), +(75,75,'ipdec',MULTIPOLYGONFromText('MULTIPOLYGON(((0.50 0.48,0.07 0.31,0.19 0.23,0.51 0.74,0.50 0.48)))')), +(76,76,'pde',MULTIPOLYGONFromText('MULTIPOLYGON(((0.79 0.42,0.61 0.98,0.13 0.85,0.52 0.16,0.79 0.42)))')), +(77,77,REPEAT('e',1432),MULTIPOLYGONFromText('MULTIPOLYGON(((0.78 0.29,0.42 0.20,0.88 0.86,0.99 0.81,0.78 0.29)))')), +(78,78,'cyhr',MULTIPOLYGONFromText('MULTIPOLYGON(((0.61 0.16,0.62 0.19,0.61 0.16)),((0.62 0.94,0.65 0.53,0.15 0.25,0.71 0.41,0.62 0.94)),((0.67 0.63,0.86 0.60,0.67 0.63)))')), +(79,79,'n',MULTIPOLYGONFromText('MULTIPOLYGON(((0.39 0.89,0.25 0.77,0.22 0.21,0.51 0.19,0.71 0.51,0.39 0.89)))')), +(80,80,'y',MULTIPOLYGONFromText('MULTIPOLYGON(((0.29 0.36,0.29 0.36)))')), +(81,81,'r',MULTIPOLYGONFromText('MULTIPOLYGON(((0.05 0.94,0.93 0.37,0.22 0.07,0.73 0.75,0.99 0.35,0.05 0.94)))')), +(82,82,'w',MULTIPOLYGONFromText('MULTIPOLYGON(((0.33 0.37,0.06 0.59,0.34 0.82,0.73 0.86,0.18 0.78,0.99 0.03,0.33 0.37)))')), +(83,83,REPEAT('g',74),MULTIPOLYGONFromText('MULTIPOLYGON(((0.60 0.54,0.25 0.31,0.60 0.54)))')), +(84,84,REPEAT('s',214),MULTIPOLYGONFromText('MULTIPOLYGON(((0.80 0.34,0.09 0.74,0.47 0.96,0.55 0.19,0.80 0.34)))')), +(85,85,REPEAT('h',223),MULTIPOLYGONFromText('MULTIPOLYGON(((0.76 0.26,0.16 0.85,0.91 0.75,0.64 0.83,0.47 0.02,0.92 0.58,0.76 0.26)))')), +(86,86,'l',MULTIPOLYGONFromText('MULTIPOLYGON(((0.11 0.64,0.41 0.64,0.64 0.64,0.11 0.64)))')), +(87,87,'hj',MULTIPOLYGONFromText('MULTIPOLYGON(((0.66 1.00,0.21 0.96,0.52 0.44,0.94 0.06,0.80 0.39,0.33 0.57,0.30 0.89,0.66 1.00)))')), +(88,88,'axcs',MULTIPOLYGONFromText('MULTIPOLYGON(((0.20 0.66,0.71 0.41,0.32 0.94,0.30 0.66,0.50 0.49,0.60 0.67,0.20 0.66)))')), +(89,89,'cs',MULTIPOLYGONFromText('MULTIPOLYGON(((0.02 0.69,0.80 0.21,0.09 0.23,0.45 0.66,0.10 0.72,0.02 0.69)))')), +(90,90,'f',MULTIPOLYGONFromText('MULTIPOLYGON(((0.87 0.14,0.54 0.83,0.87 0.42,0.36 0.58,0.87 0.14)))')), +(91,91,'icq',MULTIPOLYGONFromText('MULTIPOLYGON(((0.73 0.57,0.36 0.41,0.86 0.33,0.76 0.49,0.44 0.83,0.73 0.57)))')), +(92,92,REPEAT('z',783),MULTIPOLYGONFromText('MULTIPOLYGON(((0.28 0.98,0.05 0.26,0.09 0.59,1.00 0.17,0.55 0.68,0.12 0.04,0.28 0.98)))')), +(93,93,'z',MULTIPOLYGONFromText('MULTIPOLYGON(((0.05 0.89,0.05 0.89)))')), +(94,94,REPEAT('x',1412),MULTIPOLYGONFromText('MULTIPOLYGON(((0.79 0.83,0.12 0.49,0.54 0.63,0.79 0.83)))')), +(95,95,REPEAT('u',2500),MULTIPOLYGONFromText('MULTIPOLYGON(((0.50 0.55,0.13 0.19,0.72 0.06,0.50 0.55)),((0.73 0.92,0.02 0.48,0.73 0.92)))')); +DROP TABLE t1; + --echo # End of 10.6 tests diff --git a/storage/innobase/gis/gis0geo.cc b/storage/innobase/gis/gis0geo.cc index 4c3ff1881d0..20744b17d9c 100644 --- a/storage/innobase/gis/gis0geo.cc +++ b/storage/innobase/gis/gis0geo.cc @@ -542,9 +542,9 @@ split_rtree_node( b->n_node = 2; copy_coords(g1, a->coords, n_dim); - size1 += key_size; + size1 += a->key_len; copy_coords(g2, b->coords, n_dim); - size2 += key_size; + size2 += b->key_len; for (i = n_entries - 2; i > 0; --i) { /* Can't write into group 2 */ @@ -561,10 +561,10 @@ split_rtree_node( pick_next(node, n_entries, g1, g2, &next, &next_node, n_dim); if (next_node == 1) { - size1 += key_size; + size1 += next->key_len; mbr_join(g1, next->coords, n_dim); } else { - size2 += key_size; + size2 += next->key_len; mbr_join(g2, next->coords, n_dim); } diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc index 0a7a364be6d..47611e8df83 100644 --- a/storage/innobase/gis/gis0rtree.cc +++ b/storage/innobase/gis/gis0rtree.cc @@ -97,6 +97,7 @@ rtr_page_split_initialize_nodes( for (cur = task; cur < stop - 1; ++cur) { cur->coords = reserve_coords(buf_pos, SPDIMS); cur->key = rec; + cur->key_len = static_cast(len); memcpy(cur->coords, source_cur, DATA_MBR_LEN); @@ -110,11 +111,11 @@ rtr_page_split_initialize_nodes( source_cur = static_cast(dfield_get_data( dtuple_get_nth_field(tuple, 0))); cur->coords = reserve_coords(buf_pos, SPDIMS); - rec = (byte*) mem_heap_alloc( - heap, rec_get_converted_size(cursor->index(), tuple, 0)); - + len = rec_get_converted_size(cursor->index(), tuple, 0); + rec = (byte*) mem_heap_alloc(heap, len); rec = rec_convert_dtuple_to_rec(rec, cursor->index(), tuple, 0); cur->key = rec; + cur->key_len = static_cast(len); memcpy(cur->coords, source_cur, DATA_MBR_LEN); @@ -1106,8 +1107,10 @@ corrupted: /* Reposition the cursor for insert and try insertion */ page_cursor = btr_cur_get_page_cur(cursor); - page_cursor->block = cur_split_node->n_node != first_rec_group - ? new_block : block; + buf_block_t *insert_block = (cur_split_node->n_node != first_rec_group) + ? new_block + : block; + page_cursor->block = insert_block; ulint up_match = 0, low_match = 0; @@ -1134,7 +1137,7 @@ corrupted: attempted this already. */ if (rec == NULL) { if (!is_page_cur_get_page_zip(page_cursor) - && btr_page_reorganize(page_cursor, mtr)) { + && !btr_page_reorganize(page_cursor, mtr)) { rec = page_cur_tuple_insert(page_cursor, tuple, offsets, heap, n_ext, mtr); @@ -1194,11 +1197,11 @@ after_insert: IF_DBUG(iterated=true,); rec_t* i_rec = page_rec_get_next(page_get_infimum_rec( - buf_block_get_frame(block))); + buf_block_get_frame(insert_block))); if (UNIV_UNLIKELY(!i_rec)) { goto corrupted; } - btr_cur_position(cursor->index(), i_rec, block, cursor); + btr_cur_position(cursor->index(), i_rec, insert_block, cursor); goto func_start; } diff --git a/storage/innobase/include/gis0geo.h b/storage/innobase/include/gis0geo.h index 3fd01a3ae54..9ce6f621cf9 100644 --- a/storage/innobase/include/gis0geo.h +++ b/storage/innobase/include/gis0geo.h @@ -72,6 +72,7 @@ struct rtr_split_node_t double square; /* square of the mbr.*/ int n_node; /* which group in.*/ uchar* key; /* key. */ + uint16_t key_len; /* key length */ double* coords; /* mbr. */ }; From 3fd03e4b2c39433d175ee81535f15c2f940c0c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 23 Oct 2025 07:36:12 +0300 Subject: [PATCH 17/54] MDEV-27675 review fixup rtree_mbr_from_wkb::n_node: Change the data type from int to uint16_t and pack it together with the added field key_len. In this way, an increase of sizeof(rtree_mbr_from_wkb) will be avoided. --- storage/innobase/gis/gis0geo.cc | 6 +++--- storage/innobase/include/gis0geo.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/storage/innobase/gis/gis0geo.cc b/storage/innobase/gis/gis0geo.cc index 20744b17d9c..28d39d11610 100644 --- a/storage/innobase/gis/gis0geo.cc +++ b/storage/innobase/gis/gis0geo.cc @@ -445,7 +445,7 @@ pick_next( double* g1, /*!< in: mbr of group 1. */ double* g2, /*!< in: mbr of group 2. */ rtr_split_node_t** choice, /*!< out: the next node.*/ - int* n_group, /*!< out: group number.*/ + uint16_t* n_group, /*!< out: 1 or 2 */ int n_dim) /*!< in: dimensions. */ { rtr_split_node_t* cur = node; @@ -487,7 +487,7 @@ mark_all_entries( /*=============*/ rtr_split_node_t* node, /*!< in/out: split nodes. */ int n_entries, /*!< in: entries number. */ - int n_group) /*!< in: group number. */ + uint16_t n_group) /*!< in: 1 or 2 */ { rtr_split_node_t* cur = node; rtr_split_node_t* end = node + n_entries; @@ -522,7 +522,7 @@ split_rtree_node( double* g1 = reserve_coords(d_buffer, n_dim); double* g2 = reserve_coords(d_buffer, n_dim); rtr_split_node_t* next = NULL; - int next_node = 0; + uint16_t next_node = 0; int i; int first_rec_group = 1; rtr_split_node_t* end = node + n_entries; diff --git a/storage/innobase/include/gis0geo.h b/storage/innobase/include/gis0geo.h index 9ce6f621cf9..906f0507dde 100644 --- a/storage/innobase/include/gis0geo.h +++ b/storage/innobase/include/gis0geo.h @@ -70,9 +70,9 @@ rtree_mbr_from_wkb( struct rtr_split_node_t { double square; /* square of the mbr.*/ - int n_node; /* which group in.*/ - uchar* key; /* key. */ + uint16_t n_node; /* group: 1 or 2, or 0=unassigned */ uint16_t key_len; /* key length */ + uchar* key; /* key. */ double* coords; /* mbr. */ }; From fa9ab779ca358d24ff9d6da95973153833a76353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 23 Oct 2025 09:08:08 +0300 Subject: [PATCH 18/54] MDEV-36545: Possible crash in row_raw_format_str() row_raw_format_str(): Treat the invalid value charset_coll==0 as binary. This could be invoked on FTS_%_CONFIG.key or SYS_FOREIGN.ID or possible other key columns. dtype_is_utf8(): Merge to its only caller row_raw_format_str(). row_raw_format(): Add debug assertions and comments to document when dtype_get_charset_coll(prtype) may be 0. --- storage/innobase/include/data0type.h | 10 ---------- storage/innobase/include/data0type.inl | 25 ------------------------ storage/innobase/row/row0row.cc | 27 +++++++++++++++++--------- 3 files changed, 18 insertions(+), 44 deletions(-) diff --git a/storage/innobase/include/data0type.h b/storage/innobase/include/data0type.h index 3d63ddb767c..2c5d38996d1 100644 --- a/storage/innobase/include/data0type.h +++ b/storage/innobase/include/data0type.h @@ -353,16 +353,6 @@ dtype_form_prtype(ulint old_prtype, ulint charset_coll) return(uint32_t(old_prtype + (charset_coll << 16))); } -/*********************************************************************//** -Determines if a MySQL string type is a subset of UTF-8. This function -may return false negatives, in case further character-set collation -codes are introduced in MySQL later. -@return whether a subset of UTF-8 */ -UNIV_INLINE -bool -dtype_is_utf8( -/*==========*/ - ulint prtype);/*!< in: precise data type */ /*********************************************************************//** Gets the type length. @return fixed length of the type, in bytes, or 0 if variable-length */ diff --git a/storage/innobase/include/data0type.inl b/storage/innobase/include/data0type.inl index 329cee5d190..72834eae5fb 100644 --- a/storage/innobase/include/data0type.inl +++ b/storage/innobase/include/data0type.inl @@ -27,31 +27,6 @@ Created 1/16/1996 Heikki Tuuri #include "mach0data.h" #include "ha_prototypes.h" -/*********************************************************************//** -Determines if a MySQL string type is a subset of UTF-8. This function -may return false negatives, in case further character-set collation -codes are introduced in MySQL later. -@return whether a subset of UTF-8 */ -UNIV_INLINE -bool -dtype_is_utf8( -/*==========*/ - ulint prtype) /*!< in: precise data type */ -{ - /* These codes have been copied from strings/ctype-extra.c - and strings/ctype-utf8.c. */ - switch (dtype_get_charset_coll(prtype)) { - case 11: /* ascii_general_ci */ - case 65: /* ascii_bin */ - case 33: /* utf8_general_ci */ - case 83: /* utf8_bin */ - case 254: /* utf8_general_cs */ - return true; - } - - return false; -} - /*********************************************************************//** Gets the MySQL type code from a dtype. @return MySQL type code; this is NOT an InnoDB type code! */ diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc index 29aa31a3374..d1dbbc313d7 100644 --- a/storage/innobase/row/row0row.cc +++ b/storage/innobase/row/row0row.cc @@ -1407,18 +1407,18 @@ row_raw_format_str( charset_coll = dtype_get_charset_coll(prtype); - if (UNIV_LIKELY(dtype_is_utf8(prtype))) { - + switch (charset_coll) { + case 11: /* ascii_general_ci */ + case 65: /* ascii_bin */ + case 33: /* utf8_general_ci */ + case 83: /* utf8_bin */ + case 254: /* utf8_general_cs */ return(ut_str_sql_format(data, data_len, buf, buf_size)); - } - /* else */ - - if (charset_coll == DATA_MYSQL_BINARY_CHARSET_COLL) { - + case 0: + case DATA_MYSQL_BINARY_CHARSET_COLL: *format_in_hex = TRUE; return(0); } - /* else */ return(innobase_raw_format(data, data_len, charset_coll, buf, buf_size)); @@ -1479,9 +1479,18 @@ row_raw_format( break; case DATA_CHAR: case DATA_VARCHAR: + /* FTS_%_CONFIG.key are incorrectly created with prtype==0. + The DATA_ENGLISH is being used for CHAR columns of the + InnoDB internal SQL parser, such as SYS_FOREIGN.ID. + For these, we will eventually goto format_in_hex. */ + ut_ad(dtype_get_charset_coll(prtype) == 8 + || (mtype == DATA_VARCHAR + && (prtype == 0 || prtype == DATA_ENGLISH))); + goto format_str; case DATA_MYSQL: case DATA_VARMYSQL: - + ut_ad(dtype_get_charset_coll(prtype)); + format_str: ret = row_raw_format_str(data, data_len, prtype, buf, buf_size, &format_in_hex); if (format_in_hex) { From a7f0d79f8c1fc66005401eae8de258dfe8c0a219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 23 Oct 2025 09:53:27 +0300 Subject: [PATCH 19/54] MDEV-35155: Small innodb_log_file_size may lead to excessive writing Any InnoDB write workload is marking data pages in the buffer pool dirty. To make the changes durable, it suffices to write to the write-ahead log to facilitate crash recovery. The longer we keep pages dirty in the buffer pool, the better, because the same pages could be modified again and a single write to the file system could cover several changes. Eventually, we must write out dirty pages, so that we can advance the log checkpoint, that is, allow the start of the recovery log to be discarded. (On a clean shutdown, a full checkpoint to the end of the log will be made.) A write workload can be bound by innodb_buffer_pool_size (we must write out changes and evict data pages to make room for others) or by innodb_log_file_size (we must advance the log checkpoint before the tail of the circular ib_logfile0 would overwrite the previous checkpoint). In innodb_log_file_size bound workloads, we failed to set an optimal target for the next checkpoint LSN. If we write out too few pages, then all writer threads may occasionally be blocked in log_free_check() while the buf_flush_page_cleaner() thread is resolving the situation. If we write out too many pages, then the I/O subsystem will be loaded unnecessarily and there will be some write amplification in case some of the unnecessarily written pages would be modified soon afterwards. log_close(): Return the target LSN for buf_flush_ahead(lsn), bitwise-ORed with the "furious" flag, or the special values 0 indicating that no flushing is needed, which is the usual case. log_checkpoint_margin(): Use a similar page checkpoint target as log_close() for the !not_furious case. mtr_flush_ahead(): A wrapper for buf_flush_ahead(). mtr_t::commit_log_release(): Make some common code non-inline in order to reduce code duplication. buf_flush_ahead(lsn, furious=false): Avoid an unnecessary wake-up of the page cleaner if it is scheduled to wake up once per second. Co-developed-by: Alessandro Vetere Reviewed by: Vladislav Lesin --- storage/innobase/buf/buf0flu.cc | 18 +++++- storage/innobase/include/mtr0mtr.h | 33 ++++------- storage/innobase/log/log0log.cc | 8 +-- storage/innobase/mtr/mtr0mtr.cc | 91 +++++++++++++++++++----------- 4 files changed, 90 insertions(+), 60 deletions(-) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index a5148713b09..5b408ae11bc 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -2191,10 +2191,24 @@ ATTRIBUTE_COLD void buf_flush_ahead(lsn_t lsn, bool furious) noexcept if (limit < lsn) { limit= lsn; - buf_pool.page_cleaner_set_idle(false); - pthread_cond_signal(&buf_pool.do_flush_list); if (furious) + { + /* Request any concurrent threads to wait for this batch to complete, + in log_free_check(). */ log_sys.set_check_for_checkpoint(); + /* Immediately wake up buf_flush_page_cleaner(), even when it + is in the middle of a 1-second my_cond_timedwait(). */ + wake: + buf_pool.page_cleaner_set_idle(false); + pthread_cond_signal(&buf_pool.do_flush_list); + } + else if (buf_pool.page_cleaner_idle()) + /* In non-furious mode, concurrent writes to the log will remain + possible, and we are gently requesting buf_flush_page_cleaner() + to do more work to avoid a later call with furious=true. + We will only wake the buf_flush_page_cleaner() from an indefinite + my_cond_wait(), but we will not disturb the regular 1-second sleep. */ + goto wake; } mysql_mutex_unlock(&buf_pool.flush_list_mutex); } diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index eeac3847670..9138657161e 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -645,17 +645,6 @@ public: /** Note that log_sys.latch is no longer being held exclusively. */ void flag_wr_unlock() noexcept { ut_ad(m_latch_ex); m_latch_ex= false; } - /** type of page flushing is needed during commit() */ - enum page_flush_ahead - { - /** no need to trigger page cleaner */ - PAGE_FLUSH_NO= 0, - /** asynchronous flushing is needed */ - PAGE_FLUSH_ASYNC, - /** furious flushing is needed */ - PAGE_FLUSH_SYNC - }; - private: /** Handle any pages that were freed during the mini-transaction. */ void process_freed_pages(); @@ -702,29 +691,31 @@ private: /** Commit the mini-transaction log. @tparam pmem log_sys.is_mmap() @param mtr mini-transaction - @param lsns {start_lsn,flush_ahead} */ + @param lsns {start_lsn,flush_ahead_lsn} */ template - static void commit_log(mtr_t *mtr, std::pair lsns) - noexcept; + static void commit_log(mtr_t *mtr, std::pair lsns) noexcept; + + /** Release log_sys.latch. */ + void commit_log_release() noexcept; /** Append the redo log records to the redo log buffer. - @return {start_lsn,flush_ahead} */ - std::pair do_write(); + @return {start_lsn,flush_ahead_lsn} */ + std::pair do_write() noexcept; /** Append the redo log records to the redo log buffer. @tparam mmap log_sys.is_mmap() @param mtr mini-transaction @param len number of bytes to write - @return {start_lsn,flush_ahead} */ + @return {start_lsn,flush_ahead_lsn} */ template static - std::pair finish_writer(mtr_t *mtr, size_t len); + std::pair finish_writer(mtr_t *mtr, size_t len); /** The applicable variant of commit_log() */ - static void (*commit_logger)(mtr_t *, std::pair); + static void (*commit_logger)(mtr_t *, std::pair); /** The applicable variant of finish_writer() */ - static std::pair (*finisher)(mtr_t *, size_t); + static std::pair (*finisher)(mtr_t *, size_t); - std::pair finish_write(size_t len) + std::pair finish_write(size_t len) { return finisher(this, len); } public: /** Update finisher when spin_wait_delay is changing to or from 0. */ diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 91ad1c34ccf..be15d893c6f 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -1304,10 +1304,10 @@ func_exit: } const lsn_t lsn= log_sys.get_lsn(); - const lsn_t checkpoint= log_sys.last_checkpoint_lsn; - const lsn_t sync_lsn= checkpoint + log_sys.max_checkpoint_age; + const lsn_t max_age= log_sys.max_checkpoint_age; + const lsn_t age= lsn_t(lsn - log_sys.last_checkpoint_lsn); - if (lsn <= sync_lsn) + if (age <= max_age) { #ifndef DBUG_OFF skip_checkpoint: @@ -1320,7 +1320,7 @@ func_exit: log_sys.latch.wr_unlock(); /* We must wait to prevent the tail of the log overwriting the head. */ - buf_flush_wait_flushed(std::min(sync_lsn, checkpoint + (1U << 20))); + buf_flush_wait_flushed(lsn - max_age); /* Sleep to avoid a thundering herd */ std::this_thread::sleep_for(std::chrono::milliseconds(10)); } diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index b4fea4d4a8b..d8af7284c5c 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -40,10 +40,10 @@ Created 11/26/1995 Heikki Tuuri #include "my_cpu.h" #ifdef HAVE_PMEM -void (*mtr_t::commit_logger)(mtr_t *, std::pair); +void (*mtr_t::commit_logger)(mtr_t *, std::pair); #endif -std::pair (*mtr_t::finisher)(mtr_t *, size_t); +std::pair (*mtr_t::finisher)(mtr_t *, size_t); void mtr_t::finisher_update() { @@ -335,9 +335,25 @@ void mtr_t::release() m_memo.clear(); } +ATTRIBUTE_NOINLINE void mtr_t::commit_log_release() noexcept +{ + if (m_latch_ex) + { + log_sys.latch.wr_unlock(); + m_latch_ex= false; + } + else + log_sys.latch.rd_unlock(); +} + +static ATTRIBUTE_NOINLINE ATTRIBUTE_COLD +void mtr_flush_ahead(lsn_t flush_lsn) noexcept +{ + buf_flush_ahead(flush_lsn, bool(flush_lsn & 1)); +} + template -void mtr_t::commit_log(mtr_t *mtr, std::pair lsns) - noexcept +void mtr_t::commit_log(mtr_t *mtr, std::pair lsns) noexcept { size_t modified= 0; @@ -378,25 +394,12 @@ void mtr_t::commit_log(mtr_t *mtr, std::pair lsns) buf_pool.page_cleaner_wakeup(); mysql_mutex_unlock(&buf_pool.flush_list_mutex); - if (mtr->m_latch_ex) - { - log_sys.latch.wr_unlock(); - mtr->m_latch_ex= false; - } - else - log_sys.latch.rd_unlock(); - + mtr->commit_log_release(); mtr->release(); } else { - if (mtr->m_latch_ex) - { - log_sys.latch.wr_unlock(); - mtr->m_latch_ex= false; - } - else - log_sys.latch.rd_unlock(); + mtr->commit_log_release(); for (auto it= mtr->m_memo.rbegin(); it != mtr->m_memo.rend(); ) { @@ -456,8 +459,11 @@ void mtr_t::commit_log(mtr_t *mtr, std::pair lsns) mariadb_increment_pages_updated(modified); - if (UNIV_UNLIKELY(lsns.second != PAGE_FLUSH_NO)) - buf_flush_ahead(mtr->m_commit_lsn, lsns.second == PAGE_FLUSH_SYNC); + if (UNIV_UNLIKELY(lsns.second != 0)) + { + ut_ad(lsns.second < mtr->m_commit_lsn); + mtr_flush_ahead(lsns.second); + } } /** Commit a mini-transaction. */ @@ -480,7 +486,7 @@ void mtr_t::commit() } ut_ad(!srv_read_only_mode); - std::pair lsns{do_write()}; + std::pair lsns{do_write()}; process_freed_pages(); #ifdef HAVE_PMEM commit_logger(this, lsns); @@ -971,24 +977,44 @@ std::pair log_t::append_prepare(size_t size, bool ex) noexcept /** Finish appending data to the log. @param lsn the end LSN of the log record -@return whether buf_flush_ahead() will have to be invoked */ -static mtr_t::page_flush_ahead log_close(lsn_t lsn) noexcept +@return lsn for invoking buf_flush_ahead() on, with "furious" flag in the LSB +@retval 0 if buf_flush_ahead() will not have to be invoked */ +static lsn_t log_close(lsn_t lsn) noexcept { ut_ad(log_sys.latch_have_any()); const lsn_t checkpoint_age= lsn - log_sys.last_checkpoint_lsn; + const lsn_t max_age= log_sys.max_modified_age_async; if (UNIV_UNLIKELY(checkpoint_age >= log_sys.log_capacity) && /* silence message on create_log_file() after the log had been deleted */ checkpoint_age != lsn) log_overwrite_warning(lsn); - else if (UNIV_LIKELY(checkpoint_age <= log_sys.max_modified_age_async)) - return mtr_t::PAGE_FLUSH_NO; - else if (UNIV_LIKELY(checkpoint_age <= log_sys.max_checkpoint_age)) - return mtr_t::PAGE_FLUSH_ASYNC; + else if (UNIV_LIKELY(checkpoint_age <= max_age)) + return 0; - log_sys.set_check_for_checkpoint(); - return mtr_t::PAGE_FLUSH_SYNC; + /* The last checkpoint is too old. Let us set an appropriate + checkpoint age target, that is, a checkpoint LSN target that is the + current LSN minus the maximum age. Let us see if are exceeding the + log_checkpoint_margin() limit that will involve a synchronous wait + in each write operation. */ + + const bool furious{checkpoint_age >= log_sys.max_checkpoint_age}; + + /* If furious==true, we could set a less aggressive target + (lsn - log_sys.max_checkpoint_age) instead of what we will be using + in both cases (lsn - log_sys.max_checkpoint_age_async). + + The aim of the more aggressive target is that mtr_flush_ahead() will + request more progress in buf_flush_page_cleaner() sooner, so that it + will be less likely that several threads will end up waiting in + log_checkpoint_margin(). That function will use the less aggressive + limit (lsn - log_sys.max_checkpoint_age) in order to minimize the + synchronous wait time. */ + if (furious) + log_sys.set_check_for_checkpoint(); + + return ((lsn - max_age) & ~lsn_t{1}) | lsn_t{furious}; } inline void mtr_t::page_checksum(const buf_page_t &bpage) @@ -1034,7 +1060,7 @@ inline void mtr_t::page_checksum(const buf_page_t &bpage) m_log.close(l + 4); } -std::pair mtr_t::do_write() +std::pair mtr_t::do_write() noexcept { ut_ad(!recv_no_log_write); ut_ad(is_logged()); @@ -1186,8 +1212,7 @@ inline void log_t::append(byte *&d, const void *s, size_t size) noexcept } template -std::pair -mtr_t::finish_writer(mtr_t *mtr, size_t len) +std::pair mtr_t::finish_writer(mtr_t *mtr, size_t len) { ut_ad(log_sys.is_latest()); ut_ad(!recv_no_log_write); From 9e8e215e17ee1e3336a1167ea47cad3740a51820 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 22 Oct 2025 17:57:40 +0300 Subject: [PATCH 20/54] MDEV-37903 ALTER TABLE ... ENGINE=MRG_MyISAM is not binlogged as DDL Fixed by marking MRG_MYISAM changes explicitly as a DDL --- mysql-test/main/merge_alter-master.opt | 1 + mysql-test/main/merge_alter.result | 77 ++++++++++++++++++++++++++ mysql-test/main/merge_alter.test | 20 +++++++ sql/sql_table.cc | 3 + 4 files changed, 101 insertions(+) create mode 100644 mysql-test/main/merge_alter-master.opt create mode 100644 mysql-test/main/merge_alter.result create mode 100644 mysql-test/main/merge_alter.test diff --git a/mysql-test/main/merge_alter-master.opt b/mysql-test/main/merge_alter-master.opt new file mode 100644 index 00000000000..4d69f3359db --- /dev/null +++ b/mysql-test/main/merge_alter-master.opt @@ -0,0 +1 @@ +--timezone=GMT-3 diff --git a/mysql-test/main/merge_alter.result b/mysql-test/main/merge_alter.result new file mode 100644 index 00000000000..2508cc7355b --- /dev/null +++ b/mysql-test/main/merge_alter.result @@ -0,0 +1,77 @@ +SET timestamp=1000000000; +RESET MASTER; +CREATE TABLE t (i1 int, i2 int, pk int) ; +CREATE TABLE t3 LIKE t ; +ALTER TABLE t3 ENGINE = MERGE UNION (t1,t2); +insert into t values(1,1,1); +flush logs; +/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; +/*!40019 SET @@session.max_delayed_threads=0*/; +/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; +DELIMITER /*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup +ROLLBACK/*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX Gtid list [] +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX Binlog checkpoint master-bin.000001 +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX GTID 0-1-1 ddl +/*M!100101 SET @@session.skip_parallel_replication=0*//*!*/; +/*M!100001 SET @@session.gtid_domain_id=0*//*!*/; +/*M!100001 SET @@session.server_id=1*//*!*/; +/*M!100001 SET @@session.gtid_seq_no=1*//*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid= +use `test`/*!*/; +SET TIMESTAMP=1000000000/*!*/; +SET @@session.pseudo_thread_id=#/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=1, @@session.system_versioning_insert_history=0/*!*/; +SET @@session.sql_mode=1411383296/*!*/; +SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; +/*!\C latin1 *//*!*/; +SET @@session.character_set_client=X,@@session.collation_connection=X,@@session.collation_server=X/*!*/; +SET @@session.lc_time_names=0/*!*/; +SET @@session.collation_database=DEFAULT/*!*/; +CREATE TABLE t (i1 int, i2 int, pk int) +/*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX GTID 0-1-2 ddl +/*M!100001 SET @@session.gtid_seq_no=2*//*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid= +SET TIMESTAMP=1000000000/*!*/; +CREATE TABLE t3 LIKE t +/*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX GTID 0-1-3 ddl +/*M!100001 SET @@session.gtid_seq_no=3*//*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid= +SET TIMESTAMP=1000000000/*!*/; +ALTER TABLE t3 ENGINE = MERGE UNION (t1,t2) +/*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX GTID 0-1-4 +/*M!100001 SET @@session.gtid_seq_no=4*//*!*/; +START TRANSACTION +/*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid= +SET TIMESTAMP=1000000000/*!*/; +insert into t values(1,1,1) +/*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid= +SET TIMESTAMP=1000000000/*!*/; +COMMIT +/*!*/; +# at # +#010909 4:46:40 server id # end_log_pos # CRC32 XXX Rotate to master-bin.000002 pos: 4 +DELIMITER ; +# End of log file +ROLLBACK /* added by mysqlbinlog */; +/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; +/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; +drop table t,t3; diff --git a/mysql-test/main/merge_alter.test b/mysql-test/main/merge_alter.test new file mode 100644 index 00000000000..8094fd4e9f9 --- /dev/null +++ b/mysql-test/main/merge_alter.test @@ -0,0 +1,20 @@ +--source include/have_binlog_format_mixed.inc + +# MDEV-37903 ALTER TABLE ... ENGINE=MRG_MyISAM is not binlogged as DDL + +# Fix timestamp to avoid varying results. +SET timestamp=1000000000; + +RESET MASTER; + +CREATE TABLE t (i1 int, i2 int, pk int) ; +CREATE TABLE t3 LIKE t ; +ALTER TABLE t3 ENGINE = MERGE UNION (t1,t2); +insert into t values(1,1,1); + +flush logs; +let $MYSQLD_DATADIR= `select @@datadir`; +--replace_regex /server id [0-9]*/server id #/ /server v [^ ]*/server v #.##.##/ /exec_time=[0-9]*/exec_time=#/ /thread_id=[0-9]*/thread_id=#/ /table id [0-9]*/table id #/ /mapped to number [0-9]*/mapped to number #/ /end_log_pos [0-9]*/end_log_pos #/ /# at [0-9]*/# at #/ /CRC32 0x[0-9a-f]*/CRC32 XXX/ /collation_server=[0-9]+/collation_server=X/ /character_set_client=[a-zA-Z0-9]+/character_set_client=X/ /collation_connection=[0-9]+/collation_connection=X/ /xid=\d*/xid=/ +--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLD_DATADIR/master-bin.000001 + +drop table t,t3; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e7e22fefa4d..aed7c9dda0e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -11593,6 +11593,7 @@ do_continue:; } else { + /* MERGE TABLE */ if (!table->s->tmp_table && wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto err_new_table_cleanup; @@ -11601,6 +11602,8 @@ do_continue:; alter_info->keys_onoff); if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) goto err_new_table_cleanup; + /* Ensure that the ALTER is binlogged as a DDL */ + thd->transaction->stmt.mark_trans_did_ddl(); } thd->count_cuted_fields= CHECK_FIELD_IGNORE; From b8bdbd12ddf3a258ee0c22e4e3f7ed3e0c1a720b Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 24 Oct 2025 13:32:45 +0200 Subject: [PATCH 21/54] columnstore 25.10.1-1 --- storage/columnstore/columnstore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/columnstore/columnstore b/storage/columnstore/columnstore index 22454e6eef5..e3a2563b588 160000 --- a/storage/columnstore/columnstore +++ b/storage/columnstore/columnstore @@ -1 +1 @@ -Subproject commit 22454e6eef5ba17c573f7602203e997c9331748d +Subproject commit e3a2563b58898de8117199eddfd7845c5a24886d From 21be9fbca085e4a97ce93e7881402e9157dc6040 Mon Sep 17 00:00:00 2001 From: bsrikanth-mariadb Date: Tue, 21 Oct 2025 11:16:28 +0530 Subject: [PATCH 22/54] MDEV-37901: Wrong result on QUICK_GROUP_MIN_MAX_SELECT WITH TIES The "FETCH FIRST n ROWS WITH TIES" was not enforced when the SELECT used "using index for group-by". This was caused by an optimization which removed the ORDER BY clause when the GROUP BY clause prescribed a compatible ordering. Other GROUP BY strategies used workarounds to still handle WITH TIES, see comment to using_with_ties_and_group_min_max() in this patch for details. QUICK_GROUP_MIN_MAX_SELECT didn't have a workaround. Fix this by disabling removal of ORDER BY when QUICK_GROUP_MIN_MAX_SELECT is used. --- mysql-test/main/fetch_first.result | 85 ++++++++++++++++++++++++++++++ mysql-test/main/fetch_first.test | 74 ++++++++++++++++++++++++++ sql/opt_range.cc | 40 ++++++++++++++ sql/opt_range.h | 1 + sql/sql_select.cc | 8 ++- 5 files changed, 206 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/fetch_first.result b/mysql-test/main/fetch_first.result index df182381d1c..d8717fc1b60 100644 --- a/mysql-test/main/fetch_first.result +++ b/mysql-test/main/fetch_first.result @@ -1406,3 +1406,88 @@ a b 3 bar 3 zzz DROP TABLE t1; +# +# MDEV-37901: Wrong result with Loose Scan on QUICK_GROUP_MIN_MAX_SELECT WITH TIES +# +create table t1 ( +country varchar(100), +city varchar(100), +user_score int, +index (country, city, user_score) +); +insert into t1 +select 'China', 'Shenzhen', seq from seq_10_to_100; +insert into t1 +select 'India', 'New Delhi', seq from seq_10_to_100; +insert into t1 +select 'Sri Lanka', 'Colombo', seq from seq_10_to_100; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +insert into t1 +select 'Finland', 'Espoo', seq from seq_10_to_200; +insert into t1 +select 'Greece', 'Chania', seq from seq_10_to_20; +insert into t1 +select 'Estonia', 'Narva', seq from seq_10_to_20; +insert into t1 +select 'Russia', 'St Petersburg', seq from seq_10_to_20; +# Must use "Using index for group-by": +explain +select country, city, min(user_score) +from t1 +where user_score between 9 and 199 +group by country, city +order by country +fetch first 5 rows with ties; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL country 211 NULL 4 Using where; Using index for group-by; Using temporary; Using filesort +# Must not use "Using index for group-by": +explain +select country, city, sum(user_score) +from t1 +where user_score between 9 and 199 +group by country, concat(city,'AA') +order by country +fetch first 5 rows with ties; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL country 211 NULL 273 Using where; Using index; Using temporary; Using filesort +select country, city, sum(user_score) +from t1 +where user_score between 9 and 199 +group by country, concat(city,'AA') +order by country +fetch first 5 rows with ties; +country city sum(user_score) +China Shenzhen 5005 +Estonia Narva 165 +Finland Espoo 19855 +Greece Chania 165 +India New Delhi 5005 +# both using index and index with group by should produce same result +select country, city, min(user_score) +from t1 +where user_score between 9 and 199 +group by country, city +order by country +fetch first 5 rows with ties; +country city min(user_score) +China Shenzhen 10 +Estonia Narva 10 +Finland Espoo 10 +Greece Chania 10 +India New Delhi 10 +select country, city, min(user_score) +from t1 use index() +where user_score between 9 and 199 +group by country, city +order by country +fetch first 5 rows with ties; +country city min(user_score) +China Shenzhen 10 +Estonia Narva 10 +Finland Espoo 10 +Greece Chania 10 +India New Delhi 10 +drop table t1; diff --git a/mysql-test/main/fetch_first.test b/mysql-test/main/fetch_first.test index 242807f4243..24f17953359 100644 --- a/mysql-test/main/fetch_first.test +++ b/mysql-test/main/fetch_first.test @@ -1082,3 +1082,77 @@ SELECT DISTINCT a, b FROM t1 ORDER BY a FETCH FIRST 3 ROWS WITH TIES; # Cleanup DROP TABLE t1; + + +--echo # +--echo # MDEV-37901: Wrong result with Loose Scan on QUICK_GROUP_MIN_MAX_SELECT WITH TIES +--echo # + +--source include/have_sequence.inc + +create table t1 ( + country varchar(100), + city varchar(100), + user_score int, + index (country, city, user_score) +); + +insert into t1 +select 'China', 'Shenzhen', seq from seq_10_to_100; +insert into t1 +select 'India', 'New Delhi', seq from seq_10_to_100; +insert into t1 +select 'Sri Lanka', 'Colombo', seq from seq_10_to_100; +analyze table t1 persistent for all; + +insert into t1 +select 'Finland', 'Espoo', seq from seq_10_to_200; +insert into t1 +select 'Greece', 'Chania', seq from seq_10_to_20; +insert into t1 +select 'Estonia', 'Narva', seq from seq_10_to_20; +insert into t1 +select 'Russia', 'St Petersburg', seq from seq_10_to_20; + +--echo # Must use "Using index for group-by": +explain +select country, city, min(user_score) +from t1 +where user_score between 9 and 199 +group by country, city +order by country +fetch first 5 rows with ties; + +--echo # Must not use "Using index for group-by": +explain +select country, city, sum(user_score) +from t1 +where user_score between 9 and 199 +group by country, concat(city,'AA') +order by country +fetch first 5 rows with ties; + +select country, city, sum(user_score) +from t1 +where user_score between 9 and 199 +group by country, concat(city,'AA') +order by country +fetch first 5 rows with ties; + +--echo # both using index and index with group by should produce same result + +select country, city, min(user_score) +from t1 +where user_score between 9 and 199 +group by country, city +order by country +fetch first 5 rows with ties; + +select country, city, min(user_score) +from t1 use index() +where user_score between 9 and 199 +group by country, city +order by country +fetch first 5 rows with ties; + +drop table t1; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index bae471caa10..c6c4a5d7b4f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -15227,6 +15227,46 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows, } +/* + @brief + Return true if the select is using "Using index for group-by" and also + has "ORDER BY ... FETCH FIRST n ROWS WITH TIES" + + @detail + There is a rewrite that removes the ORDER BY (JOIN::order) if the select + also has a GROUP BY that produces a compatible ordering. + However "FETCH FIRST ... WITH TIES" needs an ORDER BY clause (in + JOIN::alloc_order_fields()). + GROUP BY strategies handle it this way: + - For strategies using temporary table, JOIN::make_aggr_tables_info() will + put the ORDER BY clause back. + - OrderedGroupBy in end_send_group() handles WITH TIES with the GROUP BY + clause (note that SQL doesn't allow "GROUP BY ... WITH TIES"). + - The remaining strategy is QUICK_GROUP_MIN_MAX_SELECT, for which + = the grouping strategy in the quick select doesn't handle WITH TIES. + = end_send() would not handle WITH TIES, because JOIN::order is removed. + + The solution is to NOT remove ORDER BY when QUICK_GROUP_MIN_MAX_SELECT is + used. + + Unfortunately, the optimizer then will not recognize that it can skip + sorting and will use filesort, which will prevent short-cutting the + execution when LIMIT is reached. +*/ + +bool using_with_ties_and_group_min_max(JOIN *join) +{ + if (join->unit->lim.is_with_ties()) + { + JOIN_TAB *tab= &join->join_tab[join->const_tables]; + if (tab->select && tab->select->quick && + tab->select->quick->get_type() == + QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) + return true; + } + return false; +} + /* Construct new quick select for group queries with min/max. diff --git a/sql/opt_range.h b/sql/opt_range.h index b4db3850de4..867c3f1ecd4 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -1869,6 +1869,7 @@ public: Explain_quick_select *get_explain(MEM_ROOT *alloc) override; }; +bool using_with_ties_and_group_min_max(JOIN *join); class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 952124be5a2..2c158bcc4fc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3182,9 +3182,14 @@ int JOIN::optimize_stage2() (as MariaDB is by default sorting on GROUP BY) or if there is no GROUP BY and aggregate functions are used (as the result will only contain one row). + + (1) - Do not remove ORDER BY if we have WITH TIES and are using + QUICK_GROUP_MIN_MAX_SELECT to handle GROUP BY. See the comment + for using_with_ties_and_group_min_max() for details. */ if (order && (test_if_subpart(group_list, order) || - (!group_list && tmp_table_param.sum_func_count))) + (!group_list && tmp_table_param.sum_func_count)) && + !using_with_ties_and_group_min_max(this)) // (1) order=0; // Can't use sort on head table if using join buffering @@ -13652,7 +13657,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) if (build_tmp_join_prefix_cond(join, tab, &sel->cond)) return true; - /* We can't call sel->cond->fix_fields, as it will break tab->on_expr if it's AND condition From f84f2ce5342ddea14f3c37e3d271f3413a5128dc Mon Sep 17 00:00:00 2001 From: bsrikanth-mariadb Date: Tue, 30 Sep 2025 12:02:19 +0530 Subject: [PATCH 23/54] MDEV-31887: wrong result with split optimization Wrong result is produced when split-materialized optimization is used for grouping with order by and limit. The fix is to not let Split-Materialized optimization to happen when the sub-query has an ORDER BY with LIMIT, by returning FALSE early in the method opt_split.cc#check_for_splittable_materialized() However, with just the above change, there is a side-effect of NOT "using index for group by" in the scenario when all the following conditions are met: - 1. The query has derived table with GROUP BY and ORDER BY LIMIT 2. joined in a way that would allow Split-Materialized if ORDER BY LIMIT wasn't present 3. An index suitable for using "index for group-by" 4. No where clause so that, "using for group by" is applicable, but the index is not included in "possible_keys". The reason being, join_tab's "keys" field wasn't being set in sql_select.cc#make_join_select(). So, made this change as well as part of this PR. --- mysql-test/main/derived_split_innodb.result | 43 ++++++++++++++++++++ mysql-test/main/derived_split_innodb.test | 44 +++++++++++++++++++++ mysql-test/main/distinct.result | 2 +- mysql-test/main/group_min_max.result | 2 +- sql/opt_split.cc | 4 ++ sql/sql_select.cc | 16 +++++++- 6 files changed, 108 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index ec16fd6b417..26d6596acf1 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -1002,5 +1002,48 @@ set statement optimizer_switch='split_materialized=off' for $query; a b name total_amt 1 NULL A 10 DROP TABLE t1,t2; +# +# MDEV-37407 Wrong result with ORDER BY LIMIT +# Both, with and without split_materialized should +# produce the same results +# +SET @save_optimizer_switch= @@optimizer_switch; +CREATE TABLE t1 +(a varchar(35), b varchar(4), KEY (a)) +ENGINE=InnoDB; +INSERT INTO t1 VALUES +('Albania','AXA'), ('Australia','AUS'), ('Myanmar','MMR'), +('Bahamas','BS'), ('Brazil','BRA'), ('Barbados','BRB'); +CREATE TABLE t2 +(a varchar(4), b varchar(50), PRIMARY KEY (b,a), KEY (a)) +ENGINE=InnoDB; +INSERT INTO t2 VALUES +('AUS','Anglican'), ('MMR','Baptist'), ('BS','Anglican'), +('BS','Baptist'), ('BS','Methodist'), ('BRB','Methodist'), +('BRA','Baptist'), ('USA','Baptist'); +ANALYZE TABLE t1 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +ANALYZE TABLE t2 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +set optimizer_switch='split_materialized=off'; +SELECT t1.a +FROM (SELECT a FROM t2 GROUP BY a ORDER BY a, COUNT(DISTINCT b) LIMIT 1) dt +JOIN t1 ON +dt.a=t1.b +WHERE t1.a LIKE 'B%'; +a +set optimizer_switch='split_materialized=on'; +SELECT t1.a +FROM (SELECT a FROM t2 GROUP BY a ORDER BY a, COUNT(DISTINCT b) LIMIT 1) dt +JOIN t1 ON +dt.a=t1.b +WHERE t1.a LIKE 'B%'; +a +DROP TABLE t1,t2; +SET optimizer_switch= @save_optimizer_switch; # End of 10.11 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index 3359a0a2de1..0d2a9ecc776 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -620,5 +620,49 @@ evalp set statement optimizer_switch='split_materialized=off' for $query; DROP TABLE t1,t2; +--echo # +--echo # MDEV-37407 Wrong result with ORDER BY LIMIT +--echo # Both, with and without split_materialized should +--echo # produce the same results +--echo # + +SET @save_optimizer_switch= @@optimizer_switch; + +CREATE TABLE t1 + (a varchar(35), b varchar(4), KEY (a)) +ENGINE=InnoDB; + +INSERT INTO t1 VALUES +('Albania','AXA'), ('Australia','AUS'), ('Myanmar','MMR'), +('Bahamas','BS'), ('Brazil','BRA'), ('Barbados','BRB'); + +CREATE TABLE t2 + (a varchar(4), b varchar(50), PRIMARY KEY (b,a), KEY (a)) +ENGINE=InnoDB; + +INSERT INTO t2 VALUES +('AUS','Anglican'), ('MMR','Baptist'), ('BS','Anglican'), +('BS','Baptist'), ('BS','Methodist'), ('BRB','Methodist'), +('BRA','Baptist'), ('USA','Baptist'); + +ANALYZE TABLE t1 PERSISTENT FOR ALL; +ANALYZE TABLE t2 PERSISTENT FOR ALL; + +let $q= +SELECT t1.a +FROM (SELECT a FROM t2 GROUP BY a ORDER BY a, COUNT(DISTINCT b) LIMIT 1) dt + JOIN t1 ON + dt.a=t1.b +WHERE t1.a LIKE 'B%'; + +set optimizer_switch='split_materialized=off'; +eval $q; + +set optimizer_switch='split_materialized=on'; +eval $q; + +DROP TABLE t1,t2; + +SET optimizer_switch= @save_optimizer_switch; --echo # End of 10.11 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/mysql-test/main/distinct.result b/mysql-test/main/distinct.result index e9d47f9cefe..d8646abfb43 100644 --- a/mysql-test/main/distinct.result +++ b/mysql-test/main/distinct.result @@ -212,7 +212,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 1 Using index explain SELECT distinct a from t3 order by a desc limit 2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index NULL a 5 NULL 40 Using index +1 SIMPLE t3 range a a 5 NULL 10 Using index for group-by; Using temporary; Using filesort explain SELECT distinct a,b from t3 order by a+1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort diff --git a/mysql-test/main/group_min_max.result b/mysql-test/main/group_min_max.result index 1716db76227..a9b350ea688 100644 --- a/mysql-test/main/group_min_max.result +++ b/mysql-test/main/group_min_max.result @@ -2451,7 +2451,7 @@ EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE EXISTS (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1_outer index NULL a 10 NULL 15 Using index -2 SUBQUERY t1 index NULL a 10 NULL 15 Using index +2 SUBQUERY t1 range a a 5 NULL 6 Using index for group-by EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12; id select_type table type possible_keys key key_len ref rows Extra diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 96459a0679e..18c17e1a774 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -355,6 +355,7 @@ struct SplM_field_ext_info: public SplM_field_info with available statistics. 10. The select doesn't use WITH ROLLUP (This limitation can probably be lifted) + 11. The select doesn't have ORDER BY with LIMIT @retval true if the answer is positive @@ -388,6 +389,9 @@ bool JOIN::check_for_splittable_materialized() if (!partition_list) return false; + if (select_lex->order_list.elements > 0 && !unit->lim.is_unlimited()) //!(11) + return false; + Json_writer_object trace_wrapper(thd); Json_writer_object trace_split(thd, "check_split_materialized"); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2c158bcc4fc..4301c161f79 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13657,7 +13657,21 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) if (build_tmp_join_prefix_cond(join, tab, &sel->cond)) return true; - /* + + /* + To be removed in 11.0+: + Caution: we can reach this point with quick=NULL. Below, we'll + use tab->keys and not tab->const_keys like + get_quick_record_count() did. If we have constructed a + group-min-max quick select, make sure we're able to construct it + again + */ + if (sel->quick && sel->quick->get_type() == + QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) + { + tab->keys.set_bit(sel->quick->index); + } + /* We can't call sel->cond->fix_fields, as it will break tab->on_expr if it's AND condition (fix_fields currently removes extra AND/OR levels). From bcb77590f0f62e478726356761c673a1d4ca055a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 30 Aug 2024 11:04:14 +0200 Subject: [PATCH 24/54] cleanup: CREATE_TYPELIB_FOR() helper (cherry picked from commit d046aca0c76da36c8ba14359034a716af667aa51) --- client/mysqladmin.cc | 3 +- client/mysqlbinlog.cc | 4 +- client/mysqlcheck.c | 3 +- client/mysqldump.cc | 9 +- client/mysqltest.cc | 3 +- extra/mariabackup/xbcloud.cc | 3 +- extra/mariabackup/xtrabackup.cc | 6 +- include/typelib.h | 2 + mysys/my_static.c | 3 +- mysys/typelib.c | 3 +- plugin/auth_gssapi/server_plugin.cc | 7 +- .../aws_key_management_plugin.cc | 12 +- .../file_key_management_plugin.cc | 7 +- plugin/query_response_time/plugin.cc | 7 + plugin/server_audit/server_audit.c | 23 +- sql-common/client.c | 3 +- sql/backup.cc | 3 +- sql/handler.cc | 3 +- sql/item_strfunc.cc | 8 +- sql/log_event.cc | 8 +- sql/repl_failsafe.cc | 3 +- sql/sql_db.cc | 3 +- sql/sql_locale.cc | 472 +++++++++--------- sql/sql_plugin.cc | 3 +- sql/sql_show.cc | 5 +- sql/sys_vars.cc | 8 +- sql/sys_vars.inl | 2 +- storage/connect/ha_connect.cc | 24 +- storage/example/ha_example.cc | 6 +- storage/innobase/handler/ha_innodb.cc | 67 +-- storage/maria/aria_chk.c | 4 +- storage/maria/aria_s3_copy.cc | 2 +- storage/maria/ha_maria.cc | 30 +- storage/maria/s3_func.c | 3 +- storage/mroonga/ha_mroonga.cpp | 23 +- storage/myisam/ha_myisam.cc | 8 +- storage/myisam/myisamchk.c | 5 +- storage/myisammrg/myrg_static.c | 3 +- storage/rocksdb/ha_rocksdb.cc | 16 +- 39 files changed, 323 insertions(+), 484 deletions(-) diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 90ea88f885a..454d454b485 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -111,8 +111,7 @@ static const char *command_names[]= { NullS }; -static TYPELIB command_typelib= -{ array_elements(command_names)-1,"commands", command_names, NULL}; +static TYPELIB command_typelib= CREATE_TYPELIB_FOR(command_names); static struct my_option my_long_options[] = { diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 1c0cf34eb84..c0414676c5e 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -116,9 +116,7 @@ static bool one_database=0, one_table=0, to_last_remote_log= 0, disable_log_bin= static bool opt_hexdump= 0, opt_version= 0; const char *base64_output_mode_names[]= {"NEVER", "AUTO", "UNSPEC", "DECODE-ROWS", NullS}; -TYPELIB base64_output_mode_typelib= - { array_elements(base64_output_mode_names) - 1, "", - base64_output_mode_names, NULL }; +TYPELIB base64_output_mode_typelib=CREATE_TYPELIB_FOR(base64_output_mode_names); static enum_base64_output_mode opt_base64_output_mode= BASE64_OUTPUT_UNSPEC; static char *opt_base64_output_mode_str= NullS; static char* database= 0; diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 4bbac4ef4be..9ad69a92b58 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -66,8 +66,7 @@ const char *operation_name[]= typedef enum { DO_VIEWS_NO, DO_VIEWS_YES, DO_UPGRADE, DO_VIEWS_FROM_MYSQL } enum_do_views; const char *do_views_opts[]= {"NO", "YES", "UPGRADE", "UPGRADE_FROM_MYSQL", NullS}; -TYPELIB do_views_typelib= { array_elements(do_views_opts) - 1, "", - do_views_opts, NULL }; +TYPELIB do_views_typelib= CREATE_TYPELIB_FOR(do_views_opts); static ulong opt_do_views= DO_VIEWS_NO; static struct my_option my_long_options[] = diff --git a/client/mysqldump.cc b/client/mysqldump.cc index 75fe9f1cea5..985e93fed42 100644 --- a/client/mysqldump.cc +++ b/client/mysqldump.cc @@ -140,11 +140,7 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_no_data_m #define OPT_SYSTEM_TIMEZONES 64 static const char *opt_system_type_values[]= {"all", "users", "plugins", "udfs", "servers", "stats", "timezones"}; -static TYPELIB opt_system_types= -{ - array_elements(opt_system_type_values), "system dump options", - opt_system_type_values, NULL -}; +static TYPELIB opt_system_types=CREATE_TYPELIB_FOR(opt_system_type_values); static ulonglong opt_system= 0ULL; static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0, select_field_names_inited= 0; @@ -236,8 +232,7 @@ const char *compatible_mode_names[]= (1U<<6) | /* MAXDB */\ (1U<<10) /* ANSI */\ ) -TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, - "", compatible_mode_names, NULL}; +TYPELIB compatible_mode_typelib= CREATE_TYPELIB_FOR(compatible_mode_names); #define MED_ENGINES "MRG_MyISAM, MRG_ISAM, CONNECT, OQGRAPH, SPIDER, VP, FEDERATED" diff --git a/client/mysqltest.cc b/client/mysqltest.cc index f7829800491..ec7cbf3d063 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -595,8 +595,7 @@ struct st_command enum enum_commands type; }; -TYPELIB command_typelib= {array_elements(command_names),"", - command_names, 0}; +TYPELIB command_typelib= CREATE_TYPELIB_FOR(command_names); DYNAMIC_STRING ds_res; /* Points to ds_warning in run_query, so it can be freed */ diff --git a/extra/mariabackup/xbcloud.cc b/extra/mariabackup/xbcloud.cc index 588a15eb791..fa5dc79edbc 100644 --- a/extra/mariabackup/xbcloud.cc +++ b/extra/mariabackup/xbcloud.cc @@ -176,8 +176,7 @@ static enum {MODE_GET, MODE_PUT, MODE_DELETE} opt_mode; static char **file_list = NULL; static int file_list_size = 0; -TYPELIB storage_typelib = -{array_elements(storage_names)-1, "", storage_names, NULL}; +TYPELIB storage_typelib = CREATE_TYPELIB_FOR(storage_names); enum { OPT_STORAGE = 256, diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 9b78ee45bec..9bffd1f540e 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -389,8 +389,7 @@ static ulong innodb_flush_method; static const char *binlog_info_values[] = {"off", "lockless", "on", "auto", NullS}; -static TYPELIB binlog_info_typelib = {array_elements(binlog_info_values)-1, "", - binlog_info_values, NULL}; +static TYPELIB binlog_info_typelib = CREATE_TYPELIB_FOR(binlog_info_values); ulong opt_binlog_info; char *opt_incremental_history_name; @@ -407,8 +406,7 @@ char *opt_log_bin; const char *query_type_names[] = { "ALL", "UPDATE", "SELECT", NullS}; -TYPELIB query_type_typelib= {array_elements(query_type_names) - 1, "", - query_type_names, NULL}; +TYPELIB query_type_typelib= CREATE_TYPELIB_FOR(query_type_names); ulong opt_lock_wait_query_type; ulong opt_kill_long_query_type; diff --git a/include/typelib.h b/include/typelib.h index dc315dd3bb8..9a8ee802cae 100644 --- a/include/typelib.h +++ b/include/typelib.h @@ -27,6 +27,8 @@ typedef struct st_typelib { /* Different types saved here */ unsigned int *type_lengths; } TYPELIB; +#define CREATE_TYPELIB_FOR(X) { (unsigned int)(sizeof(X)/sizeof(X[0])) - 1, "", X, NULL } + extern my_ulonglong find_typeset(const char *x, TYPELIB *typelib, int *error_position); extern int find_type_with_warning(const char *x, TYPELIB *typelib, diff --git a/mysys/my_static.c b/mysys/my_static.c index efeb6a4568b..bc90975f632 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -131,5 +131,4 @@ my_bool my_disable_copystat_in_redel=0; const char *sql_protocol_names_lib[] = { "TCP", "SOCKET", "PIPE", NullS }; -TYPELIB sql_protocol_typelib ={ array_elements(sql_protocol_names_lib) - 1, "", - sql_protocol_names_lib, NULL }; +TYPELIB sql_protocol_typelib= CREATE_TYPELIB_FOR(sql_protocol_names_lib); diff --git a/mysys/typelib.c b/mysys/typelib.c index 03f3609b5e8..10296c35bfb 100644 --- a/mysys/typelib.c +++ b/mysys/typelib.c @@ -265,8 +265,7 @@ TYPELIB *copy_typelib(MEM_ROOT *root, const TYPELIB *from) static const char *on_off_default_names[]= { "off","on","default", 0}; -static TYPELIB on_off_default_typelib= {array_elements(on_off_default_names)-1, - "", on_off_default_names, 0}; +static TYPELIB on_off_default_typelib= CREATE_TYPELIB_FOR(on_off_default_names); /** Parse a TYPELIB name from the buffer diff --git a/plugin/auth_gssapi/server_plugin.cc b/plugin/auth_gssapi/server_plugin.cc index c45452cee8e..e4feb4e9a5f 100644 --- a/plugin/auth_gssapi/server_plugin.cc +++ b/plugin/auth_gssapi/server_plugin.cc @@ -109,12 +109,7 @@ static const char* mech_names[] = { "", NULL }; -static TYPELIB mech_name_typelib = { - 3, - "mech_name_typelib", - mech_names, - NULL -}; +static TYPELIB mech_name_typelib = CREATE_TYPELIB_FOR(mech_names); static MYSQL_SYSVAR_ENUM(mech_name, srv_mech, PLUGIN_VAR_RQCMDARG|PLUGIN_VAR_READONLY, "GSSAPI mechanism", diff --git a/plugin/aws_key_management/aws_key_management_plugin.cc b/plugin/aws_key_management/aws_key_management_plugin.cc index 444a48d6a20..1771aa89e09 100644 --- a/plugin/aws_key_management/aws_key_management_plugin.cc +++ b/plugin/aws_key_management/aws_key_management_plugin.cc @@ -673,11 +673,7 @@ struct st_mariadb_encryption aws_key_management_plugin= { }; -static TYPELIB key_spec_typelib = -{ - array_elements(key_spec_names) - 1, "", - key_spec_names, NULL -}; +static TYPELIB key_spec_typelib = CREATE_TYPELIB_FOR(key_spec_names); const char *log_level_names[] = { @@ -691,11 +687,7 @@ const char *log_level_names[] = 0 }; -static TYPELIB log_level_typelib = -{ - array_elements(log_level_names) - 1, "", - log_level_names, NULL -}; +static TYPELIB log_level_typelib = CREATE_TYPELIB_FOR(log_level_names); static MYSQL_SYSVAR_STR(master_key_id, master_key_id, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, diff --git a/plugin/file_key_management/file_key_management_plugin.cc b/plugin/file_key_management/file_key_management_plugin.cc index 927045ce175..75284578d89 100644 --- a/plugin/file_key_management/file_key_management_plugin.cc +++ b/plugin/file_key_management/file_key_management_plugin.cc @@ -32,12 +32,7 @@ static const char *encryption_algorithm_names[]= 0 }; -static TYPELIB encryption_algorithm_typelib= -{ - array_elements(encryption_algorithm_names)-1,"", - encryption_algorithm_names, NULL -}; - +static TYPELIB encryption_algorithm_typelib=CREATE_TYPELIB_FOR(encryption_algorithm_names); static MYSQL_SYSVAR_STR(filename, filename, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, diff --git a/plugin/query_response_time/plugin.cc b/plugin/query_response_time/plugin.cc index 0362c6e2792..3868f84c12f 100644 --- a/plugin/query_response_time/plugin.cc +++ b/plugin/query_response_time/plugin.cc @@ -36,6 +36,13 @@ static void query_response_time_flush_update( query_response_time_flush(); } +enum session_stat +{ + session_stat_global, + session_stat_on, + session_stat_off +}; + static MYSQL_SYSVAR_ULONG(range_base, opt_query_response_time_range_base, PLUGIN_VAR_RQCMDARG, diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 2d5b89aca69..e5e1e8af760 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -393,10 +393,7 @@ static const char *event_names[]= "CONNECT", "QUERY", "TABLE", "QUERY_DDL", "QUERY_DML", "QUERY_DCL", "QUERY_DML_NO_SELECT", NULL }; -static TYPELIB events_typelib= -{ - array_elements(event_names) - 1, "", event_names, NULL -}; +static TYPELIB events_typelib= CREATE_TYPELIB_FOR(event_names); static MYSQL_SYSVAR_SET(events, events, PLUGIN_VAR_RQCMDARG, "Specifies the set of events to monitor. Can be CONNECT, QUERY, TABLE," " QUERY_DDL, QUERY_DML, QUERY_DML_NO_SELECT, QUERY_DCL.", @@ -415,11 +412,7 @@ static const char *output_type_names[]= { "syslog", #endif "file", 0 }; -static TYPELIB output_typelib= -{ - array_elements(output_type_names) - 1, "output_typelib", - output_type_names, NULL -}; +static TYPELIB output_typelib=CREATE_TYPELIB_FOR(output_type_names); static MYSQL_SYSVAR_ENUM(output_type, output_type, PLUGIN_VAR_RQCMDARG, out_type_desc, 0, update_output_type, OUTPUT_FILE, @@ -487,11 +480,7 @@ static unsigned int syslog_facility_codes[]= LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, }; #endif -static TYPELIB syslog_facility_typelib= -{ - array_elements(syslog_facility_names) - 1, "syslog_facility_typelib", - syslog_facility_names, NULL -}; +static TYPELIB syslog_facility_typelib=CREATE_TYPELIB_FOR(syslog_facility_names); static MYSQL_SYSVAR_ENUM(syslog_facility, syslog_facility, PLUGIN_VAR_RQCMDARG, "The 'facility' parameter of the SYSLOG record." " The default is LOG_USER.", 0, update_syslog_facility, 0/*LOG_USER*/, @@ -512,11 +501,7 @@ static unsigned int syslog_priority_codes[]= }; #endif -static TYPELIB syslog_priority_typelib= -{ - array_elements(syslog_priority_names) - 1, "syslog_priority_typelib", - syslog_priority_names, NULL -}; +static TYPELIB syslog_priority_typelib=CREATE_TYPELIB_FOR(syslog_priority_names); static MYSQL_SYSVAR_ENUM(syslog_priority, syslog_priority, PLUGIN_VAR_RQCMDARG, "The 'priority' parameter of the SYSLOG record." " The default is LOG_INFO.", 0, update_syslog_priority, 6/*LOG_INFO*/, diff --git a/sql-common/client.c b/sql-common/client.c index e6ad0e97c18..49b300de7a4 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -811,8 +811,7 @@ static char *opt_strdup(const char *from, myf my_flags) return my_strdup(key_memory_mysql_options, from, my_flags); } -static TYPELIB option_types={array_elements(default_options)-1, - "options",default_options, NULL}; +static TYPELIB option_types=CREATE_TYPELIB_FOR(default_options); static int add_init_command(struct st_mysql_options *options, const char *cmd) { diff --git a/sql/backup.cc b/sql/backup.cc index c7caac3127f..10daabf9f3f 100644 --- a/sql/backup.cc +++ b/sql/backup.cc @@ -45,8 +45,7 @@ static const char *stage_names[]= {"START", "FLUSH", "BLOCK_DDL", "BLOCK_COMMIT", "END", 0}; -TYPELIB backup_stage_names= -{ array_elements(stage_names)-1, "", stage_names, 0 }; +TYPELIB backup_stage_names= CREATE_TYPELIB_FOR(stage_names); static MDL_ticket *backup_flush_ticket; static File volatile backup_log= -1; diff --git a/sql/handler.cc b/sql/handler.cc index 5c3b121da91..997f892b1a3 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -152,8 +152,7 @@ const LEX_CSTRING ha_row_type[]= const char *tx_isolation_names[]= { "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ", "SERIALIZABLE", NullS}; -TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"", - tx_isolation_names, NULL}; +TYPELIB tx_isolation_typelib= CREATE_TYPELIB_FOR(tx_isolation_names); static TYPELIB known_extensions= {0,"known_exts", NULL, NULL}; uint known_extensions_id= 0; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 9b7392f1ace..f88cda75d1b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -333,7 +333,8 @@ const char *block_encryption_mode_values[]= { "aes-128-cbc", "aes-192-cbc", "aes-256-cbc", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", NullS }; -TYPELIB block_encryption_mode_typelib= {9, 0, block_encryption_mode_values, 0}; +TYPELIB block_encryption_mode_typelib= + CREATE_TYPELIB_FOR(block_encryption_mode_values); static inline uint block_encryption_mode_to_key_length(ulong bem) { return (bem % 3 + 2) * 64; } static inline my_aes_mode block_encryption_mode_to_aes_mode(ulong bem) @@ -678,10 +679,7 @@ err: const char *histogram_types[] = {"SINGLE_PREC_HB", "DOUBLE_PREC_HB", "JSON_HB", 0}; -static TYPELIB histogram_types_typelib= - { array_elements(histogram_types), - "histogram_types", - histogram_types, NULL}; +static TYPELIB histogram_types_typelib= CREATE_TYPELIB_FOR(histogram_types); const char *representation_by_type[]= {"%.3f", "%.5f"}; String *Item_func_decode_histogram::val_str(String *str) diff --git a/sql/log_event.cc b/sql/log_event.cc index d95840c3438..717a361dbc4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -81,13 +81,7 @@ unsigned int binlog_checksum_type_length[]= { 0 }; -TYPELIB binlog_checksum_typelib= -{ - array_elements(binlog_checksum_type_names) - 1, "", - binlog_checksum_type_names, - binlog_checksum_type_length -}; - +TYPELIB binlog_checksum_typelib= CREATE_TYPELIB_FOR(binlog_checksum_type_names); #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index baff06d60ee..164ae02df4d 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -55,8 +55,7 @@ ulong rpl_status=RPL_NULL; mysql_mutex_t LOCK_rpl_status; const char *rpl_role_type[] = {"MASTER","SLAVE",NullS}; -TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"", - rpl_role_type, NULL}; +TYPELIB rpl_role_typelib = CREATE_TYPELIB_FOR(rpl_role_type); const char* rpl_status_type[]= { diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 22442390ca9..86fc0d92cb9 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -52,8 +52,7 @@ #define MAX_DROP_TABLE_Q_LEN 1024 const char *del_exts[]= {".BAK", ".opt", NullS}; -static TYPELIB deletable_extensions= -{array_elements(del_exts)-1,"del_exts", del_exts, NULL}; +static TYPELIB deletable_extensions= CREATE_TYPELIB_FOR(del_exts); static bool find_db_tables_and_rm_known_files(THD *, MY_DIR *, const Lex_ident_db_normalized &db, diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 426223d9585..8c9f2a69f9e 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -78,13 +78,13 @@ static const char *my_locale_day_names_ar_AE[8] = static const char *my_locale_ab_day_names_ar_AE[8] = {"ن","ث","ر","خ","ج","س","ح", NullS }; static TYPELIB my_locale_typelib_month_names_ar_AE = - { array_elements(my_locale_month_names_ar_AE)-1, "", my_locale_month_names_ar_AE, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ar_AE); static TYPELIB my_locale_typelib_ab_month_names_ar_AE = - { array_elements(my_locale_ab_month_names_ar_AE)-1, "", my_locale_ab_month_names_ar_AE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ar_AE); static TYPELIB my_locale_typelib_day_names_ar_AE = - { array_elements(my_locale_day_names_ar_AE)-1, "", my_locale_day_names_ar_AE, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ar_AE); static TYPELIB my_locale_typelib_ab_day_names_ar_AE = - { array_elements(my_locale_ab_day_names_ar_AE)-1, "", my_locale_ab_day_names_ar_AE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ar_AE); MY_LOCALE my_locale_ar_AE ( 6, @@ -114,13 +114,13 @@ static const char *my_locale_day_names_ar_BH[8] = static const char *my_locale_ab_day_names_ar_BH[8] = {"ن","ث","ر","خ","ج","س","ح", NullS }; static TYPELIB my_locale_typelib_month_names_ar_BH = - { array_elements(my_locale_month_names_ar_BH)-1, "", my_locale_month_names_ar_BH, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ar_BH); static TYPELIB my_locale_typelib_ab_month_names_ar_BH = - { array_elements(my_locale_ab_month_names_ar_BH)-1, "", my_locale_ab_month_names_ar_BH, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ar_BH); static TYPELIB my_locale_typelib_day_names_ar_BH = - { array_elements(my_locale_day_names_ar_BH)-1, "", my_locale_day_names_ar_BH, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ar_BH); static TYPELIB my_locale_typelib_ab_day_names_ar_BH = - { array_elements(my_locale_ab_day_names_ar_BH)-1, "", my_locale_ab_day_names_ar_BH, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ar_BH); MY_LOCALE my_locale_ar_BH ( 7, @@ -150,13 +150,13 @@ static const char *my_locale_day_names_ar_JO[8] = static const char *my_locale_ab_day_names_ar_JO[8] = {"الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت","الأحد", NullS }; static TYPELIB my_locale_typelib_month_names_ar_JO = - { array_elements(my_locale_month_names_ar_JO)-1, "", my_locale_month_names_ar_JO, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ar_JO); static TYPELIB my_locale_typelib_ab_month_names_ar_JO = - { array_elements(my_locale_ab_month_names_ar_JO)-1, "", my_locale_ab_month_names_ar_JO, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ar_JO); static TYPELIB my_locale_typelib_day_names_ar_JO = - { array_elements(my_locale_day_names_ar_JO)-1, "", my_locale_day_names_ar_JO, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ar_JO); static TYPELIB my_locale_typelib_ab_day_names_ar_JO = - { array_elements(my_locale_ab_day_names_ar_JO)-1, "", my_locale_ab_day_names_ar_JO, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ar_JO); MY_LOCALE my_locale_ar_JO ( 8, @@ -186,13 +186,13 @@ static const char *my_locale_day_names_ar_SA[8] = static const char *my_locale_ab_day_names_ar_SA[8] = {"Mon","Tue","Wed","Thu","Fri","Sat","Sun", NullS }; static TYPELIB my_locale_typelib_month_names_ar_SA = - { array_elements(my_locale_month_names_ar_SA)-1, "", my_locale_month_names_ar_SA, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ar_SA); static TYPELIB my_locale_typelib_ab_month_names_ar_SA = - { array_elements(my_locale_ab_month_names_ar_SA)-1, "", my_locale_ab_month_names_ar_SA, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ar_SA); static TYPELIB my_locale_typelib_day_names_ar_SA = - { array_elements(my_locale_day_names_ar_SA)-1, "", my_locale_day_names_ar_SA, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ar_SA); static TYPELIB my_locale_typelib_ab_day_names_ar_SA = - { array_elements(my_locale_ab_day_names_ar_SA)-1, "", my_locale_ab_day_names_ar_SA, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ar_SA); MY_LOCALE my_locale_ar_SA ( 9, @@ -222,13 +222,13 @@ static const char *my_locale_day_names_ar_SY[8] = static const char *my_locale_ab_day_names_ar_SY[8] = {"الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت","الأحد", NullS }; static TYPELIB my_locale_typelib_month_names_ar_SY = - { array_elements(my_locale_month_names_ar_SY)-1, "", my_locale_month_names_ar_SY, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ar_SY); static TYPELIB my_locale_typelib_ab_month_names_ar_SY = - { array_elements(my_locale_ab_month_names_ar_SY)-1, "", my_locale_ab_month_names_ar_SY, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ar_SY); static TYPELIB my_locale_typelib_day_names_ar_SY = - { array_elements(my_locale_day_names_ar_SY)-1, "", my_locale_day_names_ar_SY, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ar_SY); static TYPELIB my_locale_typelib_ab_day_names_ar_SY = - { array_elements(my_locale_ab_day_names_ar_SY)-1, "", my_locale_ab_day_names_ar_SY, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ar_SY); MY_LOCALE my_locale_ar_SY ( 10, @@ -258,13 +258,13 @@ static const char *my_locale_day_names_be_BY[8] = static const char *my_locale_ab_day_names_be_BY[8] = {"Пан","Аўт","Срд","Чцв","Пят","Суб","Няд", NullS }; static TYPELIB my_locale_typelib_month_names_be_BY = - { array_elements(my_locale_month_names_be_BY)-1, "", my_locale_month_names_be_BY, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_be_BY); static TYPELIB my_locale_typelib_ab_month_names_be_BY = - { array_elements(my_locale_ab_month_names_be_BY)-1, "", my_locale_ab_month_names_be_BY, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_be_BY); static TYPELIB my_locale_typelib_day_names_be_BY = - { array_elements(my_locale_day_names_be_BY)-1, "", my_locale_day_names_be_BY, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_be_BY); static TYPELIB my_locale_typelib_ab_day_names_be_BY = - { array_elements(my_locale_ab_day_names_be_BY)-1, "", my_locale_ab_day_names_be_BY, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_be_BY); MY_LOCALE my_locale_be_BY ( 11, @@ -294,13 +294,13 @@ static const char *my_locale_day_names_bg_BG[8] = static const char *my_locale_ab_day_names_bg_BG[8] = {"пн","вт","ср","чт","пт","сб","нд", NullS }; static TYPELIB my_locale_typelib_month_names_bg_BG = - { array_elements(my_locale_month_names_bg_BG)-1, "", my_locale_month_names_bg_BG, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_bg_BG); static TYPELIB my_locale_typelib_ab_month_names_bg_BG = - { array_elements(my_locale_ab_month_names_bg_BG)-1, "", my_locale_ab_month_names_bg_BG, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_bg_BG); static TYPELIB my_locale_typelib_day_names_bg_BG = - { array_elements(my_locale_day_names_bg_BG)-1, "", my_locale_day_names_bg_BG, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_bg_BG); static TYPELIB my_locale_typelib_ab_day_names_bg_BG = - { array_elements(my_locale_ab_day_names_bg_BG)-1, "", my_locale_ab_day_names_bg_BG, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_bg_BG); MY_LOCALE my_locale_bg_BG ( 12, @@ -330,13 +330,13 @@ static const char *my_locale_day_names_ca_ES[8] = static const char *my_locale_ab_day_names_ca_ES[8] = {"dl","dt","dc","dj","dv","ds","dg", NullS }; static TYPELIB my_locale_typelib_month_names_ca_ES = - { array_elements(my_locale_month_names_ca_ES)-1, "", my_locale_month_names_ca_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ca_ES); static TYPELIB my_locale_typelib_ab_month_names_ca_ES = - { array_elements(my_locale_ab_month_names_ca_ES)-1, "", my_locale_ab_month_names_ca_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ca_ES); static TYPELIB my_locale_typelib_day_names_ca_ES = - { array_elements(my_locale_day_names_ca_ES)-1, "", my_locale_day_names_ca_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ca_ES); static TYPELIB my_locale_typelib_ab_day_names_ca_ES = - { array_elements(my_locale_ab_day_names_ca_ES)-1, "", my_locale_ab_day_names_ca_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ca_ES); MY_LOCALE my_locale_ca_ES ( 13, @@ -366,13 +366,13 @@ static const char *my_locale_day_names_cs_CZ[8] = static const char *my_locale_ab_day_names_cs_CZ[8] = {"Po","Út","St","Čt","Pá","So","Ne", NullS }; static TYPELIB my_locale_typelib_month_names_cs_CZ = - { array_elements(my_locale_month_names_cs_CZ)-1, "", my_locale_month_names_cs_CZ, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_cs_CZ); static TYPELIB my_locale_typelib_ab_month_names_cs_CZ = - { array_elements(my_locale_ab_month_names_cs_CZ)-1, "", my_locale_ab_month_names_cs_CZ, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_cs_CZ); static TYPELIB my_locale_typelib_day_names_cs_CZ = - { array_elements(my_locale_day_names_cs_CZ)-1, "", my_locale_day_names_cs_CZ, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_cs_CZ); static TYPELIB my_locale_typelib_ab_day_names_cs_CZ = - { array_elements(my_locale_ab_day_names_cs_CZ)-1, "", my_locale_ab_day_names_cs_CZ, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_cs_CZ); MY_LOCALE my_locale_cs_CZ ( 14, @@ -402,13 +402,13 @@ static const char *my_locale_day_names_da_DK[8] = static const char *my_locale_ab_day_names_da_DK[8] = {"man","tir","ons","tor","fre","lør","søn", NullS }; static TYPELIB my_locale_typelib_month_names_da_DK = - { array_elements(my_locale_month_names_da_DK)-1, "", my_locale_month_names_da_DK, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_da_DK); static TYPELIB my_locale_typelib_ab_month_names_da_DK = - { array_elements(my_locale_ab_month_names_da_DK)-1, "", my_locale_ab_month_names_da_DK, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_da_DK); static TYPELIB my_locale_typelib_day_names_da_DK = - { array_elements(my_locale_day_names_da_DK)-1, "", my_locale_day_names_da_DK, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_da_DK); static TYPELIB my_locale_typelib_ab_day_names_da_DK = - { array_elements(my_locale_ab_day_names_da_DK)-1, "", my_locale_ab_day_names_da_DK, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_da_DK); MY_LOCALE my_locale_da_DK ( 15, @@ -438,13 +438,13 @@ static const char *my_locale_day_names_de_AT[8] = static const char *my_locale_ab_day_names_de_AT[8] = {"Mon","Die","Mit","Don","Fre","Sam","Son", NullS }; static TYPELIB my_locale_typelib_month_names_de_AT = - { array_elements(my_locale_month_names_de_AT)-1, "", my_locale_month_names_de_AT, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_de_AT); static TYPELIB my_locale_typelib_ab_month_names_de_AT = - { array_elements(my_locale_ab_month_names_de_AT)-1, "", my_locale_ab_month_names_de_AT, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_de_AT); static TYPELIB my_locale_typelib_day_names_de_AT = - { array_elements(my_locale_day_names_de_AT)-1, "", my_locale_day_names_de_AT, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_de_AT); static TYPELIB my_locale_typelib_ab_day_names_de_AT = - { array_elements(my_locale_ab_day_names_de_AT)-1, "", my_locale_ab_day_names_de_AT, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_de_AT); MY_LOCALE my_locale_de_AT ( 16, @@ -474,13 +474,13 @@ static const char *my_locale_day_names_de_DE[8] = static const char *my_locale_ab_day_names_de_DE[8] = {"Mo","Di","Mi","Do","Fr","Sa","So", NullS }; static TYPELIB my_locale_typelib_month_names_de_DE = - { array_elements(my_locale_month_names_de_DE)-1, "", my_locale_month_names_de_DE, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_de_DE); static TYPELIB my_locale_typelib_ab_month_names_de_DE = - { array_elements(my_locale_ab_month_names_de_DE)-1, "", my_locale_ab_month_names_de_DE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_de_DE); static TYPELIB my_locale_typelib_day_names_de_DE = - { array_elements(my_locale_day_names_de_DE)-1, "", my_locale_day_names_de_DE, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_de_DE); static TYPELIB my_locale_typelib_ab_day_names_de_DE = - { array_elements(my_locale_ab_day_names_de_DE)-1, "", my_locale_ab_day_names_de_DE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_de_DE); MY_LOCALE my_locale_de_DE ( 4, @@ -510,13 +510,13 @@ static const char *my_locale_day_names_en_US[8] = static const char *my_locale_ab_day_names_en_US[8] = {"Mon","Tue","Wed","Thu","Fri","Sat","Sun", NullS }; static TYPELIB my_locale_typelib_month_names_en_US = - { array_elements(my_locale_month_names_en_US)-1, "", my_locale_month_names_en_US, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_en_US); static TYPELIB my_locale_typelib_ab_month_names_en_US = - { array_elements(my_locale_ab_month_names_en_US)-1, "", my_locale_ab_month_names_en_US, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_en_US); static TYPELIB my_locale_typelib_day_names_en_US = - { array_elements(my_locale_day_names_en_US)-1, "", my_locale_day_names_en_US, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_en_US); static TYPELIB my_locale_typelib_ab_day_names_en_US = - { array_elements(my_locale_ab_day_names_en_US)-1, "", my_locale_ab_day_names_en_US, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_en_US); MY_LOCALE my_locale_en_US ( 0, @@ -546,13 +546,13 @@ static const char *my_locale_day_names_es_ES[8] = static const char *my_locale_ab_day_names_es_ES[8] = {"lun","mar","mié","jue","vie","sáb","dom", NullS }; static TYPELIB my_locale_typelib_month_names_es_ES = - { array_elements(my_locale_month_names_es_ES)-1, "", my_locale_month_names_es_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_es_ES); static TYPELIB my_locale_typelib_ab_month_names_es_ES = - { array_elements(my_locale_ab_month_names_es_ES)-1, "", my_locale_ab_month_names_es_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_es_ES); static TYPELIB my_locale_typelib_day_names_es_ES = - { array_elements(my_locale_day_names_es_ES)-1, "", my_locale_day_names_es_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_es_ES); static TYPELIB my_locale_typelib_ab_day_names_es_ES = - { array_elements(my_locale_ab_day_names_es_ES)-1, "", my_locale_ab_day_names_es_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_es_ES); MY_LOCALE my_locale_es_ES ( 17, @@ -582,13 +582,13 @@ static const char *my_locale_day_names_et_EE[8] = static const char *my_locale_ab_day_names_et_EE[8] = {"E","T","K","N","R","L","P", NullS }; static TYPELIB my_locale_typelib_month_names_et_EE = - { array_elements(my_locale_month_names_et_EE)-1, "", my_locale_month_names_et_EE, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_et_EE); static TYPELIB my_locale_typelib_ab_month_names_et_EE = - { array_elements(my_locale_ab_month_names_et_EE)-1, "", my_locale_ab_month_names_et_EE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_et_EE); static TYPELIB my_locale_typelib_day_names_et_EE = - { array_elements(my_locale_day_names_et_EE)-1, "", my_locale_day_names_et_EE, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_et_EE); static TYPELIB my_locale_typelib_ab_day_names_et_EE = - { array_elements(my_locale_ab_day_names_et_EE)-1, "", my_locale_ab_day_names_et_EE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_et_EE); MY_LOCALE my_locale_et_EE ( 18, @@ -618,13 +618,13 @@ static const char *my_locale_day_names_eu_ES[8] = static const char *my_locale_ab_day_names_eu_ES[8] = {"al.","ar.","az.","og.","or.","lr.","ig.", NullS }; static TYPELIB my_locale_typelib_month_names_eu_ES = - { array_elements(my_locale_month_names_eu_ES)-1, "", my_locale_month_names_eu_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_eu_ES); static TYPELIB my_locale_typelib_ab_month_names_eu_ES = - { array_elements(my_locale_ab_month_names_eu_ES)-1, "", my_locale_ab_month_names_eu_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_eu_ES); static TYPELIB my_locale_typelib_day_names_eu_ES = - { array_elements(my_locale_day_names_eu_ES)-1, "", my_locale_day_names_eu_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_eu_ES); static TYPELIB my_locale_typelib_ab_day_names_eu_ES = - { array_elements(my_locale_ab_day_names_eu_ES)-1, "", my_locale_ab_day_names_eu_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_eu_ES); MY_LOCALE my_locale_eu_ES ( 19, @@ -654,13 +654,13 @@ static const char *my_locale_day_names_fi_FI[8] = static const char *my_locale_ab_day_names_fi_FI[8] = {"ma","ti","ke","to","pe","la","su", NullS }; static TYPELIB my_locale_typelib_month_names_fi_FI = - { array_elements(my_locale_month_names_fi_FI)-1, "", my_locale_month_names_fi_FI, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_fi_FI); static TYPELIB my_locale_typelib_ab_month_names_fi_FI = - { array_elements(my_locale_ab_month_names_fi_FI)-1, "", my_locale_ab_month_names_fi_FI, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_fi_FI); static TYPELIB my_locale_typelib_day_names_fi_FI = - { array_elements(my_locale_day_names_fi_FI)-1, "", my_locale_day_names_fi_FI, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_fi_FI); static TYPELIB my_locale_typelib_ab_day_names_fi_FI = - { array_elements(my_locale_ab_day_names_fi_FI)-1, "", my_locale_ab_day_names_fi_FI, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_fi_FI); MY_LOCALE my_locale_fi_FI ( 20, @@ -690,13 +690,13 @@ static const char *my_locale_day_names_fo_FO[8] = static const char *my_locale_ab_day_names_fo_FO[8] = {"mán","týs","mik","hós","frí","ley","sun", NullS }; static TYPELIB my_locale_typelib_month_names_fo_FO = - { array_elements(my_locale_month_names_fo_FO)-1, "", my_locale_month_names_fo_FO, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_fo_FO); static TYPELIB my_locale_typelib_ab_month_names_fo_FO = - { array_elements(my_locale_ab_month_names_fo_FO)-1, "", my_locale_ab_month_names_fo_FO, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_fo_FO); static TYPELIB my_locale_typelib_day_names_fo_FO = - { array_elements(my_locale_day_names_fo_FO)-1, "", my_locale_day_names_fo_FO, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_fo_FO); static TYPELIB my_locale_typelib_ab_day_names_fo_FO = - { array_elements(my_locale_ab_day_names_fo_FO)-1, "", my_locale_ab_day_names_fo_FO, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_fo_FO); MY_LOCALE my_locale_fo_FO ( 21, @@ -726,13 +726,13 @@ static const char *my_locale_day_names_fr_FR[8] = static const char *my_locale_ab_day_names_fr_FR[8] = {"lun","mar","mer","jeu","ven","sam","dim", NullS }; static TYPELIB my_locale_typelib_month_names_fr_FR = - { array_elements(my_locale_month_names_fr_FR)-1, "", my_locale_month_names_fr_FR, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_fr_FR); static TYPELIB my_locale_typelib_ab_month_names_fr_FR = - { array_elements(my_locale_ab_month_names_fr_FR)-1, "", my_locale_ab_month_names_fr_FR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_fr_FR); static TYPELIB my_locale_typelib_day_names_fr_FR = - { array_elements(my_locale_day_names_fr_FR)-1, "", my_locale_day_names_fr_FR, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_fr_FR); static TYPELIB my_locale_typelib_ab_day_names_fr_FR = - { array_elements(my_locale_ab_day_names_fr_FR)-1, "", my_locale_ab_day_names_fr_FR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_fr_FR); MY_LOCALE my_locale_fr_FR ( 5, @@ -762,13 +762,13 @@ static const char *my_locale_day_names_gl_ES[8] = static const char *my_locale_ab_day_names_gl_ES[8] = {"Lun","Mar","Mér","Xov","Ven","Sáb","Dom", NullS }; static TYPELIB my_locale_typelib_month_names_gl_ES = - { array_elements(my_locale_month_names_gl_ES)-1, "", my_locale_month_names_gl_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_gl_ES); static TYPELIB my_locale_typelib_ab_month_names_gl_ES = - { array_elements(my_locale_ab_month_names_gl_ES)-1, "", my_locale_ab_month_names_gl_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_gl_ES); static TYPELIB my_locale_typelib_day_names_gl_ES = - { array_elements(my_locale_day_names_gl_ES)-1, "", my_locale_day_names_gl_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_gl_ES); static TYPELIB my_locale_typelib_ab_day_names_gl_ES = - { array_elements(my_locale_ab_day_names_gl_ES)-1, "", my_locale_ab_day_names_gl_ES, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_gl_ES); MY_LOCALE my_locale_gl_ES ( 22, @@ -798,13 +798,13 @@ static const char *my_locale_day_names_gu_IN[8] = static const char *my_locale_ab_day_names_gu_IN[8] = {"સોમ","મન્ગળ","બુધ","ગુરુ","શુક્ર","શનિ","રવિ", NullS }; static TYPELIB my_locale_typelib_month_names_gu_IN = - { array_elements(my_locale_month_names_gu_IN)-1, "", my_locale_month_names_gu_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_gu_IN); static TYPELIB my_locale_typelib_ab_month_names_gu_IN = - { array_elements(my_locale_ab_month_names_gu_IN)-1, "", my_locale_ab_month_names_gu_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_gu_IN); static TYPELIB my_locale_typelib_day_names_gu_IN = - { array_elements(my_locale_day_names_gu_IN)-1, "", my_locale_day_names_gu_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_gu_IN); static TYPELIB my_locale_typelib_ab_day_names_gu_IN = - { array_elements(my_locale_ab_day_names_gu_IN)-1, "", my_locale_ab_day_names_gu_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_gu_IN); MY_LOCALE my_locale_gu_IN ( 23, @@ -834,13 +834,13 @@ static const char *my_locale_day_names_he_IL[8] = static const char *my_locale_ab_day_names_he_IL[8] = {"ב'","ג'","ד'","ה'","ו'","ש'","א'", NullS }; static TYPELIB my_locale_typelib_month_names_he_IL = - { array_elements(my_locale_month_names_he_IL)-1, "", my_locale_month_names_he_IL, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_he_IL); static TYPELIB my_locale_typelib_ab_month_names_he_IL = - { array_elements(my_locale_ab_month_names_he_IL)-1, "", my_locale_ab_month_names_he_IL, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_he_IL); static TYPELIB my_locale_typelib_day_names_he_IL = - { array_elements(my_locale_day_names_he_IL)-1, "", my_locale_day_names_he_IL, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_he_IL); static TYPELIB my_locale_typelib_ab_day_names_he_IL = - { array_elements(my_locale_ab_day_names_he_IL)-1, "", my_locale_ab_day_names_he_IL, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_he_IL); MY_LOCALE my_locale_he_IL ( 24, @@ -870,13 +870,13 @@ static const char *my_locale_day_names_hi_IN[8] = static const char *my_locale_ab_day_names_hi_IN[8] = {"सोम ","मंगल ","बुध ","गुरु ","शुक्र ","शनि ","रवि ", NullS }; static TYPELIB my_locale_typelib_month_names_hi_IN = - { array_elements(my_locale_month_names_hi_IN)-1, "", my_locale_month_names_hi_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_hi_IN); static TYPELIB my_locale_typelib_ab_month_names_hi_IN = - { array_elements(my_locale_ab_month_names_hi_IN)-1, "", my_locale_ab_month_names_hi_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_hi_IN); static TYPELIB my_locale_typelib_day_names_hi_IN = - { array_elements(my_locale_day_names_hi_IN)-1, "", my_locale_day_names_hi_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_hi_IN); static TYPELIB my_locale_typelib_ab_day_names_hi_IN = - { array_elements(my_locale_ab_day_names_hi_IN)-1, "", my_locale_ab_day_names_hi_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_hi_IN); MY_LOCALE my_locale_hi_IN ( 25, @@ -906,13 +906,13 @@ static const char *my_locale_day_names_hr_HR[8] = static const char *my_locale_ab_day_names_hr_HR[8] = {"Pon","Uto","Sri","Čet","Pet","Sub","Ned", NullS }; static TYPELIB my_locale_typelib_month_names_hr_HR = - { array_elements(my_locale_month_names_hr_HR)-1, "", my_locale_month_names_hr_HR, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_hr_HR); static TYPELIB my_locale_typelib_ab_month_names_hr_HR = - { array_elements(my_locale_ab_month_names_hr_HR)-1, "", my_locale_ab_month_names_hr_HR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_hr_HR); static TYPELIB my_locale_typelib_day_names_hr_HR = - { array_elements(my_locale_day_names_hr_HR)-1, "", my_locale_day_names_hr_HR, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_hr_HR); static TYPELIB my_locale_typelib_ab_day_names_hr_HR = - { array_elements(my_locale_ab_day_names_hr_HR)-1, "", my_locale_ab_day_names_hr_HR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_hr_HR); MY_LOCALE my_locale_hr_HR ( 26, @@ -942,13 +942,13 @@ static const char *my_locale_day_names_hu_HU[8] = static const char *my_locale_ab_day_names_hu_HU[8] = {"h","k","sze","cs","p","szo","v", NullS }; static TYPELIB my_locale_typelib_month_names_hu_HU = - { array_elements(my_locale_month_names_hu_HU)-1, "", my_locale_month_names_hu_HU, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_hu_HU); static TYPELIB my_locale_typelib_ab_month_names_hu_HU = - { array_elements(my_locale_ab_month_names_hu_HU)-1, "", my_locale_ab_month_names_hu_HU, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_hu_HU); static TYPELIB my_locale_typelib_day_names_hu_HU = - { array_elements(my_locale_day_names_hu_HU)-1, "", my_locale_day_names_hu_HU, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_hu_HU); static TYPELIB my_locale_typelib_ab_day_names_hu_HU = - { array_elements(my_locale_ab_day_names_hu_HU)-1, "", my_locale_ab_day_names_hu_HU, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_hu_HU); MY_LOCALE my_locale_hu_HU ( 27, @@ -978,13 +978,13 @@ static const char *my_locale_day_names_id_ID[8] = static const char *my_locale_ab_day_names_id_ID[8] = {"Sen","Sel","Rab","Kam","Jum","Sab","Min", NullS }; static TYPELIB my_locale_typelib_month_names_id_ID = - { array_elements(my_locale_month_names_id_ID)-1, "", my_locale_month_names_id_ID, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_id_ID); static TYPELIB my_locale_typelib_ab_month_names_id_ID = - { array_elements(my_locale_ab_month_names_id_ID)-1, "", my_locale_ab_month_names_id_ID, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_id_ID); static TYPELIB my_locale_typelib_day_names_id_ID = - { array_elements(my_locale_day_names_id_ID)-1, "", my_locale_day_names_id_ID, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_id_ID); static TYPELIB my_locale_typelib_ab_day_names_id_ID = - { array_elements(my_locale_ab_day_names_id_ID)-1, "", my_locale_ab_day_names_id_ID, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_id_ID); MY_LOCALE my_locale_id_ID ( 28, @@ -1014,13 +1014,13 @@ static const char *my_locale_day_names_is_IS[8] = static const char *my_locale_ab_day_names_is_IS[8] = {"mán","þri","mið","fim","fös","lau","sun", NullS }; static TYPELIB my_locale_typelib_month_names_is_IS = - { array_elements(my_locale_month_names_is_IS)-1, "", my_locale_month_names_is_IS, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_is_IS); static TYPELIB my_locale_typelib_ab_month_names_is_IS = - { array_elements(my_locale_ab_month_names_is_IS)-1, "", my_locale_ab_month_names_is_IS, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_is_IS); static TYPELIB my_locale_typelib_day_names_is_IS = - { array_elements(my_locale_day_names_is_IS)-1, "", my_locale_day_names_is_IS, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_is_IS); static TYPELIB my_locale_typelib_ab_day_names_is_IS = - { array_elements(my_locale_ab_day_names_is_IS)-1, "", my_locale_ab_day_names_is_IS, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_is_IS); MY_LOCALE my_locale_is_IS ( 29, @@ -1050,13 +1050,13 @@ static const char *my_locale_day_names_it_CH[8] = static const char *my_locale_ab_day_names_it_CH[8] = {"lun","mar","mer","gio","ven","sab","dom", NullS }; static TYPELIB my_locale_typelib_month_names_it_CH = - { array_elements(my_locale_month_names_it_CH)-1, "", my_locale_month_names_it_CH, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_it_CH); static TYPELIB my_locale_typelib_ab_month_names_it_CH = - { array_elements(my_locale_ab_month_names_it_CH)-1, "", my_locale_ab_month_names_it_CH, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_it_CH); static TYPELIB my_locale_typelib_day_names_it_CH = - { array_elements(my_locale_day_names_it_CH)-1, "", my_locale_day_names_it_CH, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_it_CH); static TYPELIB my_locale_typelib_ab_day_names_it_CH = - { array_elements(my_locale_ab_day_names_it_CH)-1, "", my_locale_ab_day_names_it_CH, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_it_CH); MY_LOCALE my_locale_it_CH ( 30, @@ -1086,13 +1086,13 @@ static const char *my_locale_day_names_ja_JP[8] = static const char *my_locale_ab_day_names_ja_JP[8] = {"月","火","水","木","金","土","日", NullS }; static TYPELIB my_locale_typelib_month_names_ja_JP = - { array_elements(my_locale_month_names_ja_JP)-1, "", my_locale_month_names_ja_JP, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ja_JP); static TYPELIB my_locale_typelib_ab_month_names_ja_JP = - { array_elements(my_locale_ab_month_names_ja_JP)-1, "", my_locale_ab_month_names_ja_JP, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ja_JP); static TYPELIB my_locale_typelib_day_names_ja_JP = - { array_elements(my_locale_day_names_ja_JP)-1, "", my_locale_day_names_ja_JP, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ja_JP); static TYPELIB my_locale_typelib_ab_day_names_ja_JP = - { array_elements(my_locale_ab_day_names_ja_JP)-1, "", my_locale_ab_day_names_ja_JP, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ja_JP); MY_LOCALE my_locale_ja_JP ( 2, @@ -1122,13 +1122,13 @@ static const char *my_locale_day_names_ko_KR[8] = static const char *my_locale_ab_day_names_ko_KR[8] = {"월","화","수","목","금","토","일", NullS }; static TYPELIB my_locale_typelib_month_names_ko_KR = - { array_elements(my_locale_month_names_ko_KR)-1, "", my_locale_month_names_ko_KR, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ko_KR); static TYPELIB my_locale_typelib_ab_month_names_ko_KR = - { array_elements(my_locale_ab_month_names_ko_KR)-1, "", my_locale_ab_month_names_ko_KR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ko_KR); static TYPELIB my_locale_typelib_day_names_ko_KR = - { array_elements(my_locale_day_names_ko_KR)-1, "", my_locale_day_names_ko_KR, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ko_KR); static TYPELIB my_locale_typelib_ab_day_names_ko_KR = - { array_elements(my_locale_ab_day_names_ko_KR)-1, "", my_locale_ab_day_names_ko_KR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ko_KR); MY_LOCALE my_locale_ko_KR ( 31, @@ -1158,13 +1158,13 @@ static const char *my_locale_day_names_lt_LT[8] = static const char *my_locale_ab_day_names_lt_LT[8] = {"Pr","An","Tr","Kt","Pn","Št","Sk", NullS }; static TYPELIB my_locale_typelib_month_names_lt_LT = - { array_elements(my_locale_month_names_lt_LT)-1, "", my_locale_month_names_lt_LT, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_lt_LT); static TYPELIB my_locale_typelib_ab_month_names_lt_LT = - { array_elements(my_locale_ab_month_names_lt_LT)-1, "", my_locale_ab_month_names_lt_LT, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_lt_LT); static TYPELIB my_locale_typelib_day_names_lt_LT = - { array_elements(my_locale_day_names_lt_LT)-1, "", my_locale_day_names_lt_LT, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_lt_LT); static TYPELIB my_locale_typelib_ab_day_names_lt_LT = - { array_elements(my_locale_ab_day_names_lt_LT)-1, "", my_locale_ab_day_names_lt_LT, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_lt_LT); MY_LOCALE my_locale_lt_LT ( 32, @@ -1194,13 +1194,13 @@ static const char *my_locale_day_names_lv_LV[8] = static const char *my_locale_ab_day_names_lv_LV[8] = {"P ","O ","T ","C ","Pk","S ","Sv", NullS }; static TYPELIB my_locale_typelib_month_names_lv_LV = - { array_elements(my_locale_month_names_lv_LV)-1, "", my_locale_month_names_lv_LV, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_lv_LV); static TYPELIB my_locale_typelib_ab_month_names_lv_LV = - { array_elements(my_locale_ab_month_names_lv_LV)-1, "", my_locale_ab_month_names_lv_LV, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_lv_LV); static TYPELIB my_locale_typelib_day_names_lv_LV = - { array_elements(my_locale_day_names_lv_LV)-1, "", my_locale_day_names_lv_LV, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_lv_LV); static TYPELIB my_locale_typelib_ab_day_names_lv_LV = - { array_elements(my_locale_ab_day_names_lv_LV)-1, "", my_locale_ab_day_names_lv_LV, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_lv_LV); MY_LOCALE my_locale_lv_LV ( 33, @@ -1230,13 +1230,13 @@ static const char *my_locale_day_names_mk_MK[8] = static const char *my_locale_ab_day_names_mk_MK[8] = {"пон","вто","сре","чет","пет","саб","нед", NullS }; static TYPELIB my_locale_typelib_month_names_mk_MK = - { array_elements(my_locale_month_names_mk_MK)-1, "", my_locale_month_names_mk_MK, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_mk_MK); static TYPELIB my_locale_typelib_ab_month_names_mk_MK = - { array_elements(my_locale_ab_month_names_mk_MK)-1, "", my_locale_ab_month_names_mk_MK, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_mk_MK); static TYPELIB my_locale_typelib_day_names_mk_MK = - { array_elements(my_locale_day_names_mk_MK)-1, "", my_locale_day_names_mk_MK, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_mk_MK); static TYPELIB my_locale_typelib_ab_day_names_mk_MK = - { array_elements(my_locale_ab_day_names_mk_MK)-1, "", my_locale_ab_day_names_mk_MK, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_mk_MK); MY_LOCALE my_locale_mk_MK ( 34, @@ -1266,13 +1266,13 @@ static const char *my_locale_day_names_mn_MN[8] = static const char *my_locale_ab_day_names_mn_MN[8] = {"Да","Мя","Лх","Пү","Ба","Бя","Ня", NullS }; static TYPELIB my_locale_typelib_month_names_mn_MN = - { array_elements(my_locale_month_names_mn_MN)-1, "", my_locale_month_names_mn_MN, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_mn_MN); static TYPELIB my_locale_typelib_ab_month_names_mn_MN = - { array_elements(my_locale_ab_month_names_mn_MN)-1, "", my_locale_ab_month_names_mn_MN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_mn_MN); static TYPELIB my_locale_typelib_day_names_mn_MN = - { array_elements(my_locale_day_names_mn_MN)-1, "", my_locale_day_names_mn_MN, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_mn_MN); static TYPELIB my_locale_typelib_ab_day_names_mn_MN = - { array_elements(my_locale_ab_day_names_mn_MN)-1, "", my_locale_ab_day_names_mn_MN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_mn_MN); MY_LOCALE my_locale_mn_MN ( 35, @@ -1302,13 +1302,13 @@ static const char *my_locale_day_names_ms_MY[8] = static const char *my_locale_ab_day_names_ms_MY[8] = {"Isn","Sel","Rab","Kha","Jum","Sab","Ahd", NullS }; static TYPELIB my_locale_typelib_month_names_ms_MY = - { array_elements(my_locale_month_names_ms_MY)-1, "", my_locale_month_names_ms_MY, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ms_MY); static TYPELIB my_locale_typelib_ab_month_names_ms_MY = - { array_elements(my_locale_ab_month_names_ms_MY)-1, "", my_locale_ab_month_names_ms_MY, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ms_MY); static TYPELIB my_locale_typelib_day_names_ms_MY = - { array_elements(my_locale_day_names_ms_MY)-1, "", my_locale_day_names_ms_MY, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ms_MY); static TYPELIB my_locale_typelib_ab_day_names_ms_MY = - { array_elements(my_locale_ab_day_names_ms_MY)-1, "", my_locale_ab_day_names_ms_MY, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ms_MY); MY_LOCALE my_locale_ms_MY ( 36, @@ -1338,13 +1338,13 @@ static const char *my_locale_day_names_nb_NO[8] = static const char *my_locale_ab_day_names_nb_NO[8] = {"man","tir","ons","tor","fre","lør","søn", NullS }; static TYPELIB my_locale_typelib_month_names_nb_NO = - { array_elements(my_locale_month_names_nb_NO)-1, "", my_locale_month_names_nb_NO, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_nb_NO); static TYPELIB my_locale_typelib_ab_month_names_nb_NO = - { array_elements(my_locale_ab_month_names_nb_NO)-1, "", my_locale_ab_month_names_nb_NO, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_nb_NO); static TYPELIB my_locale_typelib_day_names_nb_NO = - { array_elements(my_locale_day_names_nb_NO)-1, "", my_locale_day_names_nb_NO, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_nb_NO); static TYPELIB my_locale_typelib_ab_day_names_nb_NO = - { array_elements(my_locale_ab_day_names_nb_NO)-1, "", my_locale_ab_day_names_nb_NO, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_nb_NO); MY_LOCALE my_locale_nb_NO ( 37, @@ -1374,13 +1374,13 @@ static const char *my_locale_day_names_nl_NL[8] = static const char *my_locale_ab_day_names_nl_NL[8] = {"ma","di","wo","do","vr","za","zo", NullS }; static TYPELIB my_locale_typelib_month_names_nl_NL = - { array_elements(my_locale_month_names_nl_NL)-1, "", my_locale_month_names_nl_NL, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_nl_NL); static TYPELIB my_locale_typelib_ab_month_names_nl_NL = - { array_elements(my_locale_ab_month_names_nl_NL)-1, "", my_locale_ab_month_names_nl_NL, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_nl_NL); static TYPELIB my_locale_typelib_day_names_nl_NL = - { array_elements(my_locale_day_names_nl_NL)-1, "", my_locale_day_names_nl_NL, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_nl_NL); static TYPELIB my_locale_typelib_ab_day_names_nl_NL = - { array_elements(my_locale_ab_day_names_nl_NL)-1, "", my_locale_ab_day_names_nl_NL, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_nl_NL); MY_LOCALE my_locale_nl_NL ( 38, @@ -1410,13 +1410,13 @@ static const char *my_locale_day_names_pl_PL[8] = static const char *my_locale_ab_day_names_pl_PL[8] = {"pon","wto","śro","czw","pią","sob","nie", NullS }; static TYPELIB my_locale_typelib_month_names_pl_PL = - { array_elements(my_locale_month_names_pl_PL)-1, "", my_locale_month_names_pl_PL, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_pl_PL); static TYPELIB my_locale_typelib_ab_month_names_pl_PL = - { array_elements(my_locale_ab_month_names_pl_PL)-1, "", my_locale_ab_month_names_pl_PL, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_pl_PL); static TYPELIB my_locale_typelib_day_names_pl_PL = - { array_elements(my_locale_day_names_pl_PL)-1, "", my_locale_day_names_pl_PL, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_pl_PL); static TYPELIB my_locale_typelib_ab_day_names_pl_PL = - { array_elements(my_locale_ab_day_names_pl_PL)-1, "", my_locale_ab_day_names_pl_PL, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_pl_PL); MY_LOCALE my_locale_pl_PL ( 39, @@ -1446,13 +1446,13 @@ static const char *my_locale_day_names_pt_BR[8] = static const char *my_locale_ab_day_names_pt_BR[8] = {"Seg","Ter","Qua","Qui","Sex","Sáb","Dom", NullS }; static TYPELIB my_locale_typelib_month_names_pt_BR = - { array_elements(my_locale_month_names_pt_BR)-1, "", my_locale_month_names_pt_BR, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_pt_BR); static TYPELIB my_locale_typelib_ab_month_names_pt_BR = - { array_elements(my_locale_ab_month_names_pt_BR)-1, "", my_locale_ab_month_names_pt_BR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_pt_BR); static TYPELIB my_locale_typelib_day_names_pt_BR = - { array_elements(my_locale_day_names_pt_BR)-1, "", my_locale_day_names_pt_BR, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_pt_BR); static TYPELIB my_locale_typelib_ab_day_names_pt_BR = - { array_elements(my_locale_ab_day_names_pt_BR)-1, "", my_locale_ab_day_names_pt_BR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_pt_BR); MY_LOCALE my_locale_pt_BR ( 40, @@ -1482,13 +1482,13 @@ static const char *my_locale_day_names_pt_PT[8] = static const char *my_locale_ab_day_names_pt_PT[8] = {"Seg","Ter","Qua","Qui","Sex","Sáb","Dom", NullS }; static TYPELIB my_locale_typelib_month_names_pt_PT = - { array_elements(my_locale_month_names_pt_PT)-1, "", my_locale_month_names_pt_PT, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_pt_PT); static TYPELIB my_locale_typelib_ab_month_names_pt_PT = - { array_elements(my_locale_ab_month_names_pt_PT)-1, "", my_locale_ab_month_names_pt_PT, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_pt_PT); static TYPELIB my_locale_typelib_day_names_pt_PT = - { array_elements(my_locale_day_names_pt_PT)-1, "", my_locale_day_names_pt_PT, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_pt_PT); static TYPELIB my_locale_typelib_ab_day_names_pt_PT = - { array_elements(my_locale_ab_day_names_pt_PT)-1, "", my_locale_ab_day_names_pt_PT, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_pt_PT); MY_LOCALE my_locale_pt_PT ( 41, @@ -1518,13 +1518,13 @@ static const char *my_locale_day_names_ro_RO[8] = static const char *my_locale_ab_day_names_ro_RO[8] = {"Lu","Ma","Mi","Jo","Vi","Sâ","Du", NullS }; static TYPELIB my_locale_typelib_month_names_ro_RO = - { array_elements(my_locale_month_names_ro_RO)-1, "", my_locale_month_names_ro_RO, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ro_RO); static TYPELIB my_locale_typelib_ab_month_names_ro_RO = - { array_elements(my_locale_ab_month_names_ro_RO)-1, "", my_locale_ab_month_names_ro_RO, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ro_RO); static TYPELIB my_locale_typelib_day_names_ro_RO = - { array_elements(my_locale_day_names_ro_RO)-1, "", my_locale_day_names_ro_RO, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ro_RO); static TYPELIB my_locale_typelib_ab_day_names_ro_RO = - { array_elements(my_locale_ab_day_names_ro_RO)-1, "", my_locale_ab_day_names_ro_RO, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ro_RO); MY_LOCALE my_locale_ro_RO ( 42, @@ -1554,13 +1554,13 @@ static const char *my_locale_day_names_ru_RU[8] = static const char *my_locale_ab_day_names_ru_RU[8] = {"Пнд","Втр","Срд","Чтв","Птн","Сбт","Вск", NullS }; static TYPELIB my_locale_typelib_month_names_ru_RU = - { array_elements(my_locale_month_names_ru_RU)-1, "", my_locale_month_names_ru_RU, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ru_RU); static TYPELIB my_locale_typelib_ab_month_names_ru_RU = - { array_elements(my_locale_ab_month_names_ru_RU)-1, "", my_locale_ab_month_names_ru_RU, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ru_RU); static TYPELIB my_locale_typelib_day_names_ru_RU = - { array_elements(my_locale_day_names_ru_RU)-1, "", my_locale_day_names_ru_RU, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ru_RU); static TYPELIB my_locale_typelib_ab_day_names_ru_RU = - { array_elements(my_locale_ab_day_names_ru_RU)-1, "", my_locale_ab_day_names_ru_RU, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ru_RU); MY_LOCALE my_locale_ru_RU ( 43, @@ -1590,13 +1590,13 @@ static const char *my_locale_day_names_ru_UA[8] = static const char *my_locale_ab_day_names_ru_UA[8] = {"Пнд","Вто","Срд","Чтв","Птн","Суб","Вск", NullS }; static TYPELIB my_locale_typelib_month_names_ru_UA = - { array_elements(my_locale_month_names_ru_UA)-1, "", my_locale_month_names_ru_UA, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ru_UA); static TYPELIB my_locale_typelib_ab_month_names_ru_UA = - { array_elements(my_locale_ab_month_names_ru_UA)-1, "", my_locale_ab_month_names_ru_UA, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ru_UA); static TYPELIB my_locale_typelib_day_names_ru_UA = - { array_elements(my_locale_day_names_ru_UA)-1, "", my_locale_day_names_ru_UA, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ru_UA); static TYPELIB my_locale_typelib_ab_day_names_ru_UA = - { array_elements(my_locale_ab_day_names_ru_UA)-1, "", my_locale_ab_day_names_ru_UA, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ru_UA); MY_LOCALE my_locale_ru_UA ( 44, @@ -1626,13 +1626,13 @@ static const char *my_locale_day_names_sk_SK[8] = static const char *my_locale_ab_day_names_sk_SK[8] = {"Po","Ut","St","Št","Pi","So","Ne", NullS }; static TYPELIB my_locale_typelib_month_names_sk_SK = - { array_elements(my_locale_month_names_sk_SK)-1, "", my_locale_month_names_sk_SK, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_sk_SK); static TYPELIB my_locale_typelib_ab_month_names_sk_SK = - { array_elements(my_locale_ab_month_names_sk_SK)-1, "", my_locale_ab_month_names_sk_SK, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_sk_SK); static TYPELIB my_locale_typelib_day_names_sk_SK = - { array_elements(my_locale_day_names_sk_SK)-1, "", my_locale_day_names_sk_SK, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_sk_SK); static TYPELIB my_locale_typelib_ab_day_names_sk_SK = - { array_elements(my_locale_ab_day_names_sk_SK)-1, "", my_locale_ab_day_names_sk_SK, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_sk_SK); MY_LOCALE my_locale_sk_SK ( 45, @@ -1662,13 +1662,13 @@ static const char *my_locale_day_names_sl_SI[8] = static const char *my_locale_ab_day_names_sl_SI[8] = {"pon","tor","sre","čet","pet","sob","ned", NullS }; static TYPELIB my_locale_typelib_month_names_sl_SI = - { array_elements(my_locale_month_names_sl_SI)-1, "", my_locale_month_names_sl_SI, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_sl_SI); static TYPELIB my_locale_typelib_ab_month_names_sl_SI = - { array_elements(my_locale_ab_month_names_sl_SI)-1, "", my_locale_ab_month_names_sl_SI, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_sl_SI); static TYPELIB my_locale_typelib_day_names_sl_SI = - { array_elements(my_locale_day_names_sl_SI)-1, "", my_locale_day_names_sl_SI, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_sl_SI); static TYPELIB my_locale_typelib_ab_day_names_sl_SI = - { array_elements(my_locale_ab_day_names_sl_SI)-1, "", my_locale_ab_day_names_sl_SI, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_sl_SI); MY_LOCALE my_locale_sl_SI ( 46, @@ -1698,13 +1698,13 @@ static const char *my_locale_day_names_sq_AL[8] = static const char *my_locale_ab_day_names_sq_AL[8] = {"Hën ","Mar ","Mër ","Enj ","Pre ","Sht ","Die ", NullS }; static TYPELIB my_locale_typelib_month_names_sq_AL = - { array_elements(my_locale_month_names_sq_AL)-1, "", my_locale_month_names_sq_AL, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_sq_AL); static TYPELIB my_locale_typelib_ab_month_names_sq_AL = - { array_elements(my_locale_ab_month_names_sq_AL)-1, "", my_locale_ab_month_names_sq_AL, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_sq_AL); static TYPELIB my_locale_typelib_day_names_sq_AL = - { array_elements(my_locale_day_names_sq_AL)-1, "", my_locale_day_names_sq_AL, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_sq_AL); static TYPELIB my_locale_typelib_ab_day_names_sq_AL = - { array_elements(my_locale_ab_day_names_sq_AL)-1, "", my_locale_ab_day_names_sq_AL, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_sq_AL); MY_LOCALE my_locale_sq_AL ( 47, @@ -1734,13 +1734,13 @@ static const char *my_locale_day_names_sr_RS[8] = static const char *my_locale_ab_day_names_sr_RS[8] = {"pon","uto","sre","čet","pet","sub","ned", NullS }; static TYPELIB my_locale_typelib_month_names_sr_RS = - { array_elements(my_locale_month_names_sr_RS)-1, "", my_locale_month_names_sr_RS, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_sr_RS); static TYPELIB my_locale_typelib_ab_month_names_sr_RS = - { array_elements(my_locale_ab_month_names_sr_RS)-1, "", my_locale_ab_month_names_sr_RS, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_sr_RS); static TYPELIB my_locale_typelib_day_names_sr_RS = - { array_elements(my_locale_day_names_sr_RS)-1, "", my_locale_day_names_sr_RS, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_sr_RS); static TYPELIB my_locale_typelib_ab_day_names_sr_RS = - { array_elements(my_locale_ab_day_names_sr_RS)-1, "", my_locale_ab_day_names_sr_RS, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_sr_RS); MY_LOCALE my_locale_sr_RS ( @@ -1771,13 +1771,13 @@ static const char *my_locale_day_names_sv_SE[8] = static const char *my_locale_ab_day_names_sv_SE[8] = {"mån","tis","ons","tor","fre","lör","sön", NullS }; static TYPELIB my_locale_typelib_month_names_sv_SE = - { array_elements(my_locale_month_names_sv_SE)-1, "", my_locale_month_names_sv_SE, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_sv_SE); static TYPELIB my_locale_typelib_ab_month_names_sv_SE = - { array_elements(my_locale_ab_month_names_sv_SE)-1, "", my_locale_ab_month_names_sv_SE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_sv_SE); static TYPELIB my_locale_typelib_day_names_sv_SE = - { array_elements(my_locale_day_names_sv_SE)-1, "", my_locale_day_names_sv_SE, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_sv_SE); static TYPELIB my_locale_typelib_ab_day_names_sv_SE = - { array_elements(my_locale_ab_day_names_sv_SE)-1, "", my_locale_ab_day_names_sv_SE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_sv_SE); MY_LOCALE my_locale_sv_SE ( 3, @@ -1807,13 +1807,13 @@ static const char *my_locale_day_names_ta_IN[8] = static const char *my_locale_ab_day_names_ta_IN[8] = {"த","ச","ப","வ","வ","ச","ஞ", NullS }; static TYPELIB my_locale_typelib_month_names_ta_IN = - { array_elements(my_locale_month_names_ta_IN)-1, "", my_locale_month_names_ta_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ta_IN); static TYPELIB my_locale_typelib_ab_month_names_ta_IN = - { array_elements(my_locale_ab_month_names_ta_IN)-1, "", my_locale_ab_month_names_ta_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ta_IN); static TYPELIB my_locale_typelib_day_names_ta_IN = - { array_elements(my_locale_day_names_ta_IN)-1, "", my_locale_day_names_ta_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ta_IN); static TYPELIB my_locale_typelib_ab_day_names_ta_IN = - { array_elements(my_locale_ab_day_names_ta_IN)-1, "", my_locale_ab_day_names_ta_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ta_IN); MY_LOCALE my_locale_ta_IN ( 49, @@ -1843,13 +1843,13 @@ static const char *my_locale_day_names_te_IN[8] = static const char *my_locale_ab_day_names_te_IN[8] = {"సోమ","మంగళ","బుధ","గురు","శుక్ర","శని","ఆది", NullS }; static TYPELIB my_locale_typelib_month_names_te_IN = - { array_elements(my_locale_month_names_te_IN)-1, "", my_locale_month_names_te_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_te_IN); static TYPELIB my_locale_typelib_ab_month_names_te_IN = - { array_elements(my_locale_ab_month_names_te_IN)-1, "", my_locale_ab_month_names_te_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_te_IN); static TYPELIB my_locale_typelib_day_names_te_IN = - { array_elements(my_locale_day_names_te_IN)-1, "", my_locale_day_names_te_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_te_IN); static TYPELIB my_locale_typelib_ab_day_names_te_IN = - { array_elements(my_locale_ab_day_names_te_IN)-1, "", my_locale_ab_day_names_te_IN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_te_IN); MY_LOCALE my_locale_te_IN ( 50, @@ -1879,13 +1879,13 @@ static const char *my_locale_day_names_th_TH[8] = static const char *my_locale_ab_day_names_th_TH[8] = {"จ.","อ.","พ.","พฤ.","ศ.","ส.","อา.", NullS }; static TYPELIB my_locale_typelib_month_names_th_TH = - { array_elements(my_locale_month_names_th_TH)-1, "", my_locale_month_names_th_TH, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_th_TH); static TYPELIB my_locale_typelib_ab_month_names_th_TH = - { array_elements(my_locale_ab_month_names_th_TH)-1, "", my_locale_ab_month_names_th_TH, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_th_TH); static TYPELIB my_locale_typelib_day_names_th_TH = - { array_elements(my_locale_day_names_th_TH)-1, "", my_locale_day_names_th_TH, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_th_TH); static TYPELIB my_locale_typelib_ab_day_names_th_TH = - { array_elements(my_locale_ab_day_names_th_TH)-1, "", my_locale_ab_day_names_th_TH, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_th_TH); MY_LOCALE my_locale_th_TH ( 51, @@ -1915,13 +1915,13 @@ static const char *my_locale_day_names_tr_TR[8] = static const char *my_locale_ab_day_names_tr_TR[8] = {"Pzt","Sal","Çrş","Prş","Cum","Cts","Paz", NullS }; static TYPELIB my_locale_typelib_month_names_tr_TR = - { array_elements(my_locale_month_names_tr_TR)-1, "", my_locale_month_names_tr_TR, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_tr_TR); static TYPELIB my_locale_typelib_ab_month_names_tr_TR = - { array_elements(my_locale_ab_month_names_tr_TR)-1, "", my_locale_ab_month_names_tr_TR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_tr_TR); static TYPELIB my_locale_typelib_day_names_tr_TR = - { array_elements(my_locale_day_names_tr_TR)-1, "", my_locale_day_names_tr_TR, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_tr_TR); static TYPELIB my_locale_typelib_ab_day_names_tr_TR = - { array_elements(my_locale_ab_day_names_tr_TR)-1, "", my_locale_ab_day_names_tr_TR, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_tr_TR); MY_LOCALE my_locale_tr_TR ( 52, @@ -1951,13 +1951,13 @@ static const char *my_locale_day_names_uk_UA[8] = static const char *my_locale_ab_day_names_uk_UA[8] = {"Пнд","Втр","Срд","Чтв","Птн","Сбт","Ндл", NullS }; static TYPELIB my_locale_typelib_month_names_uk_UA = - { array_elements(my_locale_month_names_uk_UA)-1, "", my_locale_month_names_uk_UA, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_uk_UA); static TYPELIB my_locale_typelib_ab_month_names_uk_UA = - { array_elements(my_locale_ab_month_names_uk_UA)-1, "", my_locale_ab_month_names_uk_UA, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_uk_UA); static TYPELIB my_locale_typelib_day_names_uk_UA = - { array_elements(my_locale_day_names_uk_UA)-1, "", my_locale_day_names_uk_UA, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_uk_UA); static TYPELIB my_locale_typelib_ab_day_names_uk_UA = - { array_elements(my_locale_ab_day_names_uk_UA)-1, "", my_locale_ab_day_names_uk_UA, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_uk_UA); MY_LOCALE my_locale_uk_UA ( 53, @@ -1987,13 +1987,13 @@ static const char *my_locale_day_names_ur_PK[8] = static const char *my_locale_ab_day_names_ur_PK[8] = {"پير","منگل","بدھ","جمعرات","جمعه","هفته","اتوار", NullS }; static TYPELIB my_locale_typelib_month_names_ur_PK = - { array_elements(my_locale_month_names_ur_PK)-1, "", my_locale_month_names_ur_PK, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ur_PK); static TYPELIB my_locale_typelib_ab_month_names_ur_PK = - { array_elements(my_locale_ab_month_names_ur_PK)-1, "", my_locale_ab_month_names_ur_PK, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ur_PK); static TYPELIB my_locale_typelib_day_names_ur_PK = - { array_elements(my_locale_day_names_ur_PK)-1, "", my_locale_day_names_ur_PK, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ur_PK); static TYPELIB my_locale_typelib_ab_day_names_ur_PK = - { array_elements(my_locale_ab_day_names_ur_PK)-1, "", my_locale_ab_day_names_ur_PK, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ur_PK); MY_LOCALE my_locale_ur_PK ( 54, @@ -2023,13 +2023,13 @@ static const char *my_locale_day_names_vi_VN[8] = static const char *my_locale_ab_day_names_vi_VN[8] = {"Th 2 ","Th 3 ","Th 4 ","Th 5 ","Th 6 ","Th 7 ","CN ", NullS }; static TYPELIB my_locale_typelib_month_names_vi_VN = - { array_elements(my_locale_month_names_vi_VN)-1, "", my_locale_month_names_vi_VN, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_vi_VN); static TYPELIB my_locale_typelib_ab_month_names_vi_VN = - { array_elements(my_locale_ab_month_names_vi_VN)-1, "", my_locale_ab_month_names_vi_VN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_vi_VN); static TYPELIB my_locale_typelib_day_names_vi_VN = - { array_elements(my_locale_day_names_vi_VN)-1, "", my_locale_day_names_vi_VN, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_vi_VN); static TYPELIB my_locale_typelib_ab_day_names_vi_VN = - { array_elements(my_locale_ab_day_names_vi_VN)-1, "", my_locale_ab_day_names_vi_VN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_vi_VN); MY_LOCALE my_locale_vi_VN ( 55, @@ -2059,13 +2059,13 @@ static const char *my_locale_day_names_zh_CN[8] = static const char *my_locale_ab_day_names_zh_CN[8] = {"一","二","三","四","五","六","日", NullS }; static TYPELIB my_locale_typelib_month_names_zh_CN = - { array_elements(my_locale_month_names_zh_CN)-1, "", my_locale_month_names_zh_CN, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_zh_CN); static TYPELIB my_locale_typelib_ab_month_names_zh_CN = - { array_elements(my_locale_ab_month_names_zh_CN)-1, "", my_locale_ab_month_names_zh_CN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_zh_CN); static TYPELIB my_locale_typelib_day_names_zh_CN = - { array_elements(my_locale_day_names_zh_CN)-1, "", my_locale_day_names_zh_CN, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_zh_CN); static TYPELIB my_locale_typelib_ab_day_names_zh_CN = - { array_elements(my_locale_ab_day_names_zh_CN)-1, "", my_locale_ab_day_names_zh_CN, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_zh_CN); MY_LOCALE my_locale_zh_CN ( 56, @@ -2095,13 +2095,13 @@ static const char *my_locale_day_names_zh_TW[8] = static const char *my_locale_ab_day_names_zh_TW[8] = {"一","二","三","四","五","六","日", NullS }; static TYPELIB my_locale_typelib_month_names_zh_TW = - { array_elements(my_locale_month_names_zh_TW)-1, "", my_locale_month_names_zh_TW, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_zh_TW); static TYPELIB my_locale_typelib_ab_month_names_zh_TW = - { array_elements(my_locale_ab_month_names_zh_TW)-1, "", my_locale_ab_month_names_zh_TW, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_zh_TW); static TYPELIB my_locale_typelib_day_names_zh_TW = - { array_elements(my_locale_day_names_zh_TW)-1, "", my_locale_day_names_zh_TW, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_zh_TW); static TYPELIB my_locale_typelib_ab_day_names_zh_TW = - { array_elements(my_locale_ab_day_names_zh_TW)-1, "", my_locale_ab_day_names_zh_TW, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_zh_TW); MY_LOCALE my_locale_zh_TW ( 57, @@ -3331,16 +3331,16 @@ static const char *my_locale_ab_day_names_ka_GE[8] = {"ორშ","სამშ","ოთხშ","ხუთშ","პარ","შაბ","კვ", NullS }; static TYPELIB my_locale_typelib_month_names_ka_GE = - { array_elements(my_locale_month_names_ka_GE)-1, "", my_locale_month_names_ka_GE, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_ka_GE); static TYPELIB my_locale_typelib_ab_month_names_ka_GE = - { array_elements(my_locale_ab_month_names_ka_GE)-1, "", my_locale_ab_month_names_ka_GE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_ka_GE); static TYPELIB my_locale_typelib_day_names_ka_GE = - { array_elements(my_locale_day_names_ka_GE)-1, "", my_locale_day_names_ka_GE, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_ka_GE); static TYPELIB my_locale_typelib_ab_day_names_ka_GE = - { array_elements(my_locale_ab_day_names_ka_GE)-1, "", my_locale_ab_day_names_ka_GE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_ka_GE); MY_LOCALE my_locale_ka_GE ( @@ -3371,13 +3371,13 @@ static const char *my_locale_day_names_sw_KE[8] = static const char *my_locale_ab_day_names_sw_KE[8] = {"Jumatatu", "Jumanne", "Jumatano", "Alhamisi", "Ijumaa", "Jumamosi", "Jumapili", NullS }; static TYPELIB my_locale_typelib_month_names_sw_KE = - { array_elements(my_locale_month_names_sw_KE)-1, "", my_locale_month_names_sw_KE, NULL }; + CREATE_TYPELIB_FOR(my_locale_month_names_sw_KE); static TYPELIB my_locale_typelib_ab_month_names_sw_KE = - { array_elements(my_locale_ab_month_names_sw_KE)-1, "", my_locale_ab_month_names_sw_KE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_month_names_sw_KE); static TYPELIB my_locale_typelib_day_names_sw_KE = - { array_elements(my_locale_day_names_sw_KE)-1, "", my_locale_day_names_sw_KE, NULL }; + CREATE_TYPELIB_FOR(my_locale_day_names_sw_KE); static TYPELIB my_locale_typelib_ab_day_names_sw_KE = - { array_elements(my_locale_ab_day_names_sw_KE)-1, "", my_locale_ab_day_names_sw_KE, NULL }; + CREATE_TYPELIB_FOR(my_locale_ab_day_names_sw_KE); MY_LOCALE my_locale_sw_KE ( 112, diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index bbe9e816d79..48da7ce6f16 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -62,8 +62,7 @@ extern struct st_maria_plugin *mysql_mandatory_plugins[]; const char *global_plugin_typelib_names[]= { "OFF", "ON", "FORCE", "FORCE_PLUS_PERMANENT", NULL }; static TYPELIB global_plugin_typelib= - { array_elements(global_plugin_typelib_names)-1, - "", global_plugin_typelib_names, NULL }; + CREATE_TYPELIB_FOR(global_plugin_typelib_names); static I_List opt_plugin_load_list; I_List *opt_plugin_load_list_ptr= &opt_plugin_load_list; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index fa7ee195785..61d7c7a484a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -139,10 +139,7 @@ LEX_CSTRING INDEX_clex_str= { STRING_WITH_LEN("INDEX") }; static const char *grant_names[]={ "select","insert","update","delete","create","drop","reload","shutdown", "process","file","grant","references","index","alter"}; - -static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **), - "grant_types", - grant_names, NULL}; +static TYPELIB grant_types = CREATE_TYPELIB_FOR(grant_names); #endif /* Match the values of enum ha_choice */ diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index e20575212b0..385380f0e79 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2540,12 +2540,8 @@ Sys_var_slave_parallel_mode::global_value_ptr(THD *thd, static const char *slave_parallel_mode_names[] = { "none", "minimal", "conservative", "optimistic", "aggressive", NULL }; -export TYPELIB slave_parallel_mode_typelib = { - array_elements(slave_parallel_mode_names)-1, - "", - slave_parallel_mode_names, - NULL -}; +export TYPELIB slave_parallel_mode_typelib = + CREATE_TYPELIB_FOR(slave_parallel_mode_names); static Sys_var_on_access_global diff --git a/sql/sys_vars.inl b/sql/sys_vars.inl index 413e06b2f28..80079526869 100644 --- a/sql/sys_vars.inl +++ b/sql/sys_vars.inl @@ -102,7 +102,7 @@ static const char *bool_values[3]= {"OFF", "ON", 0}; -TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 }; +TYPELIB bool_typelib= CREATE_TYPELIB_FOR(bool_values); template diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index ef2b23b8892..1969b237acb 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -309,11 +309,7 @@ const char *xtrace_names[] = "QUERY", "STMT", "HANDLER", "BLOCK", "MONGO", NullS }; -TYPELIB xtrace_typelib = -{ - array_elements(xtrace_names) - 1, "xtrace_typelib", - xtrace_names, NULL -}; +TYPELIB xtrace_typelib = CREATE_TYPELIB_FOR(xtrace_names); static MYSQL_THDVAR_SET( xtrace, // name @@ -347,11 +343,7 @@ const char *usetemp_names[]= "NO", "AUTO", "YES", "FORCE", "TEST", NullS }; -TYPELIB usetemp_typelib= -{ - array_elements(usetemp_names) - 1, "usetemp_typelib", - usetemp_names, NULL -}; +TYPELIB usetemp_typelib= CREATE_TYPELIB_FOR(usetemp_names); static MYSQL_THDVAR_ENUM( use_tempfile, // name @@ -394,11 +386,7 @@ const char *xconv_names[]= "NO", "YES", "FORCE", "SKIP", NullS }; -TYPELIB xconv_typelib= -{ - array_elements(xconv_names) - 1, "xconv_typelib", - xconv_names, NULL -}; +TYPELIB xconv_typelib= CREATE_TYPELIB_FOR(xconv_names); static MYSQL_THDVAR_ENUM( type_conv, // name @@ -473,11 +461,7 @@ const char *language_names[]= "default", "english", "french", NullS }; -TYPELIB language_typelib= -{ - array_elements(language_names) - 1, "language_typelib", - language_names, NULL -}; +TYPELIB language_typelib= CREATE_TYPELIB_FOR(language_names); static MYSQL_THDVAR_ENUM( msg_lang, // name diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index 0ec2c65605b..6432a2b5146 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -1002,11 +1002,7 @@ const char *enum_var_names[]= "e1", "e2", NullS }; -TYPELIB enum_var_typelib= -{ - array_elements(enum_var_names) - 1, "enum_var_typelib", - enum_var_names, NULL -}; +TYPELIB enum_var_typelib= CREATE_TYPELIB_FOR(enum_var_names); static MYSQL_SYSVAR_ENUM( enum_var, // name diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 33ee9a80037..504b10a4994 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -296,12 +296,8 @@ static const char* innodb_stats_method_names[] = { /** Used to define an enumerate type of the system variable innodb_stats_method. This is the same as "myisam_stats_method_typelib" */ -static TYPELIB innodb_stats_method_typelib = { - array_elements(innodb_stats_method_names) - 1, - "innodb_stats_method_typelib", - innodb_stats_method_names, - NULL -}; +static TYPELIB innodb_stats_method_typelib = + CREATE_TYPELIB_FOR(innodb_stats_method_names); /** Possible values for system variable "innodb_linux_aio" */ #ifdef __linux__ @@ -333,12 +329,8 @@ const char* innodb_checksum_algorithm_names[] = { /** Used to define an enumerate type of the system variable innodb_checksum_algorithm. */ -TYPELIB innodb_checksum_algorithm_typelib = { - array_elements(innodb_checksum_algorithm_names) - 1, - "innodb_checksum_algorithm_typelib", - innodb_checksum_algorithm_names, - NULL -}; +TYPELIB innodb_checksum_algorithm_typelib = + CREATE_TYPELIB_FOR(innodb_checksum_algorithm_names); /** Possible values for system variable "innodb_default_row_format". */ static const char* innodb_default_row_format_names[] = { @@ -350,12 +342,8 @@ static const char* innodb_default_row_format_names[] = { /** Used to define an enumerate type of the system variable innodb_default_row_format. */ -static TYPELIB innodb_default_row_format_typelib = { - array_elements(innodb_default_row_format_names) - 1, - "innodb_default_row_format_typelib", - innodb_default_row_format_names, - NULL -}; +static TYPELIB innodb_default_row_format_typelib = + CREATE_TYPELIB_FOR(innodb_default_row_format_names); /** Names of allowed values of innodb_flush_method */ static const char* innodb_flush_method_names[] = { @@ -376,12 +364,8 @@ static const char* innodb_flush_method_names[] = { static constexpr ulong innodb_flush_method_default = IF_WIN(6,4); /** Enumeration of innodb_flush_method */ -TYPELIB innodb_flush_method_typelib = { - array_elements(innodb_flush_method_names) - 1, - "innodb_flush_method_typelib", - innodb_flush_method_names, - NULL -}; +TYPELIB innodb_flush_method_typelib = + CREATE_TYPELIB_FOR(innodb_flush_method_names); /** Deprecated parameter */ static ulong innodb_flush_method; @@ -391,12 +375,8 @@ static const char *innodb_doublewrite_names[]= {"OFF", "ON", "fast", nullptr}; /** Enumeration of innodb_doublewrite */ -TYPELIB innodb_doublewrite_typelib= { - array_elements(innodb_doublewrite_names) - 1, - "innodb_doublewrite_typelib", - innodb_doublewrite_names, - nullptr -}; +TYPELIB innodb_doublewrite_typelib= + CREATE_TYPELIB_FOR(innodb_doublewrite_names); /** Names of allowed values of innodb_deadlock_report */ static const char *innodb_deadlock_report_names[]= { @@ -411,12 +391,8 @@ static_assert(Deadlock::REPORT_BASIC == 1, "compatibility"); static_assert(Deadlock::REPORT_FULL == 2, "compatibility"); /** Enumeration of innodb_deadlock_report */ -static TYPELIB innodb_deadlock_report_typelib = { - array_elements(innodb_deadlock_report_names) - 1, - "innodb_deadlock_report_typelib", - innodb_deadlock_report_names, - NULL -}; +static TYPELIB innodb_deadlock_report_typelib = + CREATE_TYPELIB_FOR(innodb_deadlock_report_names); /** Allowed values of innodb_instant_alter_column_allowed */ const char* innodb_instant_alter_column_allowed_names[] = { @@ -427,12 +403,8 @@ const char* innodb_instant_alter_column_allowed_names[] = { }; /** Enumeration of innodb_instant_alter_column_allowed */ -static TYPELIB innodb_instant_alter_column_allowed_typelib = { - array_elements(innodb_instant_alter_column_allowed_names) - 1, - "innodb_instant_alter_column_allowed_typelib", - innodb_instant_alter_column_allowed_names, - NULL -}; +static TYPELIB innodb_instant_alter_column_allowed_typelib = + CREATE_TYPELIB_FOR(innodb_instant_alter_column_allowed_names); /** Retrieve the FTS Relevance Ranking result for doc with doc_id of m_prebuilt->fts_doc_id @@ -19757,10 +19729,7 @@ static MYSQL_SYSVAR_BOOL(alter_copy_bulk, innodb_alter_copy_bulk, const char *page_compression_algorithms[]= { "none", "zlib", "lz4", "lzo", "lzma", "bzip2", "snappy", 0 }; static TYPELIB page_compression_algorithms_typelib= -{ - array_elements(page_compression_algorithms) - 1, 0, - page_compression_algorithms, 0 -}; + CREATE_TYPELIB_FOR(page_compression_algorithms); static MYSQL_SYSVAR_ENUM(compression_algorithm, innodb_compression_algorithm, PLUGIN_VAR_OPCMDARG, "Compression algorithm used on page compression. One of: none, zlib, lz4, lzo, lzma, bzip2, or snappy", @@ -19781,10 +19750,8 @@ static MYSQL_SYSVAR_ULONG(fatal_semaphore_wait_threshold, srv_fatal_semaphore_wa 0); static const char* srv_encrypt_tables_names[] = { "OFF", "ON", "FORCE", 0 }; -static TYPELIB srv_encrypt_tables_typelib = { - array_elements(srv_encrypt_tables_names)-1, 0, srv_encrypt_tables_names, - NULL -}; +static TYPELIB srv_encrypt_tables_typelib = + CREATE_TYPELIB_FOR(srv_encrypt_tables_names); static MYSQL_SYSVAR_ENUM(encrypt_tables, srv_encrypt_tables, PLUGIN_VAR_OPCMDARG, "Enable encryption for tables. " diff --git a/storage/maria/aria_chk.c b/storage/maria/aria_chk.c index e02df8945b4..63513a0ce8f 100644 --- a/storage/maria/aria_chk.c +++ b/storage/maria/aria_chk.c @@ -642,9 +642,7 @@ Recover (repair)/ options (When using '--recover' or '--safe-recover'):\n\ const char *maria_stats_method_names[] = {"nulls_unequal", "nulls_equal", "nulls_ignored", NullS}; -TYPELIB maria_stats_method_typelib= { - array_elements(maria_stats_method_names) - 1, "", - maria_stats_method_names, NULL}; +TYPELIB maria_stats_method_typelib= CREATE_TYPELIB_FOR(maria_stats_method_names); /* Read options */ diff --git a/storage/maria/aria_s3_copy.cc b/storage/maria/aria_s3_copy.cc index d47812498aa..65bf753889a 100644 --- a/storage/maria/aria_s3_copy.cc +++ b/storage/maria/aria_s3_copy.cc @@ -32,7 +32,7 @@ #include static const char *op_types[]= {"to_s3", "from_s3", "delete_from_s3", NullS}; -static TYPELIB op_typelib= {array_elements(op_types)-1,"", op_types, NULL}; +static TYPELIB op_typelib= CREATE_TYPELIB_FOR(op_types); #define OP_IMPOSSIBLE array_elements(op_types) static const char *load_default_groups[]= { "aria_s3_copy", 0 }; diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index ab8a996e16f..390ebe7b6df 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -87,55 +87,35 @@ const char *maria_recover_names[]= */ "NORMAL", "BACKUP", "FORCE", "QUICK", "OFF", NullS }; -TYPELIB maria_recover_typelib= -{ - array_elements(maria_recover_names) - 1, "", - maria_recover_names, NULL -}; +TYPELIB maria_recover_typelib= CREATE_TYPELIB_FOR(maria_recover_names); const char *maria_stats_method_names[]= { "nulls_unequal", "nulls_equal", "nulls_ignored", NullS }; -TYPELIB maria_stats_method_typelib= -{ - array_elements(maria_stats_method_names) - 1, "", - maria_stats_method_names, NULL -}; +TYPELIB maria_stats_method_typelib= CREATE_TYPELIB_FOR(maria_stats_method_names); /* transactions log purge mode */ const char *maria_translog_purge_type_names[]= { "immediate", "external", "at_flush", NullS }; -TYPELIB maria_translog_purge_type_typelib= -{ - array_elements(maria_translog_purge_type_names) - 1, "", - maria_translog_purge_type_names, NULL -}; +TYPELIB maria_translog_purge_type_typelib= CREATE_TYPELIB_FOR(maria_translog_purge_type_names); /* transactional log directory sync */ const char *maria_sync_log_dir_names[]= { "NEVER", "NEWFILE", "ALWAYS", NullS }; -TYPELIB maria_sync_log_dir_typelib= -{ - array_elements(maria_sync_log_dir_names) - 1, "", - maria_sync_log_dir_names, NULL -}; +TYPELIB maria_sync_log_dir_typelib= CREATE_TYPELIB_FOR(maria_sync_log_dir_names); /* transactional log group commit */ const char *maria_group_commit_names[]= { "none", "hard", "soft", NullS }; -TYPELIB maria_group_commit_typelib= -{ - array_elements(maria_group_commit_names) - 1, "", - maria_group_commit_names, NULL -}; +TYPELIB maria_group_commit_typelib= CREATE_TYPELIB_FOR(maria_group_commit_names); /** Interval between background checkpoints in seconds */ static ulong checkpoint_interval; diff --git a/storage/maria/s3_func.c b/storage/maria/s3_func.c index eeacc3deb71..587e9b19f21 100644 --- a/storage/maria/s3_func.c +++ b/storage/maria/s3_func.c @@ -40,8 +40,7 @@ static int s3_read_file_from_disk(const char *filename, uchar **to, /* Used by ha_s3.cc and tools to define different protocol options */ static const char *protocol_types[]= {"Auto", "Original", "Amazon", "Legacy", "Path", "Domain", NullS}; -TYPELIB s3_protocol_typelib= {array_elements(protocol_types)-1,"", - protocol_types, NULL}; +TYPELIB s3_protocol_typelib= CREATE_TYPELIB_FOR(protocol_types); static const char *providers[]= {"Default", "Amazon", "Huawei", NullS}; TYPELIB s3_provider_typelib = {array_elements(providers)-1,"",providers, NULL}; diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp index 786830d0129..4bd97ffa6a6 100644 --- a/storage/mroonga/ha_mroonga.cpp +++ b/storage/mroonga/ha_mroonga.cpp @@ -661,12 +661,8 @@ static const char *mrn_boolean_mode_sytnax_flag_names[] = { "ALLOW_LEADING_NOT", NullS }; -static TYPELIB mrn_boolean_mode_syntax_flags_typelib = { - array_elements(mrn_boolean_mode_sytnax_flag_names) - 1, - "", - mrn_boolean_mode_sytnax_flag_names, - NULL -}; +static TYPELIB mrn_boolean_mode_syntax_flags_typelib = + CREATE_TYPELIB_FOR(mrn_boolean_mode_sytnax_flag_names); #endif #ifdef MRN_GROONGA_EMBEDDED static mrn_bool mrn_libgroonga_embedded = true; @@ -751,12 +747,8 @@ static const char *mrn_log_level_type_names[] = { "DUMP", NullS }; -static TYPELIB mrn_log_level_typelib = { - array_elements(mrn_log_level_type_names) - 1, - "mrn_log_level_typelib", - mrn_log_level_type_names, - NULL -}; +static TYPELIB mrn_log_level_typelib = + CREATE_TYPELIB_FOR(mrn_log_level_type_names); static void mrn_log_level_update(THD *thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save) @@ -1079,12 +1071,7 @@ static const char *mrn_action_on_error_names[] = { }; static TYPELIB mrn_action_on_error_typelib = -{ - array_elements(mrn_action_on_error_names) - 1, - "mrn_action_on_error_typelib", - mrn_action_on_error_names, - NULL -}; + CREATE_TYPELIB_FOR(mrn_action_on_error_names); static MYSQL_THDVAR_ENUM(action_on_fulltext_query_error, PLUGIN_VAR_RQCMDARG, diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 422be8d4742..2a77a7af8ac 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -41,14 +41,12 @@ static ulong opt_myisam_block_size; /* bits in myisam_recover_options */ const char *myisam_recover_names[] = { "DEFAULT", "BACKUP", "FORCE", "QUICK", "BACKUP_ALL", "OFF", NullS}; -TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"", - myisam_recover_names, NULL}; +TYPELIB myisam_recover_typelib= CREATE_TYPELIB_FOR(myisam_recover_names); const char *myisam_stats_method_names[] = {"NULLS_UNEQUAL", "NULLS_EQUAL", "NULLS_IGNORED", NullS}; -TYPELIB myisam_stats_method_typelib= { - array_elements(myisam_stats_method_names) - 1, "", - myisam_stats_method_names, NULL}; +TYPELIB myisam_stats_method_typelib= + CREATE_TYPELIB_FOR(myisam_stats_method_names); static MYSQL_SYSVAR_ULONG(block_size, opt_myisam_block_size, PLUGIN_VAR_READONLY | PLUGIN_VAR_RQCMDARG, diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c index 07586ccf11c..964a859ee38 100644 --- a/storage/myisam/myisamchk.c +++ b/storage/myisam/myisamchk.c @@ -476,9 +476,8 @@ static void usage(void) const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal", "nulls_ignored", NullS}; -TYPELIB myisam_stats_method_typelib= { - array_elements(myisam_stats_method_names) - 1, "", - myisam_stats_method_names, NULL}; +TYPELIB myisam_stats_method_typelib= + CREATE_TYPELIB_FOR(myisam_stats_method_names); /* Read options */ diff --git a/storage/myisammrg/myrg_static.c b/storage/myisammrg/myrg_static.c index 36ec25cb7d9..e140f01e9d4 100644 --- a/storage/myisammrg/myrg_static.c +++ b/storage/myisammrg/myrg_static.c @@ -26,8 +26,7 @@ LIST *myrg_open_list=0; static const char *merge_insert_methods[] = { "FIRST", "LAST", NullS }; -TYPELIB merge_insert_method= { array_elements(merge_insert_methods)-1,"", - merge_insert_methods, 0}; +TYPELIB merge_insert_method= CREATE_TYPELIB_FOR(merge_insert_methods); PSI_memory_key rg_key_memory_MYRG_INFO; PSI_memory_key rg_key_memory_children; diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index 677be84a582..526a444385f 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -771,17 +771,13 @@ static std::shared_ptr rocksdb_rate_limiter; static const char *write_policy_names[] = {"write_committed", "write_prepared", "write_unprepared", NullS}; -static TYPELIB write_policy_typelib = {array_elements(write_policy_names) - 1, - "write_policy_typelib", - write_policy_names, nullptr}; +static TYPELIB write_policy_typelib = CREATE_TYPELIB_FOR(write_policy_names); #if 0 // MARIAROCKS_NOT_YET : read-free replication is not supported /* This array needs to be kept up to date with myrocks::read_free_rpl_type */ static const char *read_free_rpl_names[] = {"OFF", "PK_ONLY", "PK_SK", NullS}; -static TYPELIB read_free_rpl_typelib = {array_elements(read_free_rpl_names) - 1, - "read_free_rpl_typelib", - read_free_rpl_names, nullptr}; +static TYPELIB read_free_rpl_typelib = CREATE_TYPELIB_FOR(read_free_rpl_names); #endif /* This enum needs to be kept up to date with rocksdb::InfoLogLevel */ @@ -789,9 +785,7 @@ static const char *info_log_level_names[] = {"debug_level", "info_level", "warn_level", "error_level", "fatal_level", NullS}; -static TYPELIB info_log_level_typelib = { - array_elements(info_log_level_names) - 1, "info_log_level_typelib", - info_log_level_names, nullptr}; +static TYPELIB info_log_level_typelib = CREATE_TYPELIB_FOR(info_log_level_names); static void rocksdb_set_rocksdb_info_log_level( THD *const thd, struct st_mysql_sys_var *const var, void *const var_ptr, @@ -906,9 +900,7 @@ static int rocksdb_compact_column_family(THD *const thd, static const char *index_type_names[] = {"kBinarySearch", "kHashSearch", NullS}; -static TYPELIB index_type_typelib = {array_elements(index_type_names) - 1, - "index_type_typelib", index_type_names, - nullptr}; +static TYPELIB index_type_typelib = CREATE_TYPELIB_FOR(index_type_names); const ulong RDB_MAX_LOCK_WAIT_SECONDS = 1024 * 1024 * 1024; const ulong RDB_DEFAULT_MAX_ROW_LOCKS = 1024 * 1024; From 155ed2c57934f34d3260d8071d7dee22a95b1f0b Mon Sep 17 00:00:00 2001 From: Rex Johnston Date: Thu, 2 Oct 2025 12:53:58 +1100 Subject: [PATCH 25/54] MDEV-37784 Introduce @@new_mode variable @@new_mode is a set of flags to control introduced features. Flags are by default off. Setting a flag in @@new_mode will introduce a new different server behaviour and/or set of features. We also introduce a new option 'hidden_values' into some system variable types to hide options that we do not wish to show as options. - Don't print hidden values in mysqld --help output. - Make get_options() use the same logic as check_new_mode_value() does. - Setting @@new_mode=ALL shouldn't give warnings. (cherry picked from commit f7387cb13d0ecb252f39b572c27c79dfc3fd3678) --- include/typelib.h | 9 ++- mysql-test/main/mysqld--help.result | 4 + mysql-test/suite/sys_vars/r/new_mode.result | 60 +++++++++++++++ .../sys_vars/r/sysvars_server_embedded.result | 10 +++ .../r/sysvars_server_notembedded.result | 10 +++ mysql-test/suite/sys_vars/t/new_mode.test | 50 +++++++++++++ mysys/my_getopt.c | 16 ++++ sql/handler.cc | 2 +- sql/mysqld.cc | 7 +- sql/set_var.cc | 18 ++++- sql/set_var.h | 2 + sql/share/errmsg-utf8.txt | 5 ++ sql/sql_class.h | 18 +++++ sql/sql_locale.cc | 16 ++-- sql/sys_vars.cc | 74 +++++++++++++++++++ sql/sys_vars.inl | 26 ++++--- storage/innobase/handler/ha_innodb.cc | 2 +- storage/maria/s3_func.c | 2 +- 18 files changed, 306 insertions(+), 25 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/new_mode.result create mode 100644 mysql-test/suite/sys_vars/t/new_mode.test diff --git a/include/typelib.h b/include/typelib.h index 9a8ee802cae..091e58d04c8 100644 --- a/include/typelib.h +++ b/include/typelib.h @@ -25,9 +25,16 @@ typedef struct st_typelib { /* Different types saved here */ const char *name; /* Name of typelib */ const char **type_names; unsigned int *type_lengths; + /* + An array of indexes of enum values that are no longer supported and so are + hidden. One cannot specify hidden values, an attempt to do so will produce + a warning (while an attempt to use a name that was never part of this set + will produce an error). + */ + const int *hidden_values; } TYPELIB; -#define CREATE_TYPELIB_FOR(X) { (unsigned int)(sizeof(X)/sizeof(X[0])) - 1, "", X, NULL } +#define CREATE_TYPELIB_FOR(X) { (unsigned int)(sizeof(X)/sizeof(X[0])) - 1, "", X, NULL, NULL } extern my_ulonglong find_typeset(const char *x, TYPELIB *typelib, int *error_position); diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index 306a0bb13a1..7bdf5fa33b1 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -742,6 +742,9 @@ The following specify which files/extra groups are read (specified before remain --net-write-timeout=# Number of seconds to wait for a block to be written to a connection before aborting the write + --new-mode=name Used to introduce new behavior to existing MariaDB + versions. Any combination of: TEST_WARNING1 + Use 'ALL' to set all combinations. --note-verbosity=name Verbosity level for note-warnings given to the user. See also @@sql_notes.. Any combination of: basic, @@ -1813,6 +1816,7 @@ net-buffer-length 16384 net-read-timeout 30 net-retry-count 10 net-write-timeout 60 +new-mode note-verbosity basic,explain old FALSE old-mode UTF8_IS_UTF8MB3 diff --git a/mysql-test/suite/sys_vars/r/new_mode.result b/mysql-test/suite/sys_vars/r/new_mode.result new file mode 100644 index 00000000000..bde9c402454 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/new_mode.result @@ -0,0 +1,60 @@ +SET @global_start_value = @@global.new_mode; +SELECT @global_start_value; +@global_start_value + +SET @session_start_value = @@session.new_mode; +SELECT @session_start_value; +@session_start_value + +SET @@global.new_mode = DEFAULT; +SELECT @@global.new_mode; +@@global.new_mode + +SELECT @@session.new_mode; +@@session.new_mode + +SET @@session.new_mode = "TEST_WARNING1"; +Warnings: +Warning 4206 'TEST_WARNING1' is default and ignored +SET @@session.new_mode = "TEST_WARNING1,TEST_WARNING2"; +Warnings: +Warning 4206 'TEST_WARNING1' is default and ignored +Warning 4206 'TEST_WARNING2' is default and ignored +SET @@session.new_mode = "TEST_WARNING1,TEST_WARNING2,TEST_WARNING3"; +ERROR 42000: Variable 'new_mode' can't be set to the value of 'TEST_WARNING3' +SET @@session.new_mode = "ALL"; +select @@session.new_mode; +@@session.new_mode + +SET @@global.new_mode = NULL; +ERROR 42000: Variable 'new_mode' can't be set to the value of 'NULL' +SET @@global.new_mode = ''; +SELECT @@global.new_mode; +@@global.new_mode + +SET @@global.new_mode = ' '; +SELECT @@global.new_mode; +@@global.new_mode + +SET @@session.new_mode = NULL; +ERROR 42000: Variable 'new_mode' can't be set to the value of 'NULL' +SET @@session.new_mode = ''; +SELECT @@session.new_mode; +@@session.new_mode + +SET @@session.new_mode = ' '; +SELECT @@session.new_mode; +@@session.new_mode + +SET @@global.new_mode = OFF; +ERROR 42000: Variable 'new_mode' can't be set to the value of 'OFF' +SET @@session.new_mode = OFF; +ERROR 42000: Variable 'new_mode' can't be set to the value of 'OFF' +SET @@global.new_mode = @global_start_value; +SELECT @@global.new_mode; +@@global.new_mode + +SET @@session.new_mode = @session_start_value; +SELECT @@session.new_mode; +@@session.new_mode + diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index de9c5701240..6688230c114 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2312,6 +2312,16 @@ NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME NEW_MODE +VARIABLE_SCOPE SESSION +VARIABLE_TYPE SET +VARIABLE_COMMENT Used to introduce new behavior to existing MariaDB versions +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME NOTE_VERBOSITY VARIABLE_SCOPE SESSION VARIABLE_TYPE SET diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 4eb3c276eae..baa44f133ca 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -2522,6 +2522,16 @@ NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME NEW_MODE +VARIABLE_SCOPE SESSION +VARIABLE_TYPE SET +VARIABLE_COMMENT Used to introduce new behavior to existing MariaDB versions +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME NOTE_VERBOSITY VARIABLE_SCOPE SESSION VARIABLE_TYPE SET diff --git a/mysql-test/suite/sys_vars/t/new_mode.test b/mysql-test/suite/sys_vars/t/new_mode.test new file mode 100644 index 00000000000..71998565bf5 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/new_mode.test @@ -0,0 +1,50 @@ +--source include/load_sysvars.inc +--source include/have_debug.inc + +SET @global_start_value = @@global.new_mode; +SELECT @global_start_value; + +SET @session_start_value = @@session.new_mode; +SELECT @session_start_value; + +SET @@global.new_mode = DEFAULT; +SELECT @@global.new_mode; +SELECT @@session.new_mode; + +SET @@session.new_mode = "TEST_WARNING1"; +SET @@session.new_mode = "TEST_WARNING1,TEST_WARNING2"; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@session.new_mode = "TEST_WARNING1,TEST_WARNING2,TEST_WARNING3"; + +SET @@session.new_mode = "ALL"; +select @@session.new_mode; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.new_mode = NULL; + +SET @@global.new_mode = ''; +SELECT @@global.new_mode; + +SET @@global.new_mode = ' '; +SELECT @@global.new_mode; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@session.new_mode = NULL; + +SET @@session.new_mode = ''; +SELECT @@session.new_mode; + +SET @@session.new_mode = ' '; +SELECT @@session.new_mode; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.new_mode = OFF; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@session.new_mode = OFF; + +SET @@global.new_mode = @global_start_value; +SELECT @@global.new_mode; + +SET @@session.new_mode = @session_start_value; +SELECT @@session.new_mode; diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index ebbc797d460..4c59a02e6b5 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -1649,6 +1649,22 @@ void my_print_help(const struct my_option *options) col= print_comment(optp->typelib->type_names[0], col, name_space, comment_space); for (i= 1; i < count; i++) { + my_bool skip_value= 0; + /* Do not print the value if it is listed in hidden_values */ + if (optp->typelib->hidden_values) + { + for (const int *value= optp->typelib->hidden_values; + *value >= 0; value++) + { + if (*value == (int)i) + { + skip_value= 1; + break; + } + } + } + if (skip_value) + continue; col= print_comment(", ", col, name_space, comment_space); col= print_comment(optp->typelib->type_names[i], col, name_space, comment_space); } diff --git a/sql/handler.cc b/sql/handler.cc index 997f892b1a3..55bb62a5331 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -154,7 +154,7 @@ const char *tx_isolation_names[]= NullS}; TYPELIB tx_isolation_typelib= CREATE_TYPELIB_FOR(tx_isolation_names); -static TYPELIB known_extensions= {0,"known_exts", NULL, NULL}; +static TYPELIB known_extensions= {0,"known_exts", NULL, NULL, NULL}; uint known_extensions_id= 0; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 70d789fa452..a1d5d8583e7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -300,7 +300,7 @@ static const char *tc_heuristic_recover_names[]= static TYPELIB tc_heuristic_recover_typelib= { array_elements(tc_heuristic_recover_names)-1,"", - tc_heuristic_recover_names, NULL + tc_heuristic_recover_names, NULL, NULL }; const char *first_keyword= "first"; @@ -8670,6 +8670,9 @@ static void option_error_reporter(enum loglevel level, const char *format, ...) C_MODE_END +extern const char **new_mode_default_names; + + /** Get server options from the command line, and perform related server initializations. @@ -8730,6 +8733,8 @@ static int get_options(int *argc_ptr, char ***argv_ptr) "release. Please use --old-mode instead. "); } + check_new_mode_value(NULL, &global_system_variables.new_behavior); + if (global_system_variables.net_buffer_length > global_system_variables.max_allowed_packet) { diff --git a/sql/set_var.cc b/sql/set_var.cc index a925452f797..d0fbefbd533 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1219,9 +1219,21 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond) strbuf.length(0); for (i=0; i < tl->count; i++) { - const char *name= tl->type_names[i]; - strbuf.append(name, strlen(name)); - strbuf.append(','); + bool show= TRUE; + if (tl->hidden_values) + { + for (uint j= 0; tl->hidden_values[j] >= 0; j++) + { + if (tl->hidden_values[j] == (int)i) + show= FALSE; + } + } + if (show) + { + const char *name= tl->type_names[i]; + strbuf.append(name, strlen(name)); + strbuf.append(','); + } } if (!strbuf.is_empty()) strbuf.chop(); diff --git a/sql/set_var.h b/sql/set_var.h index 506d62dd504..ef5dd2da15d 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -493,4 +493,6 @@ void free_engine_list(plugin_ref *list); plugin_ref *copy_engine_list(plugin_ref *list); plugin_ref *temp_copy_engine_list(THD *thd, plugin_ref *list); char *pretty_print_engine_list(THD *thd, plugin_ref *list); +void check_new_mode_value(THD *thd, ulonglong *v); + #endif diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 0ec61b45141..0a86809aa8d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -12292,3 +12292,8 @@ ER_VECTOR_FORMAT_INVALID eng "Invalid vector format at offset: %d for '%-.100s'. Must be a valid JSON array of numbers." ER_PSEUDO_THREAD_ID_OVERWRITE eng "Pseudo thread id should not be modified by the client as it will be overwritten" +ER_WARN_DEFAULT_SYNTAX + chi "'%s' 默认并被忽略" + eng "'%s' is default and ignored" + ger "'%s' ist Standard und wird ignoriert" + spa "'%s' Es predeterminado e ignorado" diff --git a/sql/sql_class.h b/sql/sql_class.h index 869268af70c..30ac9c94740 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -213,6 +213,23 @@ enum enum_binlog_row_image { void old_mode_deprecated_warnings(THD *thd, ulonglong v); + +/* + Bits for @@new_mode -> thd->variables.new_behaviour system variable + See sys_vars.cc /new_mode_all_names +*/ + +#define NEW_MODE_MAX 0 + +/* Definitions above that have transitioned from new behaviour to default */ + +#define NOW_DEFAULT -1 +#define NEW_MODE_TEST_WARNING1 NOW_DEFAULT +#define NEW_MODE_TEST_WARNING2 NOW_DEFAULT + +#define TEST_NEW_MODE_FLAG(thd, flag) \ + (flag == NOW_DEFAULT ? TRUE : thd->variables.new_behavior & flag) + extern char internal_table_name[2]; extern char empty_c_string[1]; extern MYSQL_PLUGIN_IMPORT const char **errmesg; @@ -717,6 +734,7 @@ typedef struct system_variables ulonglong optimizer_trace; sql_mode_t sql_mode; ///< which non-standard SQL behaviour should be enabled sql_mode_t old_behavior; ///< which old SQL behaviour should be enabled + sql_mode_t new_behavior; ///< which new SQL behaviour should be enabled ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING ulonglong join_buff_space_limit; ulonglong log_slow_filter; diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 8c9f2a69f9e..1f1f7efd572 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -3194,25 +3194,25 @@ static const char *my_locale_ab_day_names_el_GR[8]= static TYPELIB my_locale_typelib_month_names_el_GR= { array_elements(my_locale_month_names_el_GR) - 1, - "", my_locale_month_names_el_GR, NULL + "", my_locale_month_names_el_GR, NULL, NULL }; static TYPELIB my_locale_typelib_ab_month_names_el_GR= { array_elements(my_locale_ab_month_names_el_GR)-1, - "", my_locale_ab_month_names_el_GR, NULL + "", my_locale_ab_month_names_el_GR, NULL, NULL }; static TYPELIB my_locale_typelib_day_names_el_GR= { array_elements(my_locale_day_names_el_GR)-1, - "", my_locale_day_names_el_GR, NULL + "", my_locale_day_names_el_GR, NULL, NULL }; static TYPELIB my_locale_typelib_ab_day_names_el_GR= { array_elements(my_locale_ab_day_names_el_GR) - 1, - "", my_locale_ab_day_names_el_GR, NULL + "", my_locale_ab_day_names_el_GR, NULL, NULL }; MY_LOCALE my_locale_el_GR @@ -3262,25 +3262,25 @@ static const char *my_locale_ab_day_names_rm_CH[8]= static TYPELIB my_locale_typelib_month_names_rm_CH= { array_elements(my_locale_month_names_rm_CH) - 1, - "", my_locale_month_names_rm_CH, NULL + "", my_locale_month_names_rm_CH, NULL, NULL }; static TYPELIB my_locale_typelib_ab_month_names_rm_CH= { array_elements(my_locale_ab_month_names_rm_CH) - 1, - "", my_locale_ab_month_names_rm_CH, NULL + "", my_locale_ab_month_names_rm_CH, NULL, NULL }; static TYPELIB my_locale_typelib_day_names_rm_CH= { array_elements(my_locale_day_names_rm_CH) - 1, - "", my_locale_day_names_rm_CH, NULL + "", my_locale_day_names_rm_CH, NULL, NULL }; static TYPELIB my_locale_typelib_ab_day_names_rm_CH= { array_elements(my_locale_ab_day_names_rm_CH) - 1, - "", my_locale_ab_day_names_rm_CH, NULL + "", my_locale_ab_day_names_rm_CH, NULL, NULL }; MY_LOCALE my_locale_rm_CH diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 385380f0e79..e1943ae09f3 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4048,6 +4048,80 @@ static Sys_var_set Sys_old_behavior( old_mode_names, DEFAULT(OLD_MODE_DEFAULT_VALUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(old_mode_deprecated)); + +/* + Current 'not yet default' @@new_mode flag names see sql_class.h /NEW_MODE_ + These need to be be kept in the same order as the value of definitions above +*/ +static const char *new_mode_all_names[]= +{ + "TEST_WARNING1", // Default from here, See NEW_MODE_MAX + "TEST_WARNING2", + 0 +}; + +static int new_mode_hidden_names[] = +{ + 0, // TEST_WARNING1 + 1, // TEST_WARNING2 + -1 // End of list +}; + +/* + @@new_mode flag names that are now default and thus not configurable + see previous comment +*/ +const char **new_mode_default_names= &new_mode_all_names[NEW_MODE_MAX]; + + +/* + @brief + Emit warnings if the value of @@new_mode in *v contains flags that are + already included in the default behavior. + + @param v INOUT Bitmap where bits represent indexes in new_mode_all_names + array. + Bits representing obsolete elements will be cleared. +*/ + +void check_new_mode_value(THD *thd, ulonglong *v) +{ + ulonglong vl= *v >> NEW_MODE_MAX; + for (uint i=0; new_mode_default_names[i]; i++) + { + if ((1ULL<save_result.ulonglong_value); + return false; +} + +static Sys_var_set Sys_new_behavior( + "new_mode", + "Used to introduce new behavior to existing MariaDB versions", + SESSION_VAR(new_behavior), CMD_LINE(REQUIRED_ARG), + new_mode_all_names, DEFAULT(0), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_new_mode_var_value), 0, 0, + new_mode_hidden_names); + #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) #define SSL_OPT(X) CMD_LINE(REQUIRED_ARG,X) #else diff --git a/sql/sys_vars.inl b/sql/sys_vars.inl index 80079526869..b1299d82c4a 100644 --- a/sql/sys_vars.inl +++ b/sql/sys_vars.inl @@ -317,7 +317,7 @@ public: ulonglong def_val, PolyLock *lock, enum binlog_status_enum binlog_status_arg, on_check_function on_check_func, on_update_function on_update_func, - const char *substitute) + const char *substitute, int *hidden_values) : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, getopt.arg_type, show_val_type_arg, def_val, lock, binlog_status_arg, on_check_func, @@ -326,6 +326,7 @@ public: for (typelib.count= 0; values[typelib.count]; typelib.count++) /*no-op */; typelib.name=""; typelib.type_names= values; + typelib.hidden_values= hidden_values; typelib.type_lengths= 0; // only used by Fields_enum and Field_set option.typelib= &typelib; } @@ -387,7 +388,7 @@ public: : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, SHOW_CHAR, values, def_val, lock, binlog_status_arg, on_check_func, on_update_func, - substitute) + substitute, nullptr) { option.var_type|= GET_ENUM; option.min_value= 0; @@ -458,7 +459,7 @@ public: : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, SHOW_MY_BOOL, bool_values, def_val, lock, binlog_status_arg, on_check_func, on_update_func, - substitute) + substitute, nullptr) { option.var_type|= GET_BOOL; global_var(my_bool)= def_val; @@ -1404,11 +1405,11 @@ public: enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, on_check_function on_check_func=0, on_update_function on_update_func=0, - const char *substitute=0) + const char *substitute=0, int *hidden_values=nullptr) : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, SHOW_CHAR, values, def_val, lock, binlog_status_arg, on_check_func, on_update_func, - substitute) + substitute, hidden_values) { option.var_type|= GET_FLAGSET; global_var(ulonglong)= def_val; @@ -1517,11 +1518,11 @@ public: enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, on_check_function on_check_func=0, on_update_function on_update_func=0, - const char *substitute=0) + const char *substitute=0,int *hidden_values=nullptr) : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, SHOW_CHAR, values, def_val, lock, binlog_status_arg, on_check_func, on_update_func, - substitute) + substitute, hidden_values) { option.var_type|= GET_SET; option.min_value= 0; @@ -1570,6 +1571,13 @@ public: !my_charset_latin1.strnncollsp(res->to_lex_cstring(), all_clex_str)) { var->save_result.ulonglong_value= ((1ULL << (typelib.count)) -1); + if (typelib.hidden_values) + { + for (const int *p= typelib.hidden_values; *p >= 0; p++) + { + var->save_result.ulonglong_value &= ~(1ull << *p); + } + } error_len= 0; } /* @@ -1968,11 +1976,11 @@ public: enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, on_check_function on_check_func=0, on_update_function on_update_func=0, - const char *substitute=0) + const char *substitute=0, int *hidden_values=nullptr) : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, SHOW_MY_BOOL, bool_values, def_val, lock, binlog_status_arg, on_check_func, on_update_func, - substitute) + substitute, nullptr) { option.var_type|= GET_BIT; reverse_semantics= my_count_bits(bitmask_arg) > 1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 504b10a4994..355e434a30e 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -314,7 +314,7 @@ TYPELIB innodb_linux_aio_typelib = { array_elements(innodb_linux_aio_names) - 1, "innodb_linux_aio_typelib", innodb_linux_aio_names, - NULL + NULL, NULL }; #endif diff --git a/storage/maria/s3_func.c b/storage/maria/s3_func.c index 587e9b19f21..73c9cffed26 100644 --- a/storage/maria/s3_func.c +++ b/storage/maria/s3_func.c @@ -43,7 +43,7 @@ static const char *protocol_types[]= {"Auto", "Original", "Amazon", "Legacy", "P TYPELIB s3_protocol_typelib= CREATE_TYPELIB_FOR(protocol_types); static const char *providers[]= {"Default", "Amazon", "Huawei", NullS}; -TYPELIB s3_provider_typelib = {array_elements(providers)-1,"",providers, NULL}; +TYPELIB s3_provider_typelib = {array_elements(providers)-1,"",providers, NULL, NULL}; /****************************************************************************** Allocations handler for libmarias3 From a18f8d38563be493fcc9445bc25b2f97ce0d6b7a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 6 Oct 2025 10:53:05 +0200 Subject: [PATCH 26/54] MDEV-37784 fix the warning cannot add new warnings in 11.8 anymore: * remove ER_WARN_DEFAULT_SYNTAX * use ER_VARIABLE_IGNORED instead * change the wording in it to be more generic * simplified new_mode warning-printing code (cherry picked from commit 399edc7c6205c5a2b4f18ecbfa7c3552a5c3ca15) --- mysql-test/suite/sys_vars/r/new_mode.result | 6 +++--- .../suite/sys_vars/r/new_mode_notembedded.result | 2 ++ .../suite/sys_vars/t/new_mode_notembedded.opt | 1 + .../suite/sys_vars/t/new_mode_notembedded.test | 7 +++++++ sql/mysqld.cc | 3 +-- sql/share/errmsg-utf8.txt | 7 +------ sql/sys_vars.cc | 15 +++------------ 7 files changed, 18 insertions(+), 23 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/new_mode_notembedded.result create mode 100644 mysql-test/suite/sys_vars/t/new_mode_notembedded.opt create mode 100644 mysql-test/suite/sys_vars/t/new_mode_notembedded.test diff --git a/mysql-test/suite/sys_vars/r/new_mode.result b/mysql-test/suite/sys_vars/r/new_mode.result index bde9c402454..316a48dd2ce 100644 --- a/mysql-test/suite/sys_vars/r/new_mode.result +++ b/mysql-test/suite/sys_vars/r/new_mode.result @@ -15,11 +15,11 @@ SELECT @@session.new_mode; SET @@session.new_mode = "TEST_WARNING1"; Warnings: -Warning 4206 'TEST_WARNING1' is default and ignored +Warning 4200 The setting 'new_mode=TEST_WARNING1' is ignored. It only exists for compatibility with old installations and will be removed in a future release SET @@session.new_mode = "TEST_WARNING1,TEST_WARNING2"; Warnings: -Warning 4206 'TEST_WARNING1' is default and ignored -Warning 4206 'TEST_WARNING2' is default and ignored +Warning 4200 The setting 'new_mode=TEST_WARNING1' is ignored. It only exists for compatibility with old installations and will be removed in a future release +Warning 4200 The setting 'new_mode=TEST_WARNING2' is ignored. It only exists for compatibility with old installations and will be removed in a future release SET @@session.new_mode = "TEST_WARNING1,TEST_WARNING2,TEST_WARNING3"; ERROR 42000: Variable 'new_mode' can't be set to the value of 'TEST_WARNING3' SET @@session.new_mode = "ALL"; diff --git a/mysql-test/suite/sys_vars/r/new_mode_notembedded.result b/mysql-test/suite/sys_vars/r/new_mode_notembedded.result new file mode 100644 index 00000000000..a8576d92599 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/new_mode_notembedded.result @@ -0,0 +1,2 @@ +call mtr.add_suppression('new_mode=TEST_WARNING1'); +FOUND 1 /new_mode=TEST_WARNING1/ in mysqld.1.err diff --git a/mysql-test/suite/sys_vars/t/new_mode_notembedded.opt b/mysql-test/suite/sys_vars/t/new_mode_notembedded.opt new file mode 100644 index 00000000000..7321942b663 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/new_mode_notembedded.opt @@ -0,0 +1 @@ +--new-mode=TEST_WARNING1 diff --git a/mysql-test/suite/sys_vars/t/new_mode_notembedded.test b/mysql-test/suite/sys_vars/t/new_mode_notembedded.test new file mode 100644 index 00000000000..df6b0f81342 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/new_mode_notembedded.test @@ -0,0 +1,7 @@ +--source include/have_debug.inc +--source include/not_embedded.inc + +call mtr.add_suppression('new_mode=TEST_WARNING1'); +--let SEARCH_PATTERN=new_mode=TEST_WARNING1 +--let SEARCH_FILE=$MYSQLTEST_VARDIR/log/mysqld.1.err +--source include/search_pattern_in_file.inc diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a1d5d8583e7..9a107906976 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4182,6 +4182,7 @@ static int init_common_variables() global_system_variables.lc_messages= my_default_lc_messages; global_system_variables.errmsgs= my_default_lc_messages->errmsgs->errmsgs; init_client_errs(); + check_new_mode_value(NULL, &global_system_variables.new_behavior); mysql_library_init(unused,unused,unused); /* for replication */ lex_init(); if (item_create_init()) @@ -8733,8 +8734,6 @@ static int get_options(int *argc_ptr, char ***argv_ptr) "release. Please use --old-mode instead. "); } - check_new_mode_value(NULL, &global_system_variables.new_behavior); - if (global_system_variables.net_buffer_length > global_system_variables.max_allowed_packet) { diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 0a86809aa8d..c056e3cacbf 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -12277,7 +12277,7 @@ ER_SEQUENCE_TABLE_CANNOT_HAVE_ANY_CONSTRAINTS ER_SEQUENCE_TABLE_ORDER_BY eng "ORDER BY" ER_VARIABLE_IGNORED - eng "The variable '%s' is ignored. It only exists for compatibility with old installations and will be removed in a future release" + eng "The setting '%s' is ignored. It only exists for compatibility with old installations and will be removed in a future release" ER_INCORRECT_COLUMN_NAME_COUNT eng "Incorrect column name count for derived table" chi "派生表的列名计数不正确" @@ -12292,8 +12292,3 @@ ER_VECTOR_FORMAT_INVALID eng "Invalid vector format at offset: %d for '%-.100s'. Must be a valid JSON array of numbers." ER_PSEUDO_THREAD_ID_OVERWRITE eng "Pseudo thread id should not be modified by the client as it will be overwritten" -ER_WARN_DEFAULT_SYNTAX - chi "'%s' 默认并被忽略" - eng "'%s' is default and ignored" - ger "'%s' ist Standard und wird ignoriert" - spa "'%s' Es predeterminado e ignorado" diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index e1943ae09f3..904650a8607 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4091,19 +4091,10 @@ void check_new_mode_value(THD *thd, ulonglong *v) { if ((1ULL< Date: Wed, 8 Oct 2025 15:57:12 +0300 Subject: [PATCH 27/54] MDEV-37784 Introduce @@new_mode: support all values being hidden Fix my_print_help() to print "No currently supported values". It used to print the first value even if it was hidden. (cherry picked from commit 8664461e80bf39011d6c3e28b7fa4e8af95268cc) --- mysql-test/main/mysqld--help.result | 3 +-- mysys/my_getopt.c | 29 ++++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index 7bdf5fa33b1..78407640d80 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -743,8 +743,7 @@ The following specify which files/extra groups are read (specified before remain Number of seconds to wait for a block to be written to a connection before aborting the write --new-mode=name Used to introduce new behavior to existing MariaDB - versions. Any combination of: TEST_WARNING1 - Use 'ALL' to set all combinations. + versions. No currently supported values. --note-verbosity=name Verbosity level for note-warnings given to the user. See also @@sql_notes.. Any combination of: basic, diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 4c59a02e6b5..42a35c13da7 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -1569,6 +1569,7 @@ void my_print_help(const struct my_option *options) for (optp= options; optp->name; optp++) { const char *typelib_help= 0; + my_bool skip_or_all_message= 0; if (!optp->comment) continue; if (optp->id && optp->id < 256) @@ -1612,6 +1613,7 @@ void my_print_help(const struct my_option *options) if (optp->comment && *optp->comment) { uint count; + uint hidden_value_count= 0; if (col > name_space) { @@ -1632,8 +1634,22 @@ void my_print_help(const struct my_option *options) count= optp->typelib->count; break; case GET_SET: - typelib_help= ". Any combination of: "; + if (optp->typelib->hidden_values) + { + /* Count how many values are hidden */ + for (const int *val= optp->typelib->hidden_values; *val>= 0; val++) + hidden_value_count++; + } count= optp->typelib->count; + if (count == hidden_value_count) + { + /* All values are hidden */ + typelib_help= ". No currently supported values."; + count= 0; + skip_or_all_message= 1; + } + else + typelib_help= ". Any combination of: "; break; case GET_FLAGSET: typelib_help= ". Takes a comma-separated list of option=value pairs, " @@ -1645,9 +1661,9 @@ void my_print_help(const struct my_option *options) strstr(optp->comment, optp->typelib->type_names[0]) == NULL) { uint i; + my_bool printing_first= 1; col= print_comment(typelib_help, col, name_space, comment_space); - col= print_comment(optp->typelib->type_names[0], col, name_space, comment_space); - for (i= 1; i < count; i++) + for (i= 0; i < count; i++) { my_bool skip_value= 0; /* Do not print the value if it is listed in hidden_values */ @@ -1665,7 +1681,10 @@ void my_print_help(const struct my_option *options) } if (skip_value) continue; - col= print_comment(", ", col, name_space, comment_space); + if (printing_first) + printing_first= 0; + else + col= print_comment(", ", col, name_space, comment_space); col= print_comment(optp->typelib->type_names[i], col, name_space, comment_space); } } @@ -1681,7 +1700,7 @@ void my_print_help(const struct my_option *options) printf(" to disable.)\n"); } } - else if ((optp->var_type & GET_TYPE_MASK) == GET_SET) + else if ((optp->var_type & GET_TYPE_MASK) == GET_SET && !skip_or_all_message) printf(" Use 'ALL' to set all combinations.\n"); } DBUG_VOID_RETURN; From d0ac583df8cf445f0fab5c7e2340f717ce9357b0 Mon Sep 17 00:00:00 2001 From: Oleg Smirnov Date: Wed, 1 Oct 2025 19:55:51 +0300 Subject: [PATCH 28/54] MDEV-36761 Implement NULL-aware cardinality estimation for indexed columns (Preparation for the main patch) set_statistics_for_table() incorrectly treated indexes with all NULL values the same as indexes with no statistics, because avg_frequency is 0 in both cases. This caused the optimizer to ignore valid EITS data and fall back to engine statistics. Additionally, KEY::actual_rec_per_key() would fall back to engine statistics even when EITS was available, and used incorrect pointer comparison (rec_per_key == 0 instead of nullptr). Fix by adding Index_statistics::stats_were_read flag to track per-index whether statistics were actually read from persistent tables, and restructuring actual_rec_per_key() to prioritize EITS when available. --- sql/sql_statistics.cc | 5 ++++- sql/sql_statistics.h | 11 ++++++++++- sql/table.cc | 13 +++++++++---- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 85428a43a46..588948412ff 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -3120,7 +3120,10 @@ read_statistics_for_table(THD *thd, TABLE *table, found|= index_stat.get_stat_values(index_statistics); } if (found) + { new_stats_cb->stats_available|= TABLE_STAT_INDEX; + index_statistics->mark_stats_as_read(); + } key_part_map ext_key_part_map= key_info->ext_key_part_map; if (key_info->user_defined_key_parts != key_info->ext_key_parts && @@ -4157,7 +4160,7 @@ void set_statistics_for_table(THD *thd, TABLE *table) (check_eits_preferred(thd) && table->stats_is_read && key_info->read_stats->avg_frequency_is_inited() && - key_info->read_stats->get_avg_frequency(0) > 0.5); + key_info->read_stats->has_stats()); } } diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index a5ff7ec7561..871d942c021 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -603,10 +603,19 @@ private: k-component prefixes among them */ ulonglong *avg_frequency; + bool stats_were_read; public: - void init_avg_frequency(ulonglong *ptr) { avg_frequency= ptr; } + void init_avg_frequency(ulonglong *ptr) + { + avg_frequency= ptr; + stats_were_read= false; + } + + void mark_stats_as_read() { stats_were_read= true; } + + bool has_stats() const { return stats_were_read; } bool avg_frequency_is_inited() { return avg_frequency != NULL; } diff --git a/sql/table.cc b/sql/table.cc index 8596a19d016..937ed518187 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -10299,10 +10299,15 @@ uint TABLE_SHARE::actual_n_key_parts(THD *thd) double KEY::actual_rec_per_key(uint i) const { - if (rec_per_key == 0) - return 0; - return (is_statistics_from_stat_tables ? - read_stats->get_avg_frequency(i) : (double) rec_per_key[i]); + if (is_statistics_from_stat_tables) + { + // Use engine-independent statistics (EITS) + return read_stats->get_avg_frequency(i); + } + // Fall back to engine-dependent statistics if EITS is not available + if (rec_per_key == nullptr) + return 0; // No statistics available + return (double) rec_per_key[i]; } /* From 1ae06b9e2ed3e04dcaeae7b47c47a5d68ff2f17d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 24 Oct 2025 11:45:06 +0200 Subject: [PATCH 29/54] MDEV-37947 Item_func_hex doesn't check for max_allowed_packet --- mysql-test/main/func_str.result | 9 +++++++-- mysql-test/main/func_str.test | 9 ++++----- sql/item_strfunc.cc | 14 +++++++++++++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/mysql-test/main/func_str.result b/mysql-test/main/func_str.result index 8ce64198461..db491092eb8 100644 --- a/mysql-test/main/func_str.result +++ b/mysql-test/main/func_str.result @@ -1,4 +1,3 @@ -drop table if exists t1,t2; set @save_max_allowed_packet=@@global.max_allowed_packet; set global max_allowed_packet=1048576; connect conn1,localhost,root,,; @@ -5415,5 +5414,11 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; # -# End of 10.6 tests +# MDEV-37947 Item_func_hex doesn't check for max_allowed_packet # +select hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex('\\'))))))))))))))))))))))))))))))))))))))))))))) as x; +x +NULL +Warnings: +Warning 1301 Result of hex() was larger than max_allowed_packet (16777216) - truncated +# End of 10.6 tests diff --git a/mysql-test/main/func_str.test b/mysql-test/main/func_str.test index b901aabbab2..adfa82b094a 100644 --- a/mysql-test/main/func_str.test +++ b/mysql-test/main/func_str.test @@ -2,10 +2,6 @@ # ----------- # Testing string functions ---disable_warnings -drop table if exists t1,t2; ---enable_warnings - set @save_max_allowed_packet=@@global.max_allowed_packet; set global max_allowed_packet=1048576; connect (conn1,localhost,root,,); @@ -2455,5 +2451,8 @@ SHOW CREATE TABLE t1; DROP TABLE t1; --echo # ---echo # End of 10.6 tests +--echo # MDEV-37947 Item_func_hex doesn't check for max_allowed_packet --echo # +select hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex(hex('\\'))))))))))))))))))))))))))))))))))))))))))))) as x; + +--echo # End of 10.6 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 5d778445d20..d06a076e9de 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3828,9 +3828,21 @@ String *Item_func_hex::val_str_ascii_from_val_str(String *str) { DBUG_ASSERT(&tmp_value != str); String *res= args[0]->val_str(&tmp_value); - DBUG_ASSERT(res != str); + THD *thd= current_thd; + if ((null_value= (res == NULL))) return NULL; + + if (res->length()*2 > thd->variables.max_allowed_packet) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_ALLOWED_PACKET_OVERFLOWED, + ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED), + func_name(), thd->variables.max_allowed_packet); + null_value= true; + return NULL; + } + return str->set_hex(res->ptr(), res->length()) ? make_empty_result(str) : str; } From 569039eb059c1861353251652486b5370b1a8ce2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Jan 2019 00:26:23 +0100 Subject: [PATCH 30/54] MDEV-35904/MDEV-19210: use environment file in systemd units for _WSREP_START_POSITION MDEV-35904 - backport MDEV-19210 to 10.11 as referenced by unset environment variables become warnings. We used to run `systemctl set-environment` to pass _WSREP_START_POSITION. This is bad because: * it clutter systemd's environment (yes, pid 1) * it requires root privileges * options (like LimitNOFILE=) are not applied Let's just create an environment file in ExecStartPre=, that is read before ExecStart= kicks in. We have _WSREP_START_POSITION around for the main process without any downsides. --- support-files/CMakeLists.txt | 2 ++ support-files/mariadb.service.in | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 44ad8d0ae94..2c88a8a334d 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -45,6 +45,8 @@ ELSE() IF(DEB) SET(su_user "#su mysql mysql") ENDIF() + get_filename_component(MYSQL_UNIX_DIR ${MYSQL_UNIX_ADDR} DIRECTORY) + SET(mysqlunixdir ${MYSQL_UNIX_DIR}) ENDIF() # XXX: shouldn't we just have variables for all this stuff and centralise diff --git a/support-files/mariadb.service.in b/support-files/mariadb.service.in index 0c72c1ee544..a7c76caafbe 100644 --- a/support-files/mariadb.service.in +++ b/support-files/mariadb.service.in @@ -65,17 +65,23 @@ ProtectHome=true # Execute pre and post scripts as root, otherwise it does it as User= PermissionsStartOnly=true +# Use an environment file to pass variable _WSREP_NEW_CLUSTER +EnvironmentFile=-@mysqlunixdir@/wsrep-new-cluster + +# Use an environment file to pass variable _WSREP_START_POSITION +EnvironmentFile=-@mysqlunixdir@/wsrep-start-position + @SYSTEMD_EXECSTARTPRE@ # Perform automatic wsrep recovery. When server is started without wsrep, # galera_recovery simply returns an empty string. In any case, however, # the script is not expected to return with a non-zero status. -# It is always safe to unset _WSREP_START_POSITION environment variable. +# It is always safe to remove @mysqlunixdir@/wsrep-start-position +# environment file. # Do not panic if galera_recovery script is not available. (MDEV-10538) -ExecStartPre=/bin/sh -c "systemctl unset-environment _WSREP_START_POSITION" ExecStartPre=/bin/sh -c "[ ! -e @bindir@/galera_recovery ] && VAR= || \ VAR=`@bindir@/galera_recovery`; [ $? -eq 0 ] \ - && systemctl set-environment _WSREP_START_POSITION=$VAR || exit 1" + && echo _WSREP_START_POSITION=$VAR > @mysqlunixdir@/wsrep-start-position || exit 1" # Needed to create system tables etc. # ExecStartPre=@scriptdir@/mariadb-install-db -u mysql @@ -88,7 +94,7 @@ ExecStartPre=/bin/sh -c "[ ! -e @bindir@/galera_recovery ] && VAR= || \ ExecStart=@sbindir@/mariadbd $MYSQLD_OPTS $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION # Unset _WSREP_START_POSITION environment variable. -ExecStartPost=/bin/sh -c "systemctl unset-environment _WSREP_START_POSITION" +ExecStartPost=/bin/rm -f @mysqlunixdir@/wsrep-start-position @SYSTEMD_EXECSTARTPOST@ From 649216e70d87c84b6c78e4cfb26c0afc96d5192e Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 25 Sep 2025 07:05:01 +1000 Subject: [PATCH 31/54] MDEV-37726 wsrep-new-cluster and wsrep-start-position in wrong directory with wrong selinux permissions After moving the systemd service to using environment files instead of `systemctl set-environment` in 11.6 (MDEV-19210), they (wsrep-new-cluster and wsrep-start-position) are located in /var/lib/mysql along with the socket file in Fedora/RHEL-based distros. This causes them to have incorrect selinux permissions and therefore be not readable by systemd. A solution is to generate these files in the run directory, instead, which already has correct selinux label mysqld_var_run_t mysql-selinux-1.0.12. Dissociating these files and the socket in CMake configs can also prove useful for other things. This also corrects some of the duplicate code in the build scripts and made INSTALL_RUNDATADIR into a proper location and used this for the tmpfiles where the temporary files are created. Debian's location is /run/mysqld/ matching its INSTALL_UNIX_ADDRDIR, which is now a temporary location controlled by tmpfiles. --- cmake/install_layout.cmake | 8 +++++++- scripts/galera_new_cluster.sh | 6 +++--- support-files/CMakeLists.txt | 9 +++++---- support-files/mariadb.service.in | 12 ++++++------ support-files/tmpfiles.conf.in | 16 +++++++++++++++- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake index 877b147bc6e..9410bc7a48a 100644 --- a/cmake/install_layout.cmake +++ b/cmake/install_layout.cmake @@ -163,6 +163,7 @@ SET(INSTALL_UNIX_ADDRDIR_RPM "${INSTALL_MYSQLDATADIR_RPM}/mysql.sock" SET(INSTALL_SYSTEMD_UNITDIR_RPM "/usr/lib/systemd/system") SET(INSTALL_SYSTEMD_SYSUSERSDIR_RPM "/usr/lib/sysusers.d") SET(INSTALL_SYSTEMD_TMPFILESDIR_RPM "/usr/lib/tmpfiles.d") +SET(INSTALL_RUNDATADIR_RPM "/run/mariadb") SET(INSTALL_PAMDIR_RPM "/${INSTALL_LIBDIR_RPM}/security") SET(INSTALL_PAMDATADIR_RPM "/etc/security") @@ -193,7 +194,8 @@ SET(INSTALL_SUPPORTFILESDIR_DEB "share/mysql") # SET(INSTALL_MYSQLDATADIR_DEB "/var/lib/mysql") -SET(INSTALL_UNIX_ADDRDIR_DEB "/run/mysqld/mysqld.sock") +SET(INSTALL_RUNDATADIR_DEB "/run/mysqld") +SET(INSTALL_UNIX_ADDRDIR_DEB "${INSTALL_RUNDATADIR_DEB}/mysqld.sock") SET(INSTALL_SYSTEMD_UNITDIR_DEB "/lib/systemd/system") SET(INSTALL_SYSTEMD_SYSUSERSDIR_DEB "/usr/lib/sysusers.d") SET(INSTALL_SYSTEMD_TMPFILESDIR_DEB "/usr/lib/tmpfiles.d") @@ -257,3 +259,7 @@ IF(NOT MYSQL_UNIX_ADDR) SET(MYSQL_UNIX_ADDR ${INSTALL_UNIX_ADDRDIR}) ENDIF() +IF(NOT INSTALL_RUNDATADIR) + get_filename_component(MYSQL_UNIX_DIR ${MYSQL_UNIX_ADDR} DIRECTORY) + SET(INSTALL_RUNDATADIR "${MYSQL_UNIX_DIR}" CACHE FILEPATH "Rundata installation directory" ${FORCE}) +ENDIF() diff --git a/scripts/galera_new_cluster.sh b/scripts/galera_new_cluster.sh index ac9dcf42102..b0aef8e05d2 100755 --- a/scripts/galera_new_cluster.sh +++ b/scripts/galera_new_cluster.sh @@ -21,11 +21,11 @@ EOF exit 0 fi -systemctl set-environment _WSREP_NEW_CLUSTER='--wsrep-new-cluster' && \ - systemctl restart ${1:-mariadb} +echo _WSREP_NEW_CLUSTER='--wsrep-new-cluster' > "@INSTALL_RUNDATADIR@/wsrep-new-cluster" && \ + systemctl restart mariadb.service extcode=$? -systemctl set-environment _WSREP_NEW_CLUSTER='' +rm -f "@INSTALL_RUNDATADIR@/wsrep-new-cluster" exit $extcode diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 2c88a8a334d..027e8e6a786 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -45,8 +45,6 @@ ELSE() IF(DEB) SET(su_user "#su mysql mysql") ENDIF() - get_filename_component(MYSQL_UNIX_DIR ${MYSQL_UNIX_ADDR} DIRECTORY) - SET(mysqlunixdir ${MYSQL_UNIX_DIR}) ENDIF() # XXX: shouldn't we just have variables for all this stuff and centralise @@ -212,8 +210,11 @@ IF(UNIX AND NOT WITHOUT_SERVER) RENAME mariadb.conf COMPONENT Server) ENDIF() - IF((HAVE_SYSTEMD OR INSTALL_SYSTEMD_TMPUSERS) AND INSTALL_SYSTEMD_TMPFILESDIR) - get_filename_component(MYSQL_UNIX_DIR ${MYSQL_UNIX_ADDR} DIRECTORY) + IF((HAVE_SYSTEMD OR INSTALL_SYSTEMD_TMPUSERS) AND INSTALL_SYSTEMD_TMPFILESDIR + AND INSTALL_RUNDATADIR) + IF(MYSQL_DATADIR STREQUAL INSTALL_RUNDATADIR) + SET(DISABLE_TMP "#") + ENDIF() CONFIGURE_FILE(tmpfiles.conf.in ${CMAKE_CURRENT_BINARY_DIR}/tmpfiles.conf @ONLY) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/tmpfiles.conf diff --git a/support-files/mariadb.service.in b/support-files/mariadb.service.in index a7c76caafbe..fff9ba762bb 100644 --- a/support-files/mariadb.service.in +++ b/support-files/mariadb.service.in @@ -66,22 +66,22 @@ ProtectHome=true PermissionsStartOnly=true # Use an environment file to pass variable _WSREP_NEW_CLUSTER -EnvironmentFile=-@mysqlunixdir@/wsrep-new-cluster +EnvironmentFile=-@INSTALL_RUNDATADIR@/wsrep-new-cluster # Use an environment file to pass variable _WSREP_START_POSITION -EnvironmentFile=-@mysqlunixdir@/wsrep-start-position +EnvironmentFile=-@INSTALL_RUNDATADIR@/wsrep-start-position @SYSTEMD_EXECSTARTPRE@ # Perform automatic wsrep recovery. When server is started without wsrep, # galera_recovery simply returns an empty string. In any case, however, # the script is not expected to return with a non-zero status. -# It is always safe to remove @mysqlunixdir@/wsrep-start-position +# It is always safe to remove @INSTALL_RUNDATADIR@/wsrep-start-position # environment file. # Do not panic if galera_recovery script is not available. (MDEV-10538) ExecStartPre=/bin/sh -c "[ ! -e @bindir@/galera_recovery ] && VAR= || \ VAR=`@bindir@/galera_recovery`; [ $? -eq 0 ] \ - && echo _WSREP_START_POSITION=$VAR > @mysqlunixdir@/wsrep-start-position || exit 1" + && echo _WSREP_START_POSITION=$VAR > @INSTALL_RUNDATADIR@/wsrep-start-position || exit 1" # Needed to create system tables etc. # ExecStartPre=@scriptdir@/mariadb-install-db -u mysql @@ -93,8 +93,8 @@ ExecStartPre=/bin/sh -c "[ ! -e @bindir@/galera_recovery ] && VAR= || \ # _WSREP_NEW_CLUSTER is for the exclusive use of the script galera_new_cluster ExecStart=@sbindir@/mariadbd $MYSQLD_OPTS $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION -# Unset _WSREP_START_POSITION environment variable. -ExecStartPost=/bin/rm -f @mysqlunixdir@/wsrep-start-position +# Unset _WSREP_START_POSITION/_WSREP_NEW_CLUSTER environment variable. +ExecStartPost=/bin/rm -f @INSTALL_RUNDATADIR@/wsrep-start-position @INSTALL_RUNDATADIR@/wsrep-new-cluster @SYSTEMD_EXECSTARTPOST@ diff --git a/support-files/tmpfiles.conf.in b/support-files/tmpfiles.conf.in index 03d66abc0c7..e67756f128a 100644 --- a/support-files/tmpfiles.conf.in +++ b/support-files/tmpfiles.conf.in @@ -1 +1,15 @@ -d @MYSQL_UNIX_DIR@ 0755 @MYSQLD_USER@ @MYSQLD_USER@ - +# This is the directory where the unix socket +# of MariaDB may be created. +# +# Under Galera this is where an envfile of +# the Galera start position is stored. +# +# Other temporary directories can be created here like: +# * tmpdir +# * innodb_tmpdir +# * innodb_temp_data_file_path +# * rocksdb_tmpdir +# etc. +# It shouldn't be used for datadir which is why it +# may be disabled. +@DISABLE_TMP@d @INSTALL_RUNDATADIR@ 0755 @MYSQLD_USER@ @MYSQLD_USER@ - From f1aaa7518461c346c06d4ed0701b42552129cfc5 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 30 Sep 2025 15:27:52 +1000 Subject: [PATCH 32/54] MDEV-15502 debian: systemd, with tmpfiles install not required With PermissionsStartOnly deprecated, remove this from the systemd service file. Replace Debian's ExecStartPre "install -d" with a tmpfile configuration directive creating the directory with this. Debian's ExecStartPost of the mariadb upgrade uses the ! special executable prefix added in systemd v231 to use root privs. --- cmake/systemd.cmake | 3 +-- debian/mariadb-server.install | 1 + debian/not-installed | 1 - support-files/CMakeLists.txt | 10 +++++++--- support-files/mariadb.service.in | 7 +------ support-files/tmpfiles.conf.in | 3 ++- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/cmake/systemd.cmake b/cmake/systemd.cmake index 0f37acd2afe..ff3499c87ad 100644 --- a/cmake/systemd.cmake +++ b/cmake/systemd.cmake @@ -50,8 +50,7 @@ MACRO(CHECK_SYSTEMD) SET(SYSTEMD_SCRIPTS ${SYSTEMD_SCRIPTS} galera_new_cluster galera_recovery) ENDIF() IF(DEB) - SET(SYSTEMD_EXECSTARTPRE "ExecStartPre=/usr/bin/install -m 755 -o mysql -g root -d /var/run/mysqld") - SET(SYSTEMD_EXECSTARTPOST "ExecStartPost=/etc/mysql/debian-start") + SET(SYSTEMD_EXECSTARTPOST "ExecStartPost=!/etc/mysql/debian-start") ENDIF() IF(URING_FOUND) SET(SYSTEMD_LIMIT "# For liburing and io_uring_setup() diff --git a/debian/mariadb-server.install b/debian/mariadb-server.install index 750ffd98a08..c0a38b59f27 100644 --- a/debian/mariadb-server.install +++ b/debian/mariadb-server.install @@ -16,6 +16,7 @@ lib/systemd/system/mariadb@.socket lib/systemd/system/mysql.service lib/systemd/system/mysqld.service support-files/rpm/enable_encryption.preset etc/mysql/mariadb.conf.d/99-enable-encryption.cnf.preset +usr/lib/tmpfiles.d/mariadb.conf usr/bin/aria_chk usr/bin/aria_dump_log usr/bin/aria_ftdump diff --git a/debian/not-installed b/debian/not-installed index edc3765f62b..bc7da72a2d1 100644 --- a/debian/not-installed +++ b/debian/not-installed @@ -24,7 +24,6 @@ usr/bin/uca-dump usr/bin/wsrep_sst_backup usr/lib/mysql/plugin/type_test.so usr/lib/sysusers.d/mariadb.conf # Not used (yet) in Debian systemd -usr/lib/tmpfiles.d/mariadb.conf # Not used (yet) in Debian systemd usr/sbin/rcmysql usr/share/doc/mariadb-server/COPYING (related file: "debian/tmp/usr/share/mysql/mroonga/COPYING") usr/share/doc/mariadb-server/CREDITS diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 027e8e6a786..3a33d1b8a4c 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -210,11 +210,15 @@ IF(UNIX AND NOT WITHOUT_SERVER) RENAME mariadb.conf COMPONENT Server) ENDIF() - IF((HAVE_SYSTEMD OR INSTALL_SYSTEMD_TMPUSERS) AND INSTALL_SYSTEMD_TMPFILESDIR - AND INSTALL_RUNDATADIR) + IF((HAVE_SYSTEMD OR INSTALL_SYSTEMD_TMPUSERS) AND INSTALL_SYSTEMD_TMPFILESDIR) IF(MYSQL_DATADIR STREQUAL INSTALL_RUNDATADIR) - SET(DISABLE_TMP "#") + SET(DISABLE_RUNDATADIR "#") ENDIF() + get_filename_component(MYSQL_UNIX_ADDRDIR ${MYSQL_UNIX_ADDR} DIRECTORY) + IF(MYSQL_UNIX_ADDRDIR STREQUAL MYSQL_DATADIR OR MYSQL_UNIX_ADDRDIR STREQUAL INSTALL_RUNDATADIR) + SET(DISABLE_MYSQL_UNIX_ADDRDIR "#") + ENDIF() + CONFIGURE_FILE(tmpfiles.conf.in ${CMAKE_CURRENT_BINARY_DIR}/tmpfiles.conf @ONLY) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/tmpfiles.conf diff --git a/support-files/mariadb.service.in b/support-files/mariadb.service.in index fff9ba762bb..16c905cdd62 100644 --- a/support-files/mariadb.service.in +++ b/support-files/mariadb.service.in @@ -62,17 +62,12 @@ ProtectSystem=full # Prevent accessing /home, /root and /run/user ProtectHome=true -# Execute pre and post scripts as root, otherwise it does it as User= -PermissionsStartOnly=true - # Use an environment file to pass variable _WSREP_NEW_CLUSTER EnvironmentFile=-@INSTALL_RUNDATADIR@/wsrep-new-cluster # Use an environment file to pass variable _WSREP_START_POSITION EnvironmentFile=-@INSTALL_RUNDATADIR@/wsrep-start-position -@SYSTEMD_EXECSTARTPRE@ - # Perform automatic wsrep recovery. When server is started without wsrep, # galera_recovery simply returns an empty string. In any case, however, # the script is not expected to return with a non-zero status. @@ -84,7 +79,7 @@ ExecStartPre=/bin/sh -c "[ ! -e @bindir@/galera_recovery ] && VAR= || \ && echo _WSREP_START_POSITION=$VAR > @INSTALL_RUNDATADIR@/wsrep-start-position || exit 1" # Needed to create system tables etc. -# ExecStartPre=@scriptdir@/mariadb-install-db -u mysql +# ExecStartPre=@scriptdir@/mariadb-install-db # Start main service # MYSQLD_OPTS here is for users to set in /etc/systemd/system/mariadb.service.d/MY_SPECIAL.conf diff --git a/support-files/tmpfiles.conf.in b/support-files/tmpfiles.conf.in index e67756f128a..6a2a28b59a3 100644 --- a/support-files/tmpfiles.conf.in +++ b/support-files/tmpfiles.conf.in @@ -12,4 +12,5 @@ # etc. # It shouldn't be used for datadir which is why it # may be disabled. -@DISABLE_TMP@d @INSTALL_RUNDATADIR@ 0755 @MYSQLD_USER@ @MYSQLD_USER@ - +@DISABLE_RUNDATADIR@d @INSTALL_RUNDATADIR@ 0755 @MYSQLD_USER@ @MYSQLD_USER@ - +@DISABLE_MYSQL_UNIX_ADDRDIR@d @MYSQL_UNIX_ADDRDIR@ 0755 @MYSQLD_USER@ root - From 7888b6c0d55db9ec8351c5dcce025453f49125e3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 25 Oct 2025 13:26:11 +0200 Subject: [PATCH 33/54] make max_session_mem_used tests more reliable they're very fragile by nature, but let's at least move them into one file with msan/embedded/ps/32-bit all disabled to have the memory usage more predictable. And remove these restrictions from other test files. --- mysql-test/main/alter_table_lock.result | 17 ---- mysql-test/main/alter_table_lock.test | 27 ------ mysql-test/main/error_simulation.result | 9 -- mysql-test/main/error_simulation.test | 13 --- mysql-test/main/errors.result | 20 ----- mysql-test/main/errors.test | 71 ++++------------ mysql-test/main/max_session_mem_used.result | 48 +++++++++++ mysql-test/main/max_session_mem_used.test | 85 +++++++++++++++++++ mysql-test/suite/galera/disabled.def | 1 + mysql-test/suite/maria/repair.result | 10 --- mysql-test/suite/maria/repair.test | 19 ----- .../perfschema/t/misc_session_status.test | 4 + 12 files changed, 153 insertions(+), 171 deletions(-) delete mode 100644 mysql-test/main/alter_table_lock.result delete mode 100644 mysql-test/main/alter_table_lock.test create mode 100644 mysql-test/main/max_session_mem_used.result create mode 100644 mysql-test/main/max_session_mem_used.test diff --git a/mysql-test/main/alter_table_lock.result b/mysql-test/main/alter_table_lock.result deleted file mode 100644 index 620fca23315..00000000000 --- a/mysql-test/main/alter_table_lock.result +++ /dev/null @@ -1,17 +0,0 @@ -# -# MDEV-23836: Assertion `! is_set() || m_can_overwrite_status' in -# Diagnostics_area::set_error_status (interrupted ALTER TABLE under LOCK) -# -SET @max_session_mem_used_save= @@max_session_mem_used; -CREATE TABLE t1 (a INT); -SELECT * FROM t1; -a -ALTER TABLE x MODIFY xx INT; -ERROR 42S02: Table 'test.x' doesn't exist -SET SESSION max_session_mem_used= 8192; -LOCK TABLE t1 WRITE; -ALTER TABLE t1 CHANGE COLUMN IF EXISTS b c INT; -SET SESSION max_session_mem_used = @max_session_mem_used_save; -UNLOCK TABLES; -DROP TABLE t1; -# End of 10.5 tests diff --git a/mysql-test/main/alter_table_lock.test b/mysql-test/main/alter_table_lock.test deleted file mode 100644 index 500cc3ced57..00000000000 --- a/mysql-test/main/alter_table_lock.test +++ /dev/null @@ -1,27 +0,0 @@ ---echo # ---echo # MDEV-23836: Assertion `! is_set() || m_can_overwrite_status' in ---echo # Diagnostics_area::set_error_status (interrupted ALTER TABLE under LOCK) ---echo # - -SET @max_session_mem_used_save= @@max_session_mem_used; - -CREATE TABLE t1 (a INT); -SELECT * FROM t1; - ---error ER_NO_SUCH_TABLE -ALTER TABLE x MODIFY xx INT; - -SET SESSION max_session_mem_used= 8192; ---error 0,ER_OPTION_PREVENTS_STATEMENT -LOCK TABLE t1 WRITE; - ---disable_warnings ---error 0,ER_OPTION_PREVENTS_STATEMENT -ALTER TABLE t1 CHANGE COLUMN IF EXISTS b c INT; ---enable_warnings - -SET SESSION max_session_mem_used = @max_session_mem_used_save; -UNLOCK TABLES; -DROP TABLE t1; - ---echo # End of 10.5 tests diff --git a/mysql-test/main/error_simulation.result b/mysql-test/main/error_simulation.result index c128ad88fa0..244f572413f 100644 --- a/mysql-test/main/error_simulation.result +++ b/mysql-test/main/error_simulation.result @@ -125,13 +125,4 @@ SELECT f1(1); Got one of the listed errors DROP FUNCTION f1; SET debug_dbug= @saved_dbug; -# -# MDEV-27978 wrong option name in error when exceeding max_session_mem_used -# -SET SESSION max_session_mem_used = 8192; -SELECT * FROM information_schema.processlist; -ERROR HY000: The MariaDB server is running with the --max-session-mem-used=8192 option so it cannot execute this statement -SET SESSION max_session_mem_used = DEFAULT; -# # End of 10.2 tests -# diff --git a/mysql-test/main/error_simulation.test b/mysql-test/main/error_simulation.test index fc5d9c537c7..3beeefce39f 100644 --- a/mysql-test/main/error_simulation.test +++ b/mysql-test/main/error_simulation.test @@ -144,8 +144,6 @@ SELECT a FROM t1 ORDER BY rand(1); --echo #cleanup DROP TABLE t1, pid_table; - - --echo # --echo # MDEV-12416 OOM in create_virtual_tmp_table() makes the server crash --echo # @@ -158,15 +156,4 @@ SELECT f1(1); DROP FUNCTION f1; SET debug_dbug= @saved_dbug; ---echo # ---echo # MDEV-27978 wrong option name in error when exceeding max_session_mem_used ---echo # -SET SESSION max_session_mem_used = 8192; ---error ER_OPTION_PREVENTS_STATEMENT -SELECT * FROM information_schema.processlist; -SET SESSION max_session_mem_used = DEFAULT; - - ---echo # --echo # End of 10.2 tests ---echo # diff --git a/mysql-test/main/errors.result b/mysql-test/main/errors.result index fd62df10c4a..1cb3dad405a 100644 --- a/mysql-test/main/errors.result +++ b/mysql-test/main/errors.result @@ -1,4 +1,3 @@ -drop table if exists t1; insert into t1 values(1); ERROR 42S02: Table 'test.t1' doesn't exist delete from t1; @@ -170,12 +169,6 @@ UPDATE t1 SET a = 'new' WHERE COLUMN_CREATE( 1, 'v', 1, 'w' ) IS NULL; ERROR 22007: Illegal value used as argument of dynamic column function drop table t1; -set @max_session_mem_used_save= @@max_session_mem_used; -set max_session_mem_used = 50000; -select * from seq_1_to_1000; -set max_session_mem_used = 8192; -select * from seq_1_to_1000; -set max_session_mem_used = @max_session_mem_used_save; # # MDEV-20604: Duplicate key value is silently truncated to 64 # characters in print_keydup_error @@ -231,16 +224,3 @@ Error 1327 Undeclared variable: foo Error 1305 PROCEDURE P1 does not exist drop procedure P1; # End of 10.4 tests -# -# MDEV-35828: Assertion fails in alloc_root() when memory causes it to call itself -# -CREATE TEMPORARY TABLE t1 (a INT,b INT); -INSERT INTO t1 VALUES (1,1),(2,2); -SET -@tmp=@@max_session_mem_used, -max_session_mem_used=8192; -SELECT * FROM (t1 AS t2 LEFT JOIN t1 AS t3 USING (a)),t1; -ERROR HY000: The MariaDB server is running with the --max-session-mem-used=8192 option so it cannot execute this statement -DROP TABLE t1; -SET max_session_mem_used=@tmp; -# End of 10.6 tests diff --git a/mysql-test/main/errors.test b/mysql-test/main/errors.test index 87d6d2fdec9..e748b3bef2d 100644 --- a/mysql-test/main/errors.test +++ b/mysql-test/main/errors.test @@ -3,31 +3,28 @@ # --source include/have_sequence.inc ---disable_warnings -drop table if exists t1; ---enable_warnings ---error 1146 +--error ER_NO_SUCH_TABLE insert into t1 values(1); ---error 1146 +--error ER_NO_SUCH_TABLE delete from t1; ---error 1146 +--error ER_NO_SUCH_TABLE update t1 set a=1; create table t1 (a int); ---error 1054 +--error ER_BAD_FIELD_ERROR select count(test.t1.b) from t1; ---error 1054 +--error ER_BAD_FIELD_ERROR select count(not_existing_database.t1) from t1; ---error 1054 +--error ER_BAD_FIELD_ERROR select count(not_existing_database.t1.a) from t1; ---error 1044,1146 +--error ER_DBACCESS_DENIED_ERROR,ER_NO_SUCH_TABLE select count(not_existing_database.t1.a) from not_existing_database.t1; ---error 1054 +--error ER_BAD_FIELD_ERROR select 1 from t1 order by 2; ---error 1054 +--error ER_BAD_FIELD_ERROR select 1 from t1 group by 2; ---error 1054 +--error ER_BAD_FIELD_ERROR select 1 from t1 order by t1.b; ---error 1054 +--error ER_BAD_FIELD_ERROR select count(*),b from t1; drop table t1; @@ -36,10 +33,10 @@ drop table t1; # # Bug #6080: Error message for a field with a display width that is too long # ---error 1439 +--error ER_TOO_BIG_DISPLAYWIDTH create table t1 (a int(256)); set sql_mode='traditional'; ---error 1074 +--error ER_TOO_BIG_FIELDLENGTH create table t1 (a varchar(66000)); set sql_mode=default; @@ -95,7 +92,7 @@ delimiter ;| flush status; --disable_ps2_protocol ---error 1062 +--error ER_DUP_ENTRY select f1(), f2(); --enable_ps2_protocol show status like 'Com_insert'; @@ -202,24 +199,6 @@ UPDATE t1 SET a = 'new' WHERE COLUMN_CREATE( 1, 'v', 1, 'w' ) IS NULL; drop table t1; -# -# errors caused by max_session_mem_used -# -set @max_session_mem_used_save= @@max_session_mem_used; - ---disable_result_log -set max_session_mem_used = 50000; ---error 0,ER_OPTION_PREVENTS_STATEMENT -select * from seq_1_to_1000; -set max_session_mem_used = 8192; ---error 0,ER_OPTION_PREVENTS_STATEMENT -select * from seq_1_to_1000; ---enable_result_log -# We may not be able to execute any more queries with this connection -# because of too little memory# - -set max_session_mem_used = @max_session_mem_used_save; - --echo # --echo # MDEV-20604: Duplicate key value is silently truncated to 64 --echo # characters in print_keydup_error @@ -283,24 +262,4 @@ show warnings; drop procedure P1; --- echo # End of 10.4 tests - - ---echo # ---echo # MDEV-35828: Assertion fails in alloc_root() when memory causes it to call itself ---echo # -CREATE TEMPORARY TABLE t1 (a INT,b INT); -INSERT INTO t1 VALUES (1,1),(2,2); - -SET - @tmp=@@max_session_mem_used, - max_session_mem_used=8192; - ---error ER_OPTION_PREVENTS_STATEMENT -SELECT * FROM (t1 AS t2 LEFT JOIN t1 AS t3 USING (a)),t1; - -DROP TABLE t1; -SET max_session_mem_used=@tmp; - - ---echo # End of 10.6 tests +--echo # End of 10.4 tests diff --git a/mysql-test/main/max_session_mem_used.result b/mysql-test/main/max_session_mem_used.result new file mode 100644 index 00000000000..d2ce765999b --- /dev/null +++ b/mysql-test/main/max_session_mem_used.result @@ -0,0 +1,48 @@ +# +# MDEV-23836: Assertion `! is_set() || m_can_overwrite_status' in +# Diagnostics_area::set_error_status (interrupted ALTER TABLE under LOCK) +# +CREATE TABLE t1 (a INT); +SELECT * FROM t1; +a +ALTER TABLE x MODIFY xx INT; +ERROR 42S02: Table 'test.x' doesn't exist +SET SESSION max_session_mem_used= 8192; +LOCK TABLE t1 WRITE; +ALTER TABLE t1 CHANGE COLUMN IF EXISTS b c INT; +SET SESSION max_session_mem_used = DEFAULT; +UNLOCK TABLES; +DROP TABLE t1; +# +# MDEV-27978 wrong option name in error when exceeding max_session_mem_used +# +SET SESSION max_session_mem_used = 8192; +SELECT * FROM information_schema.processlist; +ERROR HY000: The MariaDB server is running with the --max-session-mem-used=8192 option so it cannot execute this statement +SET SESSION max_session_mem_used = DEFAULT; +set max_session_mem_used = 50000; +select * from seq_1_to_1000; +set max_session_mem_used = 8192; +select * from seq_1_to_1000; +set max_session_mem_used = DEFAULT; +# +# MDEV-35828: Assertion fails in alloc_root() when memory causes it to call itself +# +CREATE TEMPORARY TABLE t1 (a INT,b INT); +INSERT INTO t1 VALUES (1,1),(2,2); +SET max_session_mem_used=8192; +SELECT * FROM (t1 AS t2 LEFT JOIN t1 AS t3 USING (a)),t1; +ERROR HY000: The MariaDB server is running with the --max-session-mem-used=8192 option so it cannot execute this statement +SET max_session_mem_used=DEFAULT; +DROP TABLE t1; +# +# MDEV-23824 SIGSEGV in end_io_cache on REPAIR LOCAL TABLE for Aria table +# +CREATE TABLE t1 (i INT) ENGINE=Aria; +INSERT INTO t1 VALUES (1); +SET max_session_mem_used=50000; +REPAIR LOCAL TABLE t1 USE_FRM; +REPAIR LOCAL TABLE t1; +DROP TABLE t1; +SET max_session_mem_used=default; +# End of 10.6 tests diff --git a/mysql-test/main/max_session_mem_used.test b/mysql-test/main/max_session_mem_used.test new file mode 100644 index 00000000000..353fdf11916 --- /dev/null +++ b/mysql-test/main/max_session_mem_used.test @@ -0,0 +1,85 @@ +# memory usage is sensitive to valgrind/ps-protocol/embedded +source include/not_msan.inc; +source include/not_valgrind.inc; +source include/no_protocol.inc; +source include/not_embedded.inc; +source include/have_64bit.inc; +source include/have_sequence.inc; + +--echo # +--echo # MDEV-23836: Assertion `! is_set() || m_can_overwrite_status' in +--echo # Diagnostics_area::set_error_status (interrupted ALTER TABLE under LOCK) +--echo # + +CREATE TABLE t1 (a INT); +SELECT * FROM t1; + +--error ER_NO_SUCH_TABLE +ALTER TABLE x MODIFY xx INT; + +SET SESSION max_session_mem_used= 8192; +--error 0,ER_OPTION_PREVENTS_STATEMENT +LOCK TABLE t1 WRITE; + +--disable_warnings +--error 0,ER_OPTION_PREVENTS_STATEMENT +ALTER TABLE t1 CHANGE COLUMN IF EXISTS b c INT; +--enable_warnings + +SET SESSION max_session_mem_used = DEFAULT; +UNLOCK TABLES; +DROP TABLE t1; + +--echo # +--echo # MDEV-27978 wrong option name in error when exceeding max_session_mem_used +--echo # +SET SESSION max_session_mem_used = 8192; +--error ER_OPTION_PREVENTS_STATEMENT +SELECT * FROM information_schema.processlist; +SET SESSION max_session_mem_used = DEFAULT; + +# +# errors caused by max_session_mem_used +# +--disable_result_log +set max_session_mem_used = 50000; +--error 0,ER_OPTION_PREVENTS_STATEMENT +select * from seq_1_to_1000; +set max_session_mem_used = 8192; +--error 0,ER_OPTION_PREVENTS_STATEMENT +select * from seq_1_to_1000; +--enable_result_log +# We may not be able to execute any more queries with this connection +# because of too little memory + +set max_session_mem_used = DEFAULT; + +--echo # +--echo # MDEV-35828: Assertion fails in alloc_root() when memory causes it to call itself +--echo # +CREATE TEMPORARY TABLE t1 (a INT,b INT); +INSERT INTO t1 VALUES (1,1),(2,2); + +SET max_session_mem_used=8192; + +--error ER_OPTION_PREVENTS_STATEMENT +SELECT * FROM (t1 AS t2 LEFT JOIN t1 AS t3 USING (a)),t1; + +SET max_session_mem_used=DEFAULT; +DROP TABLE t1; + +--echo # +--echo # MDEV-23824 SIGSEGV in end_io_cache on REPAIR LOCAL TABLE for Aria table +--echo # + +CREATE TABLE t1 (i INT) ENGINE=Aria; +INSERT INTO t1 VALUES (1); +SET max_session_mem_used=50000; +--disable_result_log +REPAIR LOCAL TABLE t1 USE_FRM; +REPAIR LOCAL TABLE t1; +--enable_result_log +DROP TABLE t1; +SET max_session_mem_used=default; + +--echo # End of 10.6 tests diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 438b1e63cfd..865696a95af 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -16,3 +16,4 @@ MW-329 : MDEV-35951 Complete freeze during MW-329 test galera_vote_rejoin_dml : MDEV-35964 Assertion `ist_seqno >= cc_seqno' failed in galera_vote_rejoin_dml galera_var_notify_cmd : MDEV-37257 WSREP: Notification command failed: 1 (Operation not permitted) galera_var_notify_ssl_ipv6 : MDEV-37257 WSREP: Notification command failed: 1 (Operation not permitted) +MDEV-26266 : cannot work reliably diff --git a/mysql-test/suite/maria/repair.result b/mysql-test/suite/maria/repair.result index 7905cb02f28..c2935b64e7d 100644 --- a/mysql-test/suite/maria/repair.result +++ b/mysql-test/suite/maria/repair.result @@ -22,16 +22,6 @@ i 1 UNLOCK TABLES; DROP TABLE t1; -# -# MDEV-23824 SIGSEGV in end_io_cache on REPAIR LOCAL TABLE for Aria table -# -CREATE TABLE t1 (i INT) ENGINE=Aria; -INSERT INTO t1 VALUES (1); -SET max_session_mem_used=50000; -REPAIR LOCAL TABLE t1 USE_FRM; -REPAIR LOCAL TABLE t1; -DROP TABLE t1; -SET max_session_mem_used=default; # MDEV-17223 Assertion `thd->killed != 0' failed in # ha_maria::enable_indexes diff --git a/mysql-test/suite/maria/repair.test b/mysql-test/suite/maria/repair.test index 08234a5a546..5e12a07df06 100644 --- a/mysql-test/suite/maria/repair.test +++ b/mysql-test/suite/maria/repair.test @@ -1,8 +1,3 @@ -# We should not run this test with embedded as we are using -# max_session_mem_used, which causes things to fail/not fail randomly -# as memory usage is different compared to normal server. - ---source include/not_embedded.inc --source include/have_sequence.inc # @@ -30,20 +25,6 @@ SELECT * FROM t1; UNLOCK TABLES; DROP TABLE t1; ---echo # ---echo # MDEV-23824 SIGSEGV in end_io_cache on REPAIR LOCAL TABLE for Aria table ---echo # - -CREATE TABLE t1 (i INT) ENGINE=Aria; -INSERT INTO t1 VALUES (1); -SET max_session_mem_used=50000; ---disable_result_log -REPAIR LOCAL TABLE t1 USE_FRM; -REPAIR LOCAL TABLE t1; ---enable_result_log -DROP TABLE t1; -SET max_session_mem_used=default; - --echo --echo # MDEV-17223 Assertion `thd->killed != 0' failed in --echo # ha_maria::enable_indexes diff --git a/mysql-test/suite/perfschema/t/misc_session_status.test b/mysql-test/suite/perfschema/t/misc_session_status.test index afb08eb4e9d..f32896d6077 100644 --- a/mysql-test/suite/perfschema/t/misc_session_status.test +++ b/mysql-test/suite/perfschema/t/misc_session_status.test @@ -1,5 +1,7 @@ --source include/not_embedded.inc --source include/have_perfschema.inc +--source include/not_msan.inc +--source include/not_valgrind.inc # This does not crash on 32 bit because of less memory used --source include/have_64bit.inc --echo # @@ -16,7 +18,9 @@ set max_session_mem_used=32768; select * from performance_schema.session_status; --enable_result_log # this used to cause mutex lock order violation when OOM happened under LOCK_global_system_variables +--disable_ps_protocol # different memory requirements set global innodb_io_capacity_max=100; set max_session_mem_used=default; +--enable_ps_protocol set global innodb_io_capacity=@old_innodb_io_capacity; set global innodb_io_capacity_max=@old_innodb_io_capacity_max; From e5994025bec0d34ddef25df2e252b8f1d2e34e51 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 24 Oct 2025 12:05:30 +0200 Subject: [PATCH 34/54] MDEV-37938 very long query cannot be killed quickly check for thd->killed in the lexer --- sql/sql_lex.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3741184d8cb..e595b4d7e08 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2028,6 +2028,12 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd) const uchar *const state_map= cs->state_map; const uchar *const ident_map= cs->ident_map; + if (thd->killed) + { + thd->send_kill_message(); + return END_OF_INPUT; + } + start_token(); state= next_state; next_state= MY_LEX_OPERATOR_OR_IDENT; From ebe27ec6eb5e4aae9119d3ebd6050138f09703a3 Mon Sep 17 00:00:00 2001 From: Oleg Smirnov Date: Fri, 26 Sep 2025 22:55:54 +0300 Subject: [PATCH 35/54] MDEV-36761: Implement NULL-aware cardinality estimation for indexed columns When all values in an indexed column are NULL, EITS statistics show avg_frequency == 0. This commit adds logic to distinguish between "no statistics available" and "all values are NULL" scenarios. For NULL-rejecting conditions (e.g., t1.col = t2.col), when statistics confirm all indexed values are NULL, the optimizer can now return a very low cardinality estimate (1.0) instead of unknown (0.0), since NULL = NULL never matches. For non-NULL-rejecting conditions (e.g., t1.col <=> t2.col), normal cardinality estimation continues to apply since matches are possible. Changes: - Added KEY::rec_per_key_null_aware() to check nulls_ratio from column statistics when avg_frequency is 0 - Modified best_access_path() in sql_select.cc to use the new rec_per_key_null_aware() method for ref access cost estimation - The optimization works with single-column and composite indexes, checking each key part's NULL-rejecting status via notnull_part bitmap --- mysql-test/main/null-aware-cardinality.result | 150 ++++++++++++++++++ mysql-test/main/null-aware-cardinality.test | 95 +++++++++++ sql/sql_select.cc | 28 +++- sql/structs.h | 4 +- sql/table.cc | 100 +++++++++++- 5 files changed, 368 insertions(+), 9 deletions(-) create mode 100644 mysql-test/main/null-aware-cardinality.result create mode 100644 mysql-test/main/null-aware-cardinality.test diff --git a/mysql-test/main/null-aware-cardinality.result b/mysql-test/main/null-aware-cardinality.result new file mode 100644 index 00000000000..5c5aae9dfb7 --- /dev/null +++ b/mysql-test/main/null-aware-cardinality.result @@ -0,0 +1,150 @@ +# Small driving table +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1, 1), (2, 2000),(3,300); +ANALYZE TABLE t1 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +# Table that will be accessed by an index lookup (`ref` access) +CREATE TABLE t2 (a INT, b INT, KEY key_b(b)); +# All t11.b values are NULL +INSERT INTO t2 SELECT seq/100, NULL FROM seq_1_to_1000; +ANALYZE TABLE t2 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status Table is already up to date +# NULL-rejecting equality t1.b = t2.b will not return any matches +# because all values of t2.b are NULL. So "rows" = 1 for t2 where 1 is +# a special value meaning "very few" rows +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b = t2.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t2 ref key_b key_b 5 test.t1.b 1 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` and `test`.`t2`.`b` = `test`.`t1`.`b` +# However, rows estimation for not NULL-rejecting conditions +# must not be affected ("rows" > 1 is expected) +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b <=> t2.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ref key_b key_b 5 test.t1.b 11 100.00 Using index condition; Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` and `test`.`t1`.`b` <=> `test`.`t2`.`b` +ANALYZE SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b <=> t2.b; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00 +1 SIMPLE t2 ref key_b key_b 5 test.t1.b 11 0.00 100.00 100.00 Using index condition; Using where +# Insert some non-NULL values and re-collect the stats +INSERT INTO t2 SELECT 1, 1 FROM seq_1_to_100; +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS (b) INDEXES (key_b); +Table Op Msg_type Msg_text +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b = t2.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t2 ref key_b key_b 5 test.t1.b 100 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` and `test`.`t2`.`b` = `test`.`t1`.`b` +# Test composite index for two columns. Key prefix is used for access +CREATE TABLE t3 (a INT, b INT, KEY key_ab(a,b)); +# All t3.b values are NULL +INSERT INTO t3 SELECT seq/100, NULL FROM seq_1_to_1000; +ANALYZE TABLE t3 PERSISTENT FOR COLUMNS(b) INDEXES(key_ab); +Table Op Msg_type Msg_text +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status Table is already up to date +# NULL-rejecting equality t1.b = t3.b, same as above. +# "rows" must be estimated to 1 +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t1.b = t3.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ref key_ab key_ab 10 test.t1.a,test.t1.b 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t3` where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t3`.`b` = `test`.`t1`.`b` +# Rows estimation for not NULL-rejecting conditions are not affected +# ("rows" > 1 is expected) +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ref key_ab key_ab 5 test.t1.a 90 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t3` where `test`.`t3`.`a` = `test`.`t1`.`a` +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t1.b <=> t3.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ref key_ab key_ab 10 test.t1.a,test.t1.b 11 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t3` where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t1`.`b` <=> `test`.`t3`.`b` +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t3.b is NULL; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ref key_ab key_ab 10 test.t1.a,const 11 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t3` where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t3`.`b` is null +# Insert some non-NULL values and re-collect the stats +INSERT INTO t3 SELECT 1, 1 FROM seq_1_to_100; +ANALYZE TABLE t3 PERSISTENT FOR COLUMNS (b) INDEXES (key_ab); +Table Op Msg_type Msg_text +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status OK +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t1.b = t3.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ref key_ab key_ab 10 test.t1.a,test.t1.b 100 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t3` where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t3`.`b` = `test`.`t1`.`b` +# Test composite index for 3 columns. Key prefix is used for access +CREATE TABLE t4 (a INT, b INT, c INT, KEY key_abc(a,b,c)); +# All t3.b values are NULL +INSERT INTO t4 SELECT seq/10, NULL, seq/10 FROM seq_1_to_1000; +ANALYZE TABLE t4 PERSISTENT FOR COLUMNS(b) INDEXES(key_abc); +Table Op Msg_type Msg_text +test.t4 analyze status Engine-independent statistics collected +test.t4 analyze status Table is already up to date +# NULL-rejecting equality t1.b = t3.b, same as above. +# "rows" must be estimated to 1 +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t4 ON t1.a = t4.a AND t1.b = t4.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t4 ref key_abc key_abc 10 test.t1.a,test.t1.b 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t4`.`c` AS `c` from `test`.`t1` join `test`.`t4` where `test`.`t4`.`a` = `test`.`t1`.`a` and `test`.`t4`.`b` = `test`.`t1`.`b` +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t4 ON t1.a = t4.a AND t1.b = t4.b and t1.b = t4.c; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t4 ref key_abc key_abc 15 test.t1.a,test.t1.b,test.t1.b 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t4`.`c` AS `c` from `test`.`t1` join `test`.`t4` where `test`.`t4`.`a` = `test`.`t1`.`a` and `test`.`t4`.`b` = `test`.`t1`.`b` and `test`.`t4`.`c` = `test`.`t1`.`b` +# "rows" expected to be > 1 +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t4 ON t1.a = t4.a; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t4 ref key_abc key_abc 5 test.t1.a 9 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t4`.`c` AS `c` from `test`.`t1` join `test`.`t4` where `test`.`t4`.`a` = `test`.`t1`.`a` +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t4 ON t1.a = t4.a AND t1.b <=> t4.c; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t4 ref key_abc key_abc 5 test.t1.a 9 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t4`.`c` AS `c` from `test`.`t1` join `test`.`t4` where `test`.`t4`.`a` = `test`.`t1`.`a` and `test`.`t1`.`b` <=> `test`.`t4`.`c` +DROP TABLE t1, t2, t3, t4; +# Test for partially covered column +CREATE TABLE t1 (a VARCHAR(10)); +INSERT INTO t1 SELECT seq FROM seq_1_to_10; +CREATE TABLE t2 ( +a VARCHAR(10), +b VARCHAR(10), +INDEX i1(a, b(5)) +); +INSERT INTO t2 SELECT seq, NULL FROM seq_1_to_1000; +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS (b) INDEXES (i1); +Table Op Msg_type Msg_text +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status Table is already up to date +EXPLAIN SELECT * FROM t1, t2 WHERE t2.a=t1.a AND t2.b=t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using where +1 SIMPLE t2 ref i1 i1 21 test.t1.a,test.t1.a 1 Using where +DROP TABLE t1, t2; diff --git a/mysql-test/main/null-aware-cardinality.test b/mysql-test/main/null-aware-cardinality.test new file mode 100644 index 00000000000..418f0f3d9af --- /dev/null +++ b/mysql-test/main/null-aware-cardinality.test @@ -0,0 +1,95 @@ +--source include/have_sequence.inc + +--echo # Small driving table +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1, 1), (2, 2000),(3,300); + +ANALYZE TABLE t1 PERSISTENT FOR ALL; + +--echo # Table that will be accessed by an index lookup (`ref` access) +CREATE TABLE t2 (a INT, b INT, KEY key_b(b)); +--echo # All t11.b values are NULL +INSERT INTO t2 SELECT seq/100, NULL FROM seq_1_to_1000; + +ANALYZE TABLE t2 PERSISTENT FOR ALL; + +--echo # NULL-rejecting equality t1.b = t2.b will not return any matches +--echo # because all values of t2.b are NULL. So "rows" = 1 for t2 where 1 is +--echo # a special value meaning "very few" rows +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b = t2.b; + +--echo # However, rows estimation for not NULL-rejecting conditions +--echo # must not be affected ("rows" > 1 is expected) +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b <=> t2.b; + +ANALYZE SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b <=> t2.b; + +--echo # Insert some non-NULL values and re-collect the stats +INSERT INTO t2 SELECT 1, 1 FROM seq_1_to_100; + +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS (b) INDEXES (key_b); + +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b = t2.b; + +--echo # Test composite index for two columns. Key prefix is used for access +CREATE TABLE t3 (a INT, b INT, KEY key_ab(a,b)); +--echo # All t3.b values are NULL +INSERT INTO t3 SELECT seq/100, NULL FROM seq_1_to_1000; + +ANALYZE TABLE t3 PERSISTENT FOR COLUMNS(b) INDEXES(key_ab); + +--echo # NULL-rejecting equality t1.b = t3.b, same as above. +--echo # "rows" must be estimated to 1 +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t1.b = t3.b; + +--echo # Rows estimation for not NULL-rejecting conditions are not affected +--echo # ("rows" > 1 is expected) +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a; + +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t1.b <=> t3.b; + +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t3.b is NULL; + +--echo # Insert some non-NULL values and re-collect the stats +INSERT INTO t3 SELECT 1, 1 FROM seq_1_to_100; + +ANALYZE TABLE t3 PERSISTENT FOR COLUMNS (b) INDEXES (key_ab); + +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t1.b = t3.b; + +--echo # Test composite index for 3 columns. Key prefix is used for access +CREATE TABLE t4 (a INT, b INT, c INT, KEY key_abc(a,b,c)); + +--echo # All t3.b values are NULL +INSERT INTO t4 SELECT seq/10, NULL, seq/10 FROM seq_1_to_1000; + +ANALYZE TABLE t4 PERSISTENT FOR COLUMNS(b) INDEXES(key_abc); + +--echo # NULL-rejecting equality t1.b = t3.b, same as above. +--echo # "rows" must be estimated to 1 +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t4 ON t1.a = t4.a AND t1.b = t4.b; + +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t4 ON t1.a = t4.a AND t1.b = t4.b and t1.b = t4.c; + +--echo # "rows" expected to be > 1 +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t4 ON t1.a = t4.a; + +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t4 ON t1.a = t4.a AND t1.b <=> t4.c; + +DROP TABLE t1, t2, t3, t4; + +--echo # Test for partially covered column +CREATE TABLE t1 (a VARCHAR(10)); +INSERT INTO t1 SELECT seq FROM seq_1_to_10; + +CREATE TABLE t2 ( + a VARCHAR(10), + b VARCHAR(10), + INDEX i1(a, b(5)) +); +INSERT INTO t2 SELECT seq, NULL FROM seq_1_to_1000; +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS (b) INDEXES (i1); + +EXPLAIN SELECT * FROM t1, t2 WHERE t2.a=t1.a AND t2.b=t1.a; + +DROP TABLE t1, t2; \ No newline at end of file diff --git a/sql/sql_select.cc b/sql/sql_select.cc index abf429a426b..7579ffc83cf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8696,7 +8696,26 @@ best_access_path(JOIN *join, ulong key_flags; uint key_parts; key_part_map found_part= 0; - /* key parts which won't have NULL in lookup tuple */ + + /* + Bitmap indicating which key parts are used with NULL-rejecting + conditions. + + A bit is set to 1 for a key part if it's used with a + NULL-rejecting condition (i.e., the condition will never be + satisfied when the indexed column contains NULL). A bit is 0 if + the key part is used with a non-NULL-rejecting condition (i.e., + the condition can be satisfied even when the indexed column + contains NULL, e.g., is NULL or <=>). + + Example: for condition + t1.keypart1 = t2.col1 AND t1.keypart2 <=> t2.col2 AND + t1.keypart3 = t2.col3 + the notnull_part bitmap will be 101 (binary), because: + - keypart1: '=' is NULL-rejecting (bit 1) + - keypart2: '<=>' is NOT NULL-rejecting (bit 0) + - keypart3: '=' is NULL-rejecting (bit 1) + */ key_part_map notnull_part=0; table_map found_ref= 0; uint key= keyuse->key; @@ -8951,7 +8970,8 @@ best_access_path(JOIN *join, } else { - if (!(records= keyinfo->actual_rec_per_key(key_parts-1))) + if (!(records= + keyinfo->rec_per_key_null_aware(key_parts-1, notnull_part))) { /* Prefer longer keys */ trace_access_idx.add("rec_per_key_stats_missing", true); records= @@ -9083,7 +9103,9 @@ best_access_path(JOIN *join, else { /* Check if we have statistic about the distribution */ - if ((records= keyinfo->actual_rec_per_key(max_key_part-1))) + if ((records= + keyinfo->rec_per_key_null_aware(max_key_part-1, + notnull_part))) { /* Fix for the case where the index statistics is too diff --git a/sql/structs.h b/sql/structs.h index eb9d9a04394..2c35aba7d41 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -171,7 +171,9 @@ typedef struct st_key { engine_option_value *option_list; ha_index_option_struct *option_struct; /* structure with parsed options */ - double actual_rec_per_key(uint i) const; + double actual_rec_per_key(uint last_key_part_in_prefix) const; + double rec_per_key_null_aware(uint last_key_part_in_prefix, + key_part_map notnull_part) const; } KEY; diff --git a/sql/table.cc b/sql/table.cc index 937ed518187..4f554bf23da 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -10297,17 +10297,107 @@ uint TABLE_SHARE::actual_n_key_parts(THD *thd) } -double KEY::actual_rec_per_key(uint i) const +/** + Get records-per-key estimate for an index prefix. + + Returns average number of records per key value for the given index prefix. + Prefers engine-independent statistics (EITS) if available and falls back + to engine-dependent statistics otherwise. + + @param max_key_part Index of the last key part in the prefix (0-based) + + @return Estimated records per key value: + - 0.0 if no statistics available + - avg_frequency from EITS if available + - rec_per_key from engine statistics if EITS is not available +*/ +double KEY::actual_rec_per_key(uint last_key_part_in_prefix) const { if (is_statistics_from_stat_tables) { // Use engine-independent statistics (EITS) - return read_stats->get_avg_frequency(i); + return read_stats->get_avg_frequency(last_key_part_in_prefix); } // Fall back to engine-dependent statistics if EITS is not available - if (rec_per_key == nullptr) - return 0; // No statistics available - return (double) rec_per_key[i]; + return rec_per_key ? (double) rec_per_key[last_key_part_in_prefix] : 0.0; +} + + +/** + Get records-per-key estimate for an index prefix with NULL-aware optimization. + + Returns average number of records per key value for the given index prefix. + When EITS statistics show avg_frequency == 0 (typically all NULL values) and + the query uses NULL-rejecting conditions (e.g., =), returns 1.0 to indicate + high selectivity since NULL = NULL never matches. + + @param max_key_part Index of the last key part in the prefix (0-based) + @param notnull_part Bitmap indicating which key parts have NULL-rejecting + conditions (bit N set means key part N uses =, not <=>) + + @return Estimated records per key value: + - 0.0 if no statistics available + - avg_frequency from EITS if available + - 1.0 if all values are NULL with NULL-rejecting condition + - rec_per_key from engine statistics if EITS is not available +*/ +double KEY::rec_per_key_null_aware(uint last_key_part_in_prefix, + key_part_map notnull_part) const +{ + if (!is_statistics_from_stat_tables) + { + // Fall back to engine-dependent statistics if EITS is not available + return rec_per_key ? (double) rec_per_key[last_key_part_in_prefix] : 0.0; + } + + // Use engine-independent statistics (EITS) + double records= read_stats->get_avg_frequency(last_key_part_in_prefix); + if (records != 0.0) + return records; + + /* + The index statistics show avg_frequency == 0 for this index prefix. + This typically means all values in the indexed columns are NULL. + + For NULL-rejecting conditions like `t1.key_col = t2.col`, we know + there will be no matches (since NULL = NULL is never true). + However, for non-NULL-rejecting conditions like `t1.key_col <=> t2.col`, + matches are possible. + + Check each key part in the prefix: if any key part has a NULL-rejecting + condition (indicated by bit set in `notnull_part`) and the statistics + confirm all values are NULL (nulls_ratio == 1.0), we can return 1.0 + (highly selective estimate) instead of 0.0 (unknown), indicating + no expected matches. + */ + for (int bit= last_key_part_in_prefix; bit >= 0; bit--) + { + key_part_map mask = (key_part_map)1 << bit; + if ((notnull_part & mask) == 0) + { + // Non-NULL-rejecting condition for the key part + continue; + } + + Field *field= table->field[key_part[bit].field->field_index]; + if (!field->read_stats) + { + // No column statistics available + continue; + } + + // Check if all values in this column are NULL according to statistics + double nulls_ratio= field->read_stats->get_nulls_ratio(); + if (nulls_ratio == 1.0) + { + /* + All values are NULL and the condition is NULL-rejecting. + Return 1.0 (highly selective), indicating no expected matches. + */ + return 1.0; + } + } + return records; } /* From 39e7133ef9e433c36ff634f6506664111e90a434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 24 Oct 2025 12:24:34 +0300 Subject: [PATCH 36/54] MDEV-37857 : Galera replication does not preserve the character set and collation associated with views, etc In Query_log_event::do_apply_event there is comparison is used character set in event same as cached charset and if not used charset is changed. Unfortunately, it was done only if thread is replica thread. Fixed by adding condition for Galera applier thread so that comparison is done leading to charset change if event had different charset. --- mysql-test/suite/galera/r/MDEV-37857.result | 44 +++++++++++++++++++++ mysql-test/suite/galera/t/MDEV-37857.test | 29 ++++++++++++++ sql/log_event_server.cc | 11 +++++- 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/galera/r/MDEV-37857.result create mode 100644 mysql-test/suite/galera/t/MDEV-37857.test diff --git a/mysql-test/suite/galera/r/MDEV-37857.result b/mysql-test/suite/galera/r/MDEV-37857.result new file mode 100644 index 00000000000..243a4b4b727 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-37857.result @@ -0,0 +1,44 @@ +connection node_2; +connection node_1; +drop table if exists t1; +drop view if exists t1; +connection node_2; +SELECT @@character_set_server, @@collation_server; +@@character_set_server @@collation_server +latin1 latin1_swedish_ci +SELECT @@character_set_client, @@collation_connection; +@@character_set_client @@collation_connection +latin1 latin1_swedish_ci +connection node_1; +SET NAMES latin1 COLLATE latin1_bin; +SELECT @@character_set_server, @@collation_server; +@@character_set_server @@collation_server +latin1 latin1_swedish_ci +SELECT @@character_set_client, @@collation_connection; +@@character_set_client @@collation_connection +latin1 latin1_bin +create table t1 (a int); +insert into t1 values (1); +create view v1 as select a from t1; +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_bin +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +connection node_2; +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_bin +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +connection node_1; +DROP VIEW v1; +DROP TABLE t1; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/t/MDEV-37857.test b/mysql-test/suite/galera/t/MDEV-37857.test new file mode 100644 index 00000000000..8a950d39bcf --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-37857.test @@ -0,0 +1,29 @@ +--source include/galera_cluster.inc + +--disable_warnings +drop table if exists t1; +drop view if exists t1; +--enable_warnings + +--connection node_2 +SELECT @@character_set_server, @@collation_server; +SELECT @@character_set_client, @@collation_connection; +--connection node_1 +SET NAMES latin1 COLLATE latin1_bin; +SELECT @@character_set_server, @@collation_server; +SELECT @@character_set_client, @@collation_connection; +create table t1 (a int); +insert into t1 values (1); +create view v1 as select a from t1; +SHOW CREATE VIEW v1; +SHOW CREATE TABLE t1; + +--connection node_2 +SHOW CREATE VIEW v1; +SHOW CREATE TABLE t1; + +--connection node_1 +DROP VIEW v1; +DROP TABLE t1; + +--source include/galera_end.inc diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index 3457224f0c4..c93aea23ad0 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -2021,7 +2021,16 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, if (charset_inited) { rpl_sql_thread_info *sql_info= thd->system_thread_info.rpl_sql_info; - if (thd->slave_thread && sql_info->cached_charset_compare(charset)) + const bool applier= +#ifdef WITH_WSREP + WSREP(thd) ? thd->wsrep_applier : +#endif + false; + + // Event charset should be compared for slave thread + // and applier threads + if ((thd->slave_thread || applier) && + sql_info->cached_charset_compare(charset)) { /* Verify that we support the charsets found in the event. */ if (!(thd->variables.character_set_client= From 25253b75ada51ef5813e4c94fbd4dc6be7a01544 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 22 Oct 2025 16:51:03 +1100 Subject: [PATCH 37/54] MDEV-37776: Debian shlibs:Depends shouldn't be explict The Debian library dependencies are auto detected and populated as part of shlibs:Depends and the explicit population is suspectable to distro packaging changes. Also fix the server gssapi plugin to the compiled server dependency consistent with other server plugins. --- debian/control | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/debian/control b/debian/control index 5aee125a4dd..ee7cef7efdf 100644 --- a/debian/control +++ b/debian/control @@ -830,8 +830,7 @@ Description: Connect storage engine for MariaDB server Package: mariadb-plugin-s3 Architecture: any -Depends: libcurl4, - mariadb-server (= ${server:Version}), +Depends: mariadb-server (= ${server:Version}), ${misc:Depends}, ${shlibs:Depends} Description: Amazon S3 archival storage engine for MariaDB @@ -860,8 +859,7 @@ Description: RocksDB storage engine for MariaDB server Package: mariadb-plugin-oqgraph Architecture: any -Depends: libjudydebian1, - mariadb-server (= ${server:Version}), +Depends: mariadb-server (= ${server:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: mariadb-oqgraph-engine-10.0, @@ -926,8 +924,7 @@ Description: Spider storage engine for MariaDB server Package: mariadb-plugin-gssapi-server Architecture: any -Depends: libgssapi-krb5-2, - mariadb-server, +Depends: mariadb-server (= ${server:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: mariadb-gssapi-server-10.1, @@ -950,8 +947,7 @@ Description: GSSAPI authentication plugin for MariaDB server Package: mariadb-plugin-gssapi-client Architecture: any -Depends: libgssapi-krb5-2, - mariadb-client (= ${binary:Version}), +Depends: mariadb-client (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: mariadb-gssapi-client-10.1, @@ -970,8 +966,7 @@ Description: GSSAPI authentication plugin for MariaDB client Package: mariadb-plugin-cracklib-password-check Architecture: any -Depends: libcrack2 (>= 2.9.0), - mariadb-server, +Depends: mariadb-server, ${misc:Depends}, ${shlibs:Depends} Description: CrackLib Password Validation Plugin for MariaDB server @@ -984,8 +979,7 @@ Description: CrackLib Password Validation Plugin for MariaDB server Package: mariadb-plugin-hashicorp-key-management Architecture: any -Depends: libcurl4, - mariadb-server, +Depends: mariadb-server, ${misc:Depends}, ${shlibs:Depends} Description: Hashicorp Key Management plugin for MariaDB From d3443c82f753e788d66573b88ae18443258bbec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 27 Oct 2025 09:21:31 +0200 Subject: [PATCH 38/54] MDEV-37056 : SIGSEGV in wsrep_check_sequence | mysql_alter_table Problem was that thd->lex->m_sql_cmd is not always set especially when user has not provided ENGINE=xxx so requesting option_storage_engine_name from there is not safe. Fixed by accessing thd->lex->m_sql_cmd only when user has used ENGINE= and if not using ha_default_handlerton and requesting engine name after it. --- mysql-test/suite/galera/r/MDEV-37056.result | 15 +++++++++++++++ mysql-test/suite/galera/t/MDEV-37056.test | 18 ++++++++++++++++++ sql/sql_table.cc | 16 ++++++++++------ 3 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 mysql-test/suite/galera/r/MDEV-37056.result create mode 100644 mysql-test/suite/galera/t/MDEV-37056.test diff --git a/mysql-test/suite/galera/r/MDEV-37056.result b/mysql-test/suite/galera/r/MDEV-37056.result new file mode 100644 index 00000000000..6870e2dbb3e --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-37056.result @@ -0,0 +1,15 @@ +connection node_2; +connection node_1; +connection node_1; +SET SESSION wsrep_on=OFF; +SET default_storage_engine=MYISAM; +CREATE SEQUENCE t; +SET SESSION wsrep_on=ON; +CREATE INDEX idx ON t (a); +ERROR HY000: Sequence 'test.t' table structure is invalid (Sequence tables cannot have any keys) +DROP SEQUENCE t; +SET default_storage_engine='MYISAM'; +CREATE SEQUENCE t INCREMENT BY 0 CACHE=0 ENGINE=InnoDB; +CREATE INDEX c ON t (c); +ERROR HY000: Sequence 'test.t' table structure is invalid (Sequence tables cannot have any keys) +DROP SEQUENCE t; diff --git a/mysql-test/suite/galera/t/MDEV-37056.test b/mysql-test/suite/galera/t/MDEV-37056.test new file mode 100644 index 00000000000..d442c6d99cf --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-37056.test @@ -0,0 +1,18 @@ +--source include/galera_cluster.inc + +--connection node_1 +SET SESSION wsrep_on=OFF; +SET default_storage_engine=MYISAM; +CREATE SEQUENCE t; +SET SESSION wsrep_on=ON; +--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE +CREATE INDEX idx ON t (a); +DROP SEQUENCE t; + +SET default_storage_engine='MYISAM'; +CREATE SEQUENCE t INCREMENT BY 0 CACHE=0 ENGINE=InnoDB; +--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE +CREATE INDEX c ON t (c); + +# cleanup +DROP SEQUENCE t; \ No newline at end of file diff --git a/sql/sql_table.cc b/sql/sql_table.cc index aed7c9dda0e..5e790bcaf45 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5014,32 +5014,35 @@ bool wsrep_check_sequence(THD* thd, const bool used_engine) { enum legacy_db_type db_type; + const LEX_CSTRING *engine_name; DBUG_ASSERT(WSREP(thd)); if (used_engine) { db_type= thd->lex->create_info.db_type->db_type; + // Currently any dynamic storage engine is not possible to identify + // using DB_TYPE_XXXX and ENGINE=SEQUENCE is one of them. + // Therefore, we get storage engine name from lex. + engine_name= + thd->lex->m_sql_cmd->option_storage_engine_name()->name(); } else { const handlerton *hton= ha_default_handlerton(thd); db_type= hton->db_type; + engine_name= hton_name(hton); } // In Galera cluster we support only InnoDB sequences if (db_type != DB_TYPE_INNODB) { - // Currently any dynamic storage engine is not possible to identify - // using DB_TYPE_XXXX and ENGINE=SEQUENCE is one of them. - // Therefore, we get storage engine name from lex. - const LEX_CSTRING *tb_name= thd->lex->m_sql_cmd->option_storage_engine_name()->name(); // (1) CREATE TABLE ... ENGINE=SEQUENCE OR // (2) ALTER TABLE ... ENGINE= OR // Note in ALTER TABLE table->s->sequence != nullptr // (3) CREATE SEQUENCE ... ENGINE= if ((thd->lex->sql_command == SQLCOM_CREATE_TABLE && - lex_string_eq(tb_name, STRING_WITH_LEN("SEQUENCE"))) || + lex_string_eq(engine_name, STRING_WITH_LEN("SEQUENCE"))) || (thd->lex->sql_command == SQLCOM_ALTER_TABLE) || (thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE)) { @@ -5047,7 +5050,8 @@ bool wsrep_check_sequence(THD* thd, "non-InnoDB sequences in Galera cluster"); push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_NOT_SUPPORTED_YET, - "ENGINE=%s not supported by Galera", tb_name->str); + "ENGINE=%s not supported by Galera", + engine_name->str); return(true); } } From 68432a0bc365d783cde21487c257b7e865221f41 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 21 Oct 2025 09:44:34 +0300 Subject: [PATCH 39/54] MDEV-29638 Crash when considering Split-Materialized plan Variant 2: "Don't call optimize_stage2 too early" The affected query had Split-Materialized derived table in another derived table: select * -- select#1 from ( select * -- select#2 from t1, (select * from t2 ... group by t2.group_col) DT -- select#3 where t1.col=t2.group_col ) TBL; The optimization went as follows: JOIN::optimize() calls select_lex->handle_derived(DT_OPTIMIZE) which calls JOIN::optimize() for all (direct and indirect) children SELECTs. select#1->handle_derived() calls JOIN::optimize() for select#2 and #3; select#2->handle_derived() calls JOIN::optimize() for select#3 the second time. That call would call JOIN::optimize_stage2(), assuming the query plan choice has been finalized for select#3. But after that, JOIN::optimize() for select#2 would continue and consider Split-Materialized for select#3. This would attempt to pick another join order and cause a crash. The fix is to have JOIN::optimize() not call optimize_stage2() ever. Finalizing the query plan choice is now done by a separate call: select_lex->handle_derived(thd->lex, DT_OPTIMIZE_STAGE2) which invokes JOIN::optimize_stage2() and saves the query plan. --- mysql-test/main/derived_split_innodb.result | 22 +++++++++ mysql-test/main/derived_split_innodb.test | 27 +++++++++++ sql/sql_derived.cc | 46 ++++++++++++++++-- sql/sql_select.cc | 52 +++++++++++++++++---- sql/sql_select.h | 1 + sql/table.h | 8 +++- 6 files changed, 143 insertions(+), 13 deletions(-) diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index 26d6596acf1..225c83170b6 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -1045,5 +1045,27 @@ WHERE t1.a LIKE 'B%'; a DROP TABLE t1,t2; SET optimizer_switch= @save_optimizer_switch; +# +# MDEV-29638 Crash when considering Split-Materialized plan +# +set @save_optimizer_switch= @@optimizer_switch; +set optimizer_switch='condition_pushdown_for_derived=off,split_materialized=on'; +CREATE TABLE t1 (id int PRIMARY KEY)engine=innodb; +CREATE TABLE t2 (id int PRIMARY KEY, c int) engine=innodb; +CREATE TABLE t3 (id int PRIMARY KEY, a int , b int, KEY (a))engine=innodb; +SELECT * FROM +( +SELECT DISTINCT t1.id +FROM t1 JOIN +( +SELECT t2.id FROM t2 JOIN t3 +ON t3.id = t2.c +WHERE (t3.a > 2 AND t3.b = 2) +GROUP BY t2.id +) m2 ON m2.id = t1.id +) dt; +id +drop table t1, t2, t3; +SET optimizer_switch= @save_optimizer_switch; # End of 10.11 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index 0d2a9ecc776..408e2fd5f3b 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -664,5 +664,32 @@ eval $q; DROP TABLE t1,t2; SET optimizer_switch= @save_optimizer_switch; + +--echo # +--echo # MDEV-29638 Crash when considering Split-Materialized plan +--echo # + +set @save_optimizer_switch= @@optimizer_switch; +set optimizer_switch='condition_pushdown_for_derived=off,split_materialized=on'; + +CREATE TABLE t1 (id int PRIMARY KEY)engine=innodb; +CREATE TABLE t2 (id int PRIMARY KEY, c int) engine=innodb; +CREATE TABLE t3 (id int PRIMARY KEY, a int , b int, KEY (a))engine=innodb; + +SELECT * FROM +( + SELECT DISTINCT t1.id + FROM t1 JOIN + ( + SELECT t2.id FROM t2 JOIN t3 + ON t3.id = t2.c + WHERE (t3.a > 2 AND t3.b = 2) + GROUP BY t2.id + ) m2 ON m2.id = t1.id +) dt; + +drop table t1, t2, t3; +SET optimizer_switch= @save_optimizer_switch; + --echo # End of 10.11 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 2eceba1d5b9..15f1a048299 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -41,6 +41,8 @@ typedef bool (*dt_processor)(THD *thd, LEX *lex, TABLE_LIST *derived); static bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived); static bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived); static bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived); +static bool mysql_derived_optimize_stage2(THD *thd, LEX *lex, + TABLE_LIST *derived); static bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived); static bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived); static bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived); @@ -58,6 +60,7 @@ dt_processor processors[]= &mysql_derived_create, &mysql_derived_fill, &mysql_derived_reinit, + &mysql_derived_optimize_stage2 }; /* @@ -109,8 +112,8 @@ mysql_handle_derived(LEX *lex, uint phases) { if (!cursor->is_view_or_derived() && phases == DT_MERGE_FOR_INSERT) continue; - uint8 allowed_phases= (cursor->is_merged_derived() ? DT_PHASES_MERGE : - DT_PHASES_MATERIALIZE | DT_MERGE_FOR_INSERT); + uint allowed_phases= (cursor->is_merged_derived() ? DT_PHASES_MERGE : + DT_PHASES_MATERIALIZE | DT_MERGE_FOR_INSERT); /* Skip derived tables to which the phase isn't applicable. TODO: mark derived at the parse time, later set it's type @@ -170,7 +173,7 @@ bool mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) { bool res= FALSE; - uint8 allowed_phases= (derived->is_merged_derived() ? DT_PHASES_MERGE : + uint allowed_phases= (derived->is_merged_derived() ? DT_PHASES_MERGE : DT_PHASES_MATERIALIZE); DBUG_ENTER("mysql_handle_single_derived"); DBUG_PRINT("enter", ("phases: 0x%x allowed: 0x%x alias: '%s'", @@ -1071,6 +1074,43 @@ err: } +/* + @brief + Call JOIN::optimize_stage2_and_finish() for all child selects that use + two-phase optimization. +*/ + +static +bool mysql_derived_optimize_stage2(THD *thd, LEX *lex, TABLE_LIST *derived) +{ + SELECT_LEX_UNIT *unit= derived->get_unit(); + SELECT_LEX *first_select= unit->first_select(); + SELECT_LEX *save_current_select= lex->current_select; + bool res= FALSE; + + if (derived->merged || unit->is_unit_op()) + { + /* + Two-phase join optimization is not applicable for merged derived tables + and UNIONs. + */ + return FALSE; + } + + lex->current_select= first_select; + /* Same condition as in mysql_derived_optimize(): */ + if (unit->derived && !derived->is_merged_derived()) + { + JOIN *join= first_select->join; + if (join && join->optimization_state == JOIN::OPTIMIZATION_PHASE_1_DONE) + res= join->optimize_stage2_and_finish(); + } + + lex->current_select= save_current_select; + return res; +} + + /** Actually create result table for a materialized derived table/view. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4301c161f79..5bc1842c4d4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1947,7 +1947,6 @@ bool JOIN::build_explain() int JOIN::optimize() { int res= 0; - join_optimization_state init_state= optimization_state; if (select_lex->pushdown_select) { // Do same as JOIN::optimize_inner does: @@ -1960,18 +1959,18 @@ int JOIN::optimize() } with_two_phase_optimization= false; } - else if (optimization_state == JOIN::OPTIMIZATION_PHASE_1_DONE) - res= optimize_stage2(); else { - // to prevent double initialization on EXPLAIN + /* + This function may be invoked multiple times. Do nothing if the + optimization (either full or stage1) are already done. + */ if (optimization_state != JOIN::NOT_OPTIMIZED) return FALSE; optimization_state= JOIN::OPTIMIZATION_IN_PROGRESS; res= optimize_inner(); } - if (!with_two_phase_optimization || - init_state == JOIN::OPTIMIZATION_PHASE_1_DONE) + if (!with_two_phase_optimization) { if (!res && have_query_plan != QEP_DELETED) res= build_explain(); @@ -1981,6 +1980,29 @@ int JOIN::optimize() } +/* + @brief + Call optimize_stage2() and save the query plan. +*/ + +int JOIN::optimize_stage2_and_finish() +{ + int res= 0; + DBUG_ASSERT(with_two_phase_optimization); + DBUG_ASSERT(optimization_state == OPTIMIZATION_PHASE_1_DONE); + + if (optimize_stage2()) + res= 1; + else + { + if (have_query_plan != JOIN::QEP_DELETED) + res= build_explain(); + optimization_state= JOIN::OPTIMIZATION_DONE; + } + return res; +} + + /** @brief Create range filters objects needed in execution for all join tables @@ -2691,6 +2713,19 @@ setup_subq_exit: } +/* + @brief + In the Stage 1 we've picked the join order. + Now, refine the query plan and sort out all the details. + The choice how to handle GROUP/ORDER BY is also made here. + + @detail + The main reason this is a separate function is Split-Materialized + optimization. There, we first consider doing non-split Materialization for + a SELECT. After that, the parent SELECT will attempt doing Splitting in + multiple ways and make the final choice. +*/ + int JOIN::optimize_stage2() { ulonglong select_opts_for_readinfo; @@ -2711,7 +2746,7 @@ int JOIN::optimize_stage2() if (make_range_rowid_filters()) DBUG_RETURN(1); - if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE)) + if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE_STAGE2)) DBUG_RETURN(1); if (optimizer_flag(thd, OPTIMIZER_SWITCH_DERIVED_WITH_KEYS)) @@ -3501,7 +3536,7 @@ setup_subq_exit: some of the derived tables, and never did stage 2. Do it now, otherwise Explain data structure will not be complete. */ - if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE)) + if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE_STAGE2)) DBUG_RETURN(1); } /* @@ -4765,6 +4800,7 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, void JOIN::exec() { + DBUG_ASSERT(optimization_state == OPTIMIZATION_DONE); DBUG_EXECUTE_IF("show_explain_probe_join_exec_start", if (dbug_user_var_equals_int(thd, "show_explain_probe_select_id", diff --git a/sql/sql_select.h b/sql/sql_select.h index 1b6ccca7441..212f40b7d43 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1676,6 +1676,7 @@ public: int optimize(); int optimize_inner(); int optimize_stage2(); + int optimize_stage2_and_finish(); bool build_explain(); int reinit(); int init_execution(); diff --git a/sql/table.h b/sql/table.h index b0cd5ce16d5..ba585e47ffd 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2031,9 +2031,13 @@ class IS_table_read_plan; #define DT_CREATE 32U #define DT_FILL 64U #define DT_REINIT 128U -#define DT_PHASES 8U + +#define DT_OPTIMIZE_STAGE2 256U + +/* Number of bits used by all phases: */ +#define DT_PHASES 9U /* Phases that are applicable to all derived tables. */ -#define DT_COMMON (DT_INIT + DT_PREPARE + DT_REINIT + DT_OPTIMIZE) +#define DT_COMMON (DT_INIT + DT_PREPARE + DT_REINIT + DT_OPTIMIZE + DT_OPTIMIZE_STAGE2) /* Phases that are applicable only to materialized derived tables. */ #define DT_MATERIALIZE (DT_CREATE + DT_FILL) From 2bf1d089cf8e5c3d98058659819e842da75811d7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 22 Oct 2025 21:40:55 +0200 Subject: [PATCH 40/54] MDEV-37906 Server crash or UBSAN errors in Item_func_nextval::update_table upon INSERT DELAYED sequences, just as triggers or check constraints, disable DELAYED --- mysql-test/suite/sql_sequence/other.result | 9 ++++++++- mysql-test/suite/sql_sequence/other.test | 11 ++++++++++- sql/sql_insert.cc | 6 +++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/sql_sequence/other.result b/mysql-test/suite/sql_sequence/other.result index 247eb5b30a8..a77c70a964b 100644 --- a/mysql-test/suite/sql_sequence/other.result +++ b/mysql-test/suite/sql_sequence/other.result @@ -385,6 +385,13 @@ disconnect con1; connection default; drop sequence s1; drop sequence s2; -# # End of 10.4 tests # +# MDEV-37906 Server crash or UBSAN errors in Item_func_nextval::update_table upon INSERT DELAYED +# +create sequence s engine=myisam; +create table t (id bigint default(nextval(s))) engine=myisam; +insert delayed into t () values(); +drop table t; +drop sequence s; +# End of 10.11 tests diff --git a/mysql-test/suite/sql_sequence/other.test b/mysql-test/suite/sql_sequence/other.test index f727f4856fb..f0aaed0a4c1 100644 --- a/mysql-test/suite/sql_sequence/other.test +++ b/mysql-test/suite/sql_sequence/other.test @@ -417,6 +417,15 @@ insert into s1 values (1, 1, 10000, 100, 1, 1000, 0, 0); drop sequence s1; drop sequence s2; ---echo # --echo # End of 10.4 tests + --echo # +--echo # MDEV-37906 Server crash or UBSAN errors in Item_func_nextval::update_table upon INSERT DELAYED +--echo # +create sequence s engine=myisam; +create table t (id bigint default(nextval(s))) engine=myisam; +insert delayed into t () values(); +drop table t; +drop sequence s; + +--echo # End of 10.11 tests diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 434f2c4c873..abc2a0f3cc8 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3406,11 +3406,11 @@ bool Delayed_insert::open_and_lock_table() return TRUE; } - if (table->triggers || table->check_constraints) + if (table->triggers || table->check_constraints || table->internal_tables) { /* - Table has triggers or check constraints. This is not an error, but we do - not support these with delayed insert. Terminate the delayed + Table uses triggers, check constraints or sequences. This is not an error, + but we do not support these with delayed insert. Terminate the delayed thread without an error and thus request lock upgrade. */ return TRUE; From 516f68af9e5d0f142cbb3cd06244d24fb9cdf115 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 23 Oct 2025 14:21:14 +0200 Subject: [PATCH 41/54] MDEV-37345 sequences and prelocking if a bunch of tables are prelocked, when a table is actually needed in the routine, open_tables picks one table out of the prelocked list with a smallest "distance". Distance is simply a difference between the actual table lock and the requested table lock. Say, if the prelocked set contains both t1 write-locked and t1 read-locked, than an UPDATE will prefer write-locked t1 and SELECT will prefer read-locked. if there's only write-locked table in the set, both UPDATE and SELECT will use it. this doesn't distingush between UPDATE and INSERT, but INSERT marks tables with tables->for_insert_data=1, which causes prelocking to invoke add_internal_tables() and prepare sequences for execution. in this bug there were two prelocked t1's, one for INSERT (with for_insert_data=1) and one for UPDATE. INSERT picks the second (they both are write-locked, so the distance is the same), its sequence is not prepared and crashes. Let's add for_insert_data as the lowest bit into the distance. --- mysql-test/suite/sql_sequence/other.result | 16 ++++++++++++++++ mysql-test/suite/sql_sequence/other.test | 20 ++++++++++++++++++++ sql/sql_base.cc | 13 ++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/sql_sequence/other.result b/mysql-test/suite/sql_sequence/other.result index a77c70a964b..92c881a60b3 100644 --- a/mysql-test/suite/sql_sequence/other.result +++ b/mysql-test/suite/sql_sequence/other.result @@ -394,4 +394,20 @@ create table t (id bigint default(nextval(s))) engine=myisam; insert delayed into t () values(); drop table t; drop sequence s; +# +# MDEV-37345 Item_func_nextval::val_int() crash on INSERT...SELECT with subqueries +# +create sequence s; +create table t1 (a int, b int default(nextval(s))); +insert into t1 () values (); +create table t2 (c int); +create procedure p() update t1 set a = 0; +create trigger tr after insert on t2 for each row +begin +insert into t1 () values (); +call p(); +end $ +insert into t2 values (); +drop table t1, t2, s; +drop procedure p; # End of 10.11 tests diff --git a/mysql-test/suite/sql_sequence/other.test b/mysql-test/suite/sql_sequence/other.test index f0aaed0a4c1..0d9e457e236 100644 --- a/mysql-test/suite/sql_sequence/other.test +++ b/mysql-test/suite/sql_sequence/other.test @@ -428,4 +428,24 @@ insert delayed into t () values(); drop table t; drop sequence s; +--echo # +--echo # MDEV-37345 Item_func_nextval::val_int() crash on INSERT...SELECT with subqueries +--echo # +# sequence and prelocking. +create sequence s; +create table t1 (a int, b int default(nextval(s))); +insert into t1 () values (); +create table t2 (c int); +create procedure p() update t1 set a = 0; +--delimiter $ +create trigger tr after insert on t2 for each row +begin + insert into t1 () values (); + call p(); +end $ +--delimiter ; +insert into t2 values (); +drop table t1, t2, s; +drop procedure p; + --echo # End of 10.11 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1eea27607ed..8259d4170c2 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2010,7 +2010,18 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) table->query_id == 0)) { int distance= ((int) table->reginfo.lock_type - - (int) table_list->lock_type); + (int) table_list->lock_type) * 2; + TABLE_LIST *tl= thd->locked_tables_mode == LTM_PRELOCKED + ? table->pos_in_table_list : table->pos_in_locked_tables; + /* + note, that merge table children are automatically added to + prelocking set in ha_myisammrg::add_children_list(), but their + TABLE_LIST's are on the execution arena, so tl will be invalid + on the second execution. Let's just skip them below. + */ + if (table_list->parent_l || !tl || + table_list->for_insert_data != tl->for_insert_data) + distance|= 1; /* Find a table that either has the exact lock type requested, From 72341bc255db3f56778fc716fe68d833c8497e83 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 14 Sep 2025 19:08:25 +0300 Subject: [PATCH 42/54] Simplify NEXTVAL(sequence) when used with DEFAULT Instead of adding another TABLE_LIST to Item_func_nextval->table_list->next_local, update instead Item_func_nextval->table_list->table with the correct table. This removes all checking of table_list->table and table_list->next_local when using sequences. --- sql/item_func.h | 12 +++--------- sql/sql_base.cc | 13 +++++++++---- sql/table.h | 1 + 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sql/item_func.h b/sql/item_func.h index d5e6512363a..4a5b5e2df9a 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -4241,7 +4241,7 @@ protected: bool check_access(THD *, privilege_t); public: Item_func_nextval(THD *thd, TABLE_LIST *table_list_arg): - Item_longlong_func(thd), table_list(table_list_arg) {} + Item_longlong_func(thd), table_list(table_list_arg), table(0) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { @@ -4270,14 +4270,8 @@ public: */ void update_table() { - if (!(table= table_list->table)) - { - /* - If nextval was used in DEFAULT then next_local points to - the table_list used by to open the sequence table - */ - table= table_list->next_local->table; - } + table= table_list->table; + DBUG_ASSERT(table); } bool const_item() const override { return 0; } Item *do_get_copy(THD *thd) const override diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8259d4170c2..75ff76c7d43 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2423,6 +2423,11 @@ retry_share: DBUG_ASSERT(table->file->pushed_cond == NULL); table_list->updatable= 1; // It is not derived table nor non-updatable VIEW table_list->table= table; + if (table_list->linked_table) + { + /* Update link for sequence tables in default */ + table_list->linked_table->table= table; + } if (!from_share && table->vcol_fix_expr(thd)) DBUG_RETURN(true); @@ -5052,7 +5057,7 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx, next_local value as it may have been changed by a previous statement using the same table. */ - tables->next_local= tmp; + tmp->linked_table= tables; continue; } @@ -5067,10 +5072,10 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx, &prelocking_ctx->query_tables_last, tables->for_insert_data); /* - Store link to the new table_list that will be used by open so that - Item_func_nextval() can find it + Store link to the sequences table so that we can in open_table() update + it to point to the opened table. */ - tables->next_local= tl; + tl->linked_table= tables; DBUG_PRINT("info", ("table name: %s added", tables->table_name.str)); } while ((tables= tables->next_global)); DBUG_RETURN(FALSE); diff --git a/sql/table.h b/sql/table.h index ba585e47ffd..341532b6345 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2414,6 +2414,7 @@ struct TABLE_LIST TABLE_LIST *next_local; /* link in a global list of all queries tables */ TABLE_LIST *next_global, **prev_global; + TABLE_LIST *linked_table; // For sequence tables used in default LEX_CSTRING db; LEX_CSTRING table_name; LEX_CSTRING schema_table_name; From 8df3524cf38eb684620069a7989244e38579f2df Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 23 Oct 2025 16:16:31 +0200 Subject: [PATCH 43/54] MDEV-37345 temporary table, ALTER, recreate sequence Test case only. The bug is fixed by cherry-pick of 2d5db535847 "Simplify NEXTVAL(sequence) when used with DEFAULT" --- mysql-test/suite/sql_sequence/other.result | 6 ++++++ mysql-test/suite/sql_sequence/other.test | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/mysql-test/suite/sql_sequence/other.result b/mysql-test/suite/sql_sequence/other.result index 92c881a60b3..1e485d47c99 100644 --- a/mysql-test/suite/sql_sequence/other.result +++ b/mysql-test/suite/sql_sequence/other.result @@ -410,4 +410,10 @@ end $ insert into t2 values (); drop table t1, t2, s; drop procedure p; +create sequence s; +create temporary table t (f int); +alter table t modify f int default(nextval(s)); +create or replace sequence s; +insert into t values (default); +drop sequence s; # End of 10.11 tests diff --git a/mysql-test/suite/sql_sequence/other.test b/mysql-test/suite/sql_sequence/other.test index 0d9e457e236..e1051b7afa0 100644 --- a/mysql-test/suite/sql_sequence/other.test +++ b/mysql-test/suite/sql_sequence/other.test @@ -448,4 +448,12 @@ insert into t2 values (); drop table t1, t2, s; drop procedure p; +# another one, temporary table, ALTER, recreate sequence +create sequence s; +create temporary table t (f int); +alter table t modify f int default(nextval(s)); +create or replace sequence s; +insert into t values (default); +drop sequence s; + --echo # End of 10.11 tests From 956920816e9e918dd9746d41b3bef21dbcac7675 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 24 Oct 2025 14:57:59 +0200 Subject: [PATCH 44/54] MDEV-37710 ASAN errors in find_type2 upon executing a procedure from sys schema don't reload stored routines in the middle of the execution of a routine. we don't want different iterations of a loop to see diffefent definitions For this: remember Cversion in THD on the first sp cache lookup, after that only compare versions with this value not with Cversion. --- mysql-test/main/sp-bugs2.result | 29 ++++++++++++++++++++++++++++ mysql-test/main/sp-bugs2.test | 34 ++++++++++++++++++++++++++++++--- sql/sp.cc | 5 +++-- sql/sp_cache.cc | 4 ++-- sql/sp_cache.h | 2 +- sql/sql_base.cc | 4 ++-- sql/sql_class.h | 18 +++++++++++++---- sql/sql_parse.cc | 2 ++ 8 files changed, 84 insertions(+), 14 deletions(-) diff --git a/mysql-test/main/sp-bugs2.result b/mysql-test/main/sp-bugs2.result index 75826c29221..7d8b485b79c 100644 --- a/mysql-test/main/sp-bugs2.result +++ b/mysql-test/main/sp-bugs2.result @@ -1,3 +1,6 @@ +# +# MDEV-6610 Assertion `thd->is_error() || thd->killed' failed in mysql_execute_command on executing an SP with repeated CREATE TABLE .. SELECT +# CREATE TABLE t1 (i INT); SET @a = 2; CREATE TABLE IF NOT EXISTS t2 (i INT) ENGINE = MyISAM @@ -94,4 +97,30 @@ CALL p1(); # Clean up DROP FUNCTION cnt; DROP PROCEDURE p1; +# +# MDEV-37710 ASAN errors in find_type2 upon executing a procedure from sys schema +# +create procedure p1() +begin +declare found int; +repeat +set found = exists (select * from information_schema.routines where routine_name='f'); +if (sys.ps_is_consumer_enabled('events_waits_history_long') = 'yes') then +select * from mysql.user; +end if; +select release_all_locks(); +until found end repeat; +end$$ +select get_lock('p1', 300); +get_lock('p1', 300) +1 +call p1(); +connect con1,localhost,root,,; +select get_lock('p1', 300); +get_lock('p1', 300) +1 +create function f() returns int return 1; +connection default; +drop function f; +drop procedure p1; # End of 10.11 tests diff --git a/mysql-test/main/sp-bugs2.test b/mysql-test/main/sp-bugs2.test index 6b841626aa8..a666e96a00c 100644 --- a/mysql-test/main/sp-bugs2.test +++ b/mysql-test/main/sp-bugs2.test @@ -1,6 +1,6 @@ -# -# MDEV-6610 Assertion `thd->is_error() || thd->killed' failed in mysql_execute_command on executing an SP with repeated CREATE TABLE .. SELECT -# +--echo # +--echo # MDEV-6610 Assertion `thd->is_error() || thd->killed' failed in mysql_execute_command on executing an SP with repeated CREATE TABLE .. SELECT +--echo # CREATE TABLE t1 (i INT); SET @a = 2; @@ -97,4 +97,32 @@ CALL p1(); DROP FUNCTION cnt; DROP PROCEDURE p1; +--echo # +--echo # MDEV-37710 ASAN errors in find_type2 upon executing a procedure from sys schema +--echo # +delimiter $$; +create procedure p1() +begin + declare found int; + repeat + set found = exists (select * from information_schema.routines where routine_name='f'); + if (sys.ps_is_consumer_enabled('events_waits_history_long') = 'yes') then + select * from mysql.user; + end if; + select release_all_locks(); + until found end repeat; +end$$ +delimiter ;$$ +select get_lock('p1', 300); +--send call p1() +--connect con1,localhost,root,, +select get_lock('p1', 300); +create function f() returns int return 1; +--connection default +--disable_result_log +--reap +--enable_result_log +drop function f; +drop procedure p1; + --echo # End of 10.11 tests diff --git a/sql/sp.cc b/sql/sp.cc index 5c0cae7de2d..a4f429c61b5 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1127,7 +1127,7 @@ Sp_handler::sp_drop_routine_internal(THD *thd, sp_cache **spc= get_cache(thd); DBUG_ASSERT(spc); if ((sp= sp_cache_lookup(spc, name))) - sp_cache_flush_obsolete(spc, &sp); + sp_cache_flush_obsolete(spc, &sp, sp_cache_version()); /* Drop statistics for this stored program from performance schema. */ MYSQL_DROP_SP(type(), name->m_db.str, static_cast(name->m_db.length), name->m_name.str, static_cast(name->m_name.length)); @@ -2818,10 +2818,11 @@ int Sp_handler::sp_cache_routine(THD *thd, DBUG_ASSERT(spc); *sp= sp_cache_lookup(spc, name); + thd->set_sp_cache_version_if_needed(sp_cache_version()); if (*sp) { - sp_cache_flush_obsolete(spc, sp); + sp_cache_flush_obsolete(spc, sp, thd->sp_cache_version()); if (*sp) DBUG_RETURN(SP_OK); } diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 731a6410a2f..9f4ab7b97d2 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -231,9 +231,9 @@ void sp_cache_invalidate() inside SP'. */ -void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp) +void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp, ulong version) { - if ((*sp)->sp_cache_version() < Cversion && !(*sp)->is_invoked()) + if ((*sp)->sp_cache_version() < version) { (*cp)->remove(*sp); *sp= NULL; diff --git a/sql/sp_cache.h b/sql/sp_cache.h index 7506edff814..e4cf131025c 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -59,7 +59,7 @@ void sp_cache_clear(sp_cache **cp); void sp_cache_insert(sp_cache **cp, sp_head *sp); sp_head *sp_cache_lookup(sp_cache **cp, const Database_qualified_name *name); void sp_cache_invalidate(); -void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp); +void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp, ulong version); ulong sp_cache_version(); void sp_cache_enforce_limit(sp_cache *cp, ulong upper_limit_for_elements); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 75ff76c7d43..34d40988793 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3186,7 +3186,7 @@ static bool check_and_update_routine_version(THD *thd, Sroutine_hash_entry *rt, sp_head *sp) { - ulong spc_version= sp_cache_version(); + ulong spc_version= thd->sp_cache_version(); /* sp is NULL if there is no such routine. */ ulong version= sp ? sp->sp_cache_version() : spc_version; /* @@ -3196,7 +3196,7 @@ check_and_update_routine_version(THD *thd, Sroutine_hash_entry *rt, Sic: version != spc_version <--> sp is not NULL. */ if (rt->m_sp_cache_version != version || - (version != spc_version && !sp->is_invoked())) + (version < spc_version && !sp->is_invoked())) { if (thd->m_reprepare_observer && thd->m_reprepare_observer->report_error(thd)) diff --git a/sql/sql_class.h b/sql/sql_class.h index 58028f0183d..df21af03031 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2449,16 +2449,16 @@ struct wait_for_commit class Sp_caches { +protected: + ulong m_sp_cache_version; public: sp_cache *sp_proc_cache; sp_cache *sp_func_cache; sp_cache *sp_package_spec_cache; sp_cache *sp_package_body_cache; Sp_caches() - :sp_proc_cache(NULL), - sp_func_cache(NULL), - sp_package_spec_cache(NULL), - sp_package_body_cache(NULL) + :m_sp_cache_version(0), sp_proc_cache(NULL), sp_func_cache(NULL), + sp_package_spec_cache(NULL), sp_package_body_cache(NULL) { } ~Sp_caches() { @@ -2481,6 +2481,16 @@ public: Don't delete cache objects itself. */ void sp_caches_empty(); + ulong sp_cache_version() const + { + DBUG_ASSERT(m_sp_cache_version); + return m_sp_cache_version; + } + void set_sp_cache_version_if_needed(ulong version) + { + if (!m_sp_cache_version) + m_sp_cache_version= version; + } }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a66e1ec83c1..e460005ba74 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7772,6 +7772,8 @@ void THD::reset_for_next_command(bool do_clear_error) save_prep_leaf_list= false; + m_sp_cache_version= 0; + #ifdef WITH_WSREP #if !defined(DBUG_OFF) if (mysql_bin_log.is_open()) From 78e474b1a72082cf2a5199c13c0ba9e1db97afd3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 25 Oct 2025 20:16:04 +0200 Subject: [PATCH 45/54] cleanup: sp_cache_flush_obsolete it was only truly used in one place, where it needed to compare its arguments before removing an entry from the cache. in the second place it was used, the comparison was redundant, it was only called to remove, not to compare. let's replace it with a function that just removes. --- sql/sp.cc | 5 +++-- sql/sp_cache.cc | 9 +++------ sql/sp_cache.h | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/sql/sp.cc b/sql/sp.cc index a4f429c61b5..d393f06d675 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1127,7 +1127,7 @@ Sp_handler::sp_drop_routine_internal(THD *thd, sp_cache **spc= get_cache(thd); DBUG_ASSERT(spc); if ((sp= sp_cache_lookup(spc, name))) - sp_cache_flush_obsolete(spc, &sp, sp_cache_version()); + sp_cache_remove(spc, &sp); /* Drop statistics for this stored program from performance schema. */ MYSQL_DROP_SP(type(), name->m_db.str, static_cast(name->m_db.length), name->m_name.str, static_cast(name->m_name.length)); @@ -2822,7 +2822,8 @@ int Sp_handler::sp_cache_routine(THD *thd, if (*sp) { - sp_cache_flush_obsolete(spc, sp, thd->sp_cache_version()); + if ((*sp)->sp_cache_version() < thd->sp_cache_version()) + sp_cache_remove(spc, sp); if (*sp) DBUG_RETURN(SP_OK); } diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 9f4ab7b97d2..dd93d6fc101 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -231,13 +231,10 @@ void sp_cache_invalidate() inside SP'. */ -void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp, ulong version) +void sp_cache_remove(sp_cache **cp, sp_head **sp) { - if ((*sp)->sp_cache_version() < version) - { - (*cp)->remove(*sp); - *sp= NULL; - } + (*cp)->remove(*sp); + *sp= NULL; } /** diff --git a/sql/sp_cache.h b/sql/sp_cache.h index e4cf131025c..ea157a41ead 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -59,7 +59,7 @@ void sp_cache_clear(sp_cache **cp); void sp_cache_insert(sp_cache **cp, sp_head *sp); sp_head *sp_cache_lookup(sp_cache **cp, const Database_qualified_name *name); void sp_cache_invalidate(); -void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp, ulong version); +void sp_cache_remove(sp_cache **cp, sp_head **sp); ulong sp_cache_version(); void sp_cache_enforce_limit(sp_cache *cp, ulong upper_limit_for_elements); From 292bab3565fbee86099e1ac88bd57e9d937a2c68 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 25 Oct 2025 20:21:21 +0200 Subject: [PATCH 46/54] cleanup: Sp_caches::sp_caches_swap() remove the fix for MDEV-25243. It's no longer needed, because a routine can no longer be re-parsed in the middle of a statement. --- sql/sql_class.h | 7 ------- sql/sql_show.cc | 32 -------------------------------- 2 files changed, 39 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index df21af03031..313a25f2af3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2468,13 +2468,6 @@ public: DBUG_ASSERT(sp_package_spec_cache == NULL); DBUG_ASSERT(sp_package_body_cache == NULL); } - void sp_caches_swap(Sp_caches &rhs) - { - swap_variables(sp_cache*, sp_proc_cache, rhs.sp_proc_cache); - swap_variables(sp_cache*, sp_func_cache, rhs.sp_func_cache); - swap_variables(sp_cache*, sp_package_spec_cache, rhs.sp_package_spec_cache); - swap_variables(sp_cache*, sp_package_body_cache, rhs.sp_package_body_cache); - } void sp_caches_clear(); /** Clear content of sp related caches. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bfb4011f104..5ab3c3f0cb8 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5285,30 +5285,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) uint table_open_method= tables->table_open_method; bool can_deadlock; MEM_ROOT tmp_mem_root; - /* - We're going to open FRM files for tables. - In case of VIEWs that contain stored function calls, - these stored functions will be parsed and put to the SP cache. - - Suppose we have a view containing a stored function call: - CREATE VIEW v1 AS SELECT f1() AS c1; - and now we're running: - SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=f1(); - If a parallel thread invalidates the cache, - e.g. by creating or dropping some stored routine, - the SELECT query will re-parse f1() when processing "v1" - and replace the outdated cached version of f1() to a new one. - But the old version of f1() is referenced from the m_sp member - of the Item_func_sp instances used in the WHERE condition. - We cannot destroy it. To avoid such clashes, let's remember - all old routines into a temporary SP cache collection - and process tables with a new empty temporary SP cache collection. - Then restore to the old SP cache collection at the end. - */ - Sp_caches old_sp_caches; - - old_sp_caches.sp_caches_swap(*thd); - bzero(&tmp_mem_root, sizeof(tmp_mem_root)); /* @@ -5481,14 +5457,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) err: thd->restore_backup_open_tables_state(&open_tables_state_backup); free_root(&tmp_mem_root, 0); - - /* - Now restore to the saved SP cache collection - and clear the temporary SP cache collection. - */ - old_sp_caches.sp_caches_swap(*thd); - old_sp_caches.sp_caches_clear(); - DBUG_RETURN(error); } From aa70eeac2cff766d7ff2dad3e9b84b575dd14194 Mon Sep 17 00:00:00 2001 From: Oleg Smirnov Date: Tue, 28 Oct 2025 01:58:00 +0700 Subject: [PATCH 47/54] MDEV-36761: Put NULL-aware cardinality estimation under new_mode flag The NULL-aware index statistics fix is now controlled by the FIX_INDEX_STATS_FOR_ALL_NULLS flag and disabled by default for preserving execution plan stability in stable versions. To enable: SET @@new_mode = 'FIX_INDEX_STATS_FOR_ALL_NULLS'; Or via command line: --new-mode=FIX_INDEX_STATS_FOR_ALL_NULLS Or in configuration file: [mysqld] new_mode=FIX_INDEX_STATS_FOR_ALL_NULLS `all_nulls_key_parts` bitmap is now calculated at set_statistics_for_table() --- mysql-test/main/mysqld--help.result | 4 +- ...y.result => null_aware_cardinality.result} | 16 +++-- ...ality.test => null_aware_cardinality.test} | 12 +++- mysql-test/suite/sys_vars/r/new_mode.result | 2 +- .../sys_vars/r/sysvars_server_embedded.result | 2 +- .../r/sysvars_server_notembedded.result | 2 +- sql/sql_class.h | 3 +- sql/sql_select.cc | 3 + sql/sql_statistics.cc | 32 +++++++-- sql/sql_statistics.h | 9 ++- sql/structs.h | 8 +++ sql/sys_vars.cc | 5 +- sql/table.cc | 68 ++++--------------- 13 files changed, 94 insertions(+), 72 deletions(-) rename mysql-test/main/{null-aware-cardinality.result => null_aware_cardinality.result} (92%) rename mysql-test/main/{null-aware-cardinality.test => null_aware_cardinality.test} (90%) diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index 78407640d80..f9ed13e1e17 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -743,7 +743,9 @@ The following specify which files/extra groups are read (specified before remain Number of seconds to wait for a block to be written to a connection before aborting the write --new-mode=name Used to introduce new behavior to existing MariaDB - versions. No currently supported values. + versions. Any combination of: + FIX_INDEX_STATS_FOR_ALL_NULLS + Use 'ALL' to set all combinations. --note-verbosity=name Verbosity level for note-warnings given to the user. See also @@sql_notes.. Any combination of: basic, diff --git a/mysql-test/main/null-aware-cardinality.result b/mysql-test/main/null_aware_cardinality.result similarity index 92% rename from mysql-test/main/null-aware-cardinality.result rename to mysql-test/main/null_aware_cardinality.result index 5c5aae9dfb7..66edc11531a 100644 --- a/mysql-test/main/null-aware-cardinality.result +++ b/mysql-test/main/null_aware_cardinality.result @@ -1,3 +1,4 @@ +SET @session_start_value = @@new_mode; # Small driving table CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1, 1), (2, 2000),(3,300); @@ -13,6 +14,7 @@ ANALYZE TABLE t2 PERSISTENT FOR ALL; Table Op Msg_type Msg_text test.t2 analyze status Engine-independent statistics collected test.t2 analyze status Table is already up to date +SET @@new_mode = "FIX_INDEX_STATS_FOR_ALL_NULLS"; # NULL-rejecting equality t1.b = t2.b will not return any matches # because all values of t2.b are NULL. So "rows" = 1 for t2 where 1 is # a special value meaning "very few" rows @@ -30,10 +32,6 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ref key_b key_b 5 test.t1.b 11 100.00 Using index condition; Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` and `test`.`t1`.`b` <=> `test`.`t2`.`b` -ANALYZE SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b <=> t2.b; -id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00 -1 SIMPLE t2 ref key_b key_b 5 test.t1.b 11 0.00 100.00 100.00 Using index condition; Using where # Insert some non-NULL values and re-collect the stats INSERT INTO t2 SELECT 1, 1 FROM seq_1_to_100; ANALYZE TABLE t2 PERSISTENT FOR COLUMNS (b) INDEXES (key_b); @@ -82,12 +80,21 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t3 ref key_ab key_ab 10 test.t1.a,const 11 100.00 Using where; Using index Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t3` where `test`.`t3`.`a` = `test`.`t1`.`a` and `test`.`t3`.`b` is null +# In the old mode (null-aware estimation is not enabled), "rows" > 1 +SET @@new_mode = ""; +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b = t2.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t2 ref key_b key_b 5 test.t1.b 100 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` where `test`.`t2`.`a` = `test`.`t1`.`a` and `test`.`t2`.`b` = `test`.`t1`.`b` # Insert some non-NULL values and re-collect the stats INSERT INTO t3 SELECT 1, 1 FROM seq_1_to_100; ANALYZE TABLE t3 PERSISTENT FOR COLUMNS (b) INDEXES (key_ab); Table Op Msg_type Msg_text test.t3 analyze status Engine-independent statistics collected test.t3 analyze status OK +SET @@new_mode = "FIX_INDEX_STATS_FOR_ALL_NULLS"; EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t1.b = t3.b; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where @@ -147,4 +154,5 @@ EXPLAIN SELECT * FROM t1, t2 WHERE t2.a=t1.a AND t2.b=t1.a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using where 1 SIMPLE t2 ref i1 i1 21 test.t1.a,test.t1.a 1 Using where +SET @@new_mode = @session_start_value; DROP TABLE t1, t2; diff --git a/mysql-test/main/null-aware-cardinality.test b/mysql-test/main/null_aware_cardinality.test similarity index 90% rename from mysql-test/main/null-aware-cardinality.test rename to mysql-test/main/null_aware_cardinality.test index 418f0f3d9af..eead918367a 100644 --- a/mysql-test/main/null-aware-cardinality.test +++ b/mysql-test/main/null_aware_cardinality.test @@ -1,5 +1,7 @@ --source include/have_sequence.inc +SET @session_start_value = @@new_mode; + --echo # Small driving table CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1, 1), (2, 2000),(3,300); @@ -13,6 +15,8 @@ INSERT INTO t2 SELECT seq/100, NULL FROM seq_1_to_1000; ANALYZE TABLE t2 PERSISTENT FOR ALL; +SET @@new_mode = "FIX_INDEX_STATS_FOR_ALL_NULLS"; + --echo # NULL-rejecting equality t1.b = t2.b will not return any matches --echo # because all values of t2.b are NULL. So "rows" = 1 for t2 where 1 is --echo # a special value meaning "very few" rows @@ -22,8 +26,6 @@ EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b = t2.b; --echo # must not be affected ("rows" > 1 is expected) EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b <=> t2.b; -ANALYZE SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b <=> t2.b; - --echo # Insert some non-NULL values and re-collect the stats INSERT INTO t2 SELECT 1, 1 FROM seq_1_to_100; @@ -50,11 +52,16 @@ EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t1.b <=> t3.b; EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t3.b is NULL; +--echo # In the old mode (null-aware estimation is not enabled), "rows" > 1 +SET @@new_mode = ""; +EXPLAIN EXTENDED SELECT * FROM t1 JOIN t2 ON t1.a = t2.a AND t1.b = t2.b; + --echo # Insert some non-NULL values and re-collect the stats INSERT INTO t3 SELECT 1, 1 FROM seq_1_to_100; ANALYZE TABLE t3 PERSISTENT FOR COLUMNS (b) INDEXES (key_ab); +SET @@new_mode = "FIX_INDEX_STATS_FOR_ALL_NULLS"; EXPLAIN EXTENDED SELECT * FROM t1 JOIN t3 ON t1.a = t3.a AND t1.b = t3.b; --echo # Test composite index for 3 columns. Key prefix is used for access @@ -92,4 +99,5 @@ ANALYZE TABLE t2 PERSISTENT FOR COLUMNS (b) INDEXES (i1); EXPLAIN SELECT * FROM t1, t2 WHERE t2.a=t1.a AND t2.b=t1.a; +SET @@new_mode = @session_start_value; DROP TABLE t1, t2; \ No newline at end of file diff --git a/mysql-test/suite/sys_vars/r/new_mode.result b/mysql-test/suite/sys_vars/r/new_mode.result index 316a48dd2ce..d078537a1e1 100644 --- a/mysql-test/suite/sys_vars/r/new_mode.result +++ b/mysql-test/suite/sys_vars/r/new_mode.result @@ -25,7 +25,7 @@ ERROR 42000: Variable 'new_mode' can't be set to the value of 'TEST_WARNING3' SET @@session.new_mode = "ALL"; select @@session.new_mode; @@session.new_mode - +FIX_INDEX_STATS_FOR_ALL_NULLS SET @@global.new_mode = NULL; ERROR 42000: Variable 'new_mode' can't be set to the value of 'NULL' SET @@global.new_mode = ''; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 6688230c114..34c01434f40 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2319,7 +2319,7 @@ VARIABLE_COMMENT Used to introduce new behavior to existing MariaDB versions NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST +ENUM_VALUE_LIST FIX_INDEX_STATS_FOR_ALL_NULLS READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME NOTE_VERBOSITY diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index baa44f133ca..c898835003e 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -2529,7 +2529,7 @@ VARIABLE_COMMENT Used to introduce new behavior to existing MariaDB versions NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST +ENUM_VALUE_LIST FIX_INDEX_STATS_FOR_ALL_NULLS READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME NOTE_VERBOSITY diff --git a/sql/sql_class.h b/sql/sql_class.h index 30ac9c94740..d075bfb264b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -219,7 +219,8 @@ void old_mode_deprecated_warnings(THD *thd, ulonglong v); See sys_vars.cc /new_mode_all_names */ -#define NEW_MODE_MAX 0 +#define NEW_MODE_FIX_INDEX_STATS_FOR_ALL_NULLS (1ULL << 0) +#define NEW_MODE_MAX 1 /* Definitions above that have transitioned from new behaviour to default */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7579ffc83cf..f8f304a2e71 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13450,6 +13450,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, keyinfo->algorithm= HA_KEY_ALG_UNDEF; keyinfo->flags= HA_GENERATED_KEY; keyinfo->is_statistics_from_stat_tables= FALSE; + keyinfo->all_nulls_key_parts= 0; keyinfo->name.str= "$hj"; keyinfo->name.length= 3; keyinfo->rec_per_key= (ulong*) thd->calloc(sizeof(ulong)*key_parts); @@ -22432,6 +22433,7 @@ bool Create_tmp_table::finalize(THD *thd, keyinfo->collected_stats= NULL; keyinfo->algorithm= HA_KEY_ALG_UNDEF; keyinfo->is_statistics_from_stat_tables= FALSE; + keyinfo->all_nulls_key_parts= 0; keyinfo->name= group_key; keyinfo->comment.str= 0; ORDER *cur_group= m_group; @@ -22553,6 +22555,7 @@ bool Create_tmp_table::finalize(THD *thd, keyinfo->name= distinct_key; keyinfo->algorithm= HA_KEY_ALG_UNDEF; keyinfo->is_statistics_from_stat_tables= FALSE; + keyinfo->all_nulls_key_parts= 0; keyinfo->read_stats= NULL; keyinfo->collected_stats= NULL; diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 588948412ff..f3741482853 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -4156,11 +4156,35 @@ void set_statistics_for_table(THD *thd, TABLE *table) for (key_info= table->key_info, key_info_end= key_info+table->s->keys; key_info < key_info_end; key_info++) { + key_info->all_nulls_key_parts= 0; key_info->is_statistics_from_stat_tables= - (check_eits_preferred(thd) && - table->stats_is_read && - key_info->read_stats->avg_frequency_is_inited() && - key_info->read_stats->has_stats()); + (check_eits_preferred(thd) && + table->stats_is_read && + key_info->read_stats->avg_frequency_is_inited() && + key_info->read_stats->has_stats(thd)); + + // Fill out `all_nulls_key_parts` bitmap + if (TEST_NEW_MODE_FLAG(thd, NEW_MODE_FIX_INDEX_STATS_FOR_ALL_NULLS) && + key_info->is_statistics_from_stat_tables) + { + for (uint part_idx= 0; part_idx < key_info->usable_key_parts; part_idx++) + { + Field *field= + table->field[key_info->key_part[part_idx].field->field_index]; + if (!field->read_stats) + { + // No column statistics available + continue; + } + + // Check if all values in this column are NULL according to statistics + double nulls_ratio= field->read_stats->get_nulls_ratio(); + if (nulls_ratio == 1.0) + { + key_info->all_nulls_key_parts |= (1 << part_idx); + } + } + } } } diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index 871d942c021..dd1d5090641 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -606,7 +606,6 @@ private: bool stats_were_read; public: - void init_avg_frequency(ulonglong *ptr) { avg_frequency= ptr; @@ -615,7 +614,13 @@ public: void mark_stats_as_read() { stats_were_read= true; } - bool has_stats() const { return stats_were_read; } + bool has_stats(THD *thd) const + { + if (TEST_NEW_MODE_FLAG(thd, NEW_MODE_FIX_INDEX_STATS_FOR_ALL_NULLS)) + return stats_were_read; + else + return get_avg_frequency(0) > 0.5; + } bool avg_frequency_is_inited() { return avg_frequency != NULL; } diff --git a/sql/structs.h b/sql/structs.h index 2c35aba7d41..d81666e256e 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -171,6 +171,14 @@ typedef struct st_key { engine_option_value *option_list; ha_index_option_struct *option_struct; /* structure with parsed options */ + /* + Bitmap of key parts where all values are NULL (nulls_ratio == 1.0). + Bit N set means key part N has all NULLs in the corresponding column. + Used for NULL-aware cardinality estimation. + It is computed based on EITS data, otherwise it is 0. + */ + key_part_map all_nulls_key_parts; + double actual_rec_per_key(uint last_key_part_in_prefix) const; double rec_per_key_null_aware(uint last_key_part_in_prefix, key_part_map notnull_part) const; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 904650a8607..3643e6cb2a3 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4055,6 +4055,7 @@ static Sys_var_set Sys_old_behavior( */ static const char *new_mode_all_names[]= { + "FIX_INDEX_STATS_FOR_ALL_NULLS", "TEST_WARNING1", // Default from here, See NEW_MODE_MAX "TEST_WARNING2", 0 @@ -4062,8 +4063,8 @@ static const char *new_mode_all_names[]= static int new_mode_hidden_names[] = { - 0, // TEST_WARNING1 - 1, // TEST_WARNING2 + 1, // TEST_WARNING1 + 2, // TEST_WARNING2 -1 // End of list }; diff --git a/sql/table.cc b/sql/table.cc index 4f554bf23da..ff311a87572 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8642,6 +8642,7 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, bzero(keyinfo->rec_per_key, sizeof(ulong)*key_parts); keyinfo->read_stats= NULL; keyinfo->collected_stats= NULL; + keyinfo->all_nulls_key_parts= 0; for (i= 0; i < key_parts; i++) { @@ -10304,7 +10305,8 @@ uint TABLE_SHARE::actual_n_key_parts(THD *thd) Prefers engine-independent statistics (EITS) if available and falls back to engine-dependent statistics otherwise. - @param max_key_part Index of the last key part in the prefix (0-based) + @param last_key_part_in_prefix Index of the last key part + in the prefix (0-based) @return Estimated records per key value: - 0.0 if no statistics available @@ -10331,7 +10333,8 @@ double KEY::actual_rec_per_key(uint last_key_part_in_prefix) const the query uses NULL-rejecting conditions (e.g., =), returns 1.0 to indicate high selectivity since NULL = NULL never matches. - @param max_key_part Index of the last key part in the prefix (0-based) + @param last_key_part_in_prefix Index of the last key part + in the prefix (0-based) @param notnull_part Bitmap indicating which key parts have NULL-rejecting conditions (bit N set means key part N uses =, not <=>) @@ -10344,60 +10347,19 @@ double KEY::actual_rec_per_key(uint last_key_part_in_prefix) const double KEY::rec_per_key_null_aware(uint last_key_part_in_prefix, key_part_map notnull_part) const { - if (!is_statistics_from_stat_tables) + if (notnull_part & all_nulls_key_parts) { - // Fall back to engine-dependent statistics if EITS is not available - return rec_per_key ? (double) rec_per_key[last_key_part_in_prefix] : 0.0; + /* + For NULL-rejecting conditions like `t1.key_col = t2.col`, we know + there will be no matches (since NULL = NULL is never true). + If at least one NULL-rejecting condition is present, and all + corresponding key part values are NULL, return number of records 1.0 + (highly selective), indicating no expected matches. + */ + return 1.0; } - // Use engine-independent statistics (EITS) - double records= read_stats->get_avg_frequency(last_key_part_in_prefix); - if (records != 0.0) - return records; - - /* - The index statistics show avg_frequency == 0 for this index prefix. - This typically means all values in the indexed columns are NULL. - - For NULL-rejecting conditions like `t1.key_col = t2.col`, we know - there will be no matches (since NULL = NULL is never true). - However, for non-NULL-rejecting conditions like `t1.key_col <=> t2.col`, - matches are possible. - - Check each key part in the prefix: if any key part has a NULL-rejecting - condition (indicated by bit set in `notnull_part`) and the statistics - confirm all values are NULL (nulls_ratio == 1.0), we can return 1.0 - (highly selective estimate) instead of 0.0 (unknown), indicating - no expected matches. - */ - for (int bit= last_key_part_in_prefix; bit >= 0; bit--) - { - key_part_map mask = (key_part_map)1 << bit; - if ((notnull_part & mask) == 0) - { - // Non-NULL-rejecting condition for the key part - continue; - } - - Field *field= table->field[key_part[bit].field->field_index]; - if (!field->read_stats) - { - // No column statistics available - continue; - } - - // Check if all values in this column are NULL according to statistics - double nulls_ratio= field->read_stats->get_nulls_ratio(); - if (nulls_ratio == 1.0) - { - /* - All values are NULL and the condition is NULL-rejecting. - Return 1.0 (highly selective), indicating no expected matches. - */ - return 1.0; - } - } - return records; + return actual_rec_per_key(last_key_part_in_prefix); } /* From 240b4e83e03075a9f6ca59f94f9b50cdac25c1f0 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 24 Oct 2025 22:09:45 +0300 Subject: [PATCH 48/54] MDEV-37913: disable_index_merge_plans causes SELECT data loss when more than 100 ORs (Variant 2) SEL_TREE* tree_or(SEL_TREE *X, SEL_TREE *Y) tries to conserve memory by reusing object *X for the return value when possible. MDEV-34620 has added logic to disable construction of index_merge plans for N-way ORs with large N. That logic interfered with object reuse logic: for the parameters of: X = SEL_TREE{ trees=[key1_treeA, key2_treeB]} Y = SEL_TREE{ trees=[key1_treeC]} we would decide to reuse object X. For key1, we would produce key_or(key1_treeA, key1_treeC) but key2_treeB would be just left there. Then, we would construct a range scan from key2_treeB. Fixed by moving the "disable building index_merge plans" logic into a location where it would not interfere with object reuse logic. --- mysql-test/main/range.result | 21 +++++++++++++++++++++ mysql-test/main/range.test | 26 ++++++++++++++++++++++++++ mysql-test/main/range_mrr_icp.result | 21 +++++++++++++++++++++ sql/opt_range.cc | 9 +++++++-- 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/range.result b/mysql-test/main/range.result index fa1f62b0763..6943a295acb 100644 --- a/mysql-test/main/range.result +++ b/mysql-test/main/range.result @@ -3736,6 +3736,27 @@ DROP TABLE t1; # # End of 10.5 tests # +# +# MDEV-37913: disable_index_merge_plans causes SELECT data loss when more than 100 ORs +# +CREATE TABLE t1 ( +id int primary key, +key1 int, +index(key1) +); +INSERT INTO t1 VALUES +(1, 1), +(2, 1), +(3, 2); +$query; +id key1 +1 1 +2 1 +3 2 +drop table t1; +# +# End of 10.11 tests +# set global innodb_stats_persistent= @innodb_stats_persistent_save; set global innodb_stats_persistent_sample_pages= @innodb_stats_persistent_sample_pages_save; diff --git a/mysql-test/main/range.test b/mysql-test/main/range.test index 2da200f4730..a77cef34e4c 100644 --- a/mysql-test/main/range.test +++ b/mysql-test/main/range.test @@ -2533,6 +2533,32 @@ DROP TABLE t1; --echo # End of 10.5 tests --echo # +--echo # +--echo # MDEV-37913: disable_index_merge_plans causes SELECT data loss when more than 100 ORs +--echo # +CREATE TABLE t1 ( + id int primary key, + key1 int, + index(key1) +); + +INSERT INTO t1 VALUES +(1, 1), +(2, 1), +(3, 2); + +let $query=` + select concat('select * from t1 where (key1 = 2 AND id = 3) ', + REPEAT(' OR (key1 = 1)', 100)) +`; + +evalp $query; + +drop table t1; + +--echo # +--echo # End of 10.11 tests +--echo # set global innodb_stats_persistent= @innodb_stats_persistent_save; set global innodb_stats_persistent_sample_pages= @innodb_stats_persistent_sample_pages_save; diff --git a/mysql-test/main/range_mrr_icp.result b/mysql-test/main/range_mrr_icp.result index a49ad31ecdf..7a5a1405c73 100644 --- a/mysql-test/main/range_mrr_icp.result +++ b/mysql-test/main/range_mrr_icp.result @@ -3725,6 +3725,27 @@ DROP TABLE t1; # # End of 10.5 tests # +# +# MDEV-37913: disable_index_merge_plans causes SELECT data loss when more than 100 ORs +# +CREATE TABLE t1 ( +id int primary key, +key1 int, +index(key1) +); +INSERT INTO t1 VALUES +(1, 1), +(2, 1), +(3, 2); +$query; +id key1 +1 1 +2 1 +3 2 +drop table t1; +# +# End of 10.11 tests +# set global innodb_stats_persistent= @innodb_stats_persistent_save; set global innodb_stats_persistent_sample_pages= @innodb_stats_persistent_sample_pages_save; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index c6c4a5d7b4f..75abbe3bae2 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -9974,8 +9974,6 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) { bool must_be_ored= sel_trees_must_be_ored(param, tree1, tree2, ored_keys); no_imerge_from_ranges= must_be_ored; - if (param->disable_index_merge_plans) - no_imerge_from_ranges= true; if (no_imerge_from_ranges && no_merges1 && no_merges2) { @@ -10025,6 +10023,13 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) DBUG_RETURN(result); } + /* + Ok, the result now has the ranges that one gets for (RT1 OR RT2). + If construction of SEL_IMERGE is disabled, stop right here. + */ + if (param->disable_index_merge_plans) + DBUG_RETURN(result); + SEL_IMERGE *imerge_from_ranges; if (!(imerge_from_ranges= new SEL_IMERGE())) result= NULL; From 9dce783911a91d60fee01ac028d0dd0cfc18b9de Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 3 Nov 2025 00:21:43 +0100 Subject: [PATCH 49/54] fix spider/bugfix.mdev_22979 test * remove the file to be --repeat friendly * specify the correct defaults-group-suffix. Spider doesn't use the conventional .1 group, so MYSQLD_CMD skips a lot of config options, in particular it doesn't read --tmpdir and creates files in /tmp --- storage/spider/mysql-test/spider/bugfix/t/mdev_22979.test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_22979.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_22979.test index 7f42bd734c6..93e210a9e50 100644 --- a/storage/spider/mysql-test/spider/bugfix/t/mdev_22979.test +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_22979.test @@ -12,7 +12,8 @@ let $PLUGIN_DIR=`select @@plugin_dir`; --write_file $MYSQLTEST_VARDIR/tmp/mdev_22979.sql drop table if exists foo.bar; EOF ---exec $MYSQLD_CMD --datadir=$MYSQLD_DATADIR --bootstrap --plugin-dir=$PLUGIN_DIR --plugin-load-add=ha_spider < $MYSQLTEST_VARDIR/tmp/mdev_22979.sql +--exec $MYSQLD --defaults-group-suffix=.1.1 --defaults-file=$MYSQLTEST_VARDIR/my.cnf --datadir=$MYSQLD_DATADIR --bootstrap --plugin-dir=$PLUGIN_DIR --plugin-load-add=ha_spider < $MYSQLTEST_VARDIR/tmp/mdev_22979.sql --source include/start_mysqld.inc --disable_query_log --source ../../include/clean_up_spider.inc +--remove_file $MYSQLTEST_VARDIR/tmp/mdev_22979.sql From cb0d6dd835023a7162ace471cd047161f205dd58 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Nov 2025 21:36:53 +0100 Subject: [PATCH 50/54] fix rpm upgrade tests after MDEV-37726 MDEV-37726 moved wsrep-start-position to INSTALL_RUNDATADIR and made the latter to be created by systemd-tmpfiles. Now postin scriptlet has to run systemd-tmpfiles explicitly to make sure INSTALL_RUNDATADIR exists before restarting the server. followup for 649216e70d87 --- support-files/rpm/server-postin.sh | 1 + support-files/rpm/server-posttrans.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/support-files/rpm/server-postin.sh b/support-files/rpm/server-postin.sh index 5a66381d593..e08bce07530 100644 --- a/support-files/rpm/server-postin.sh +++ b/support-files/rpm/server-postin.sh @@ -1,5 +1,6 @@ if [ -f /usr/lib/systemd/system/mariadb.service -a -x /usr/bin/systemctl ]; then systemd_conf=/etc/systemd/system/mariadb.service.d/migrated-from-my.cnf-settings.conf + systemd-tmpfiles --create mariadb.conf if [ -x %{_bindir}/mariadb-service-convert -a ! -f "${systemd_conf}" ]; then # Either fresh install or upgrade non-systemd -> systemd mkdir -p /etc/systemd/system/mariadb.service.d diff --git a/support-files/rpm/server-posttrans.sh b/support-files/rpm/server-posttrans.sh index d91ff65e04f..e6c411e4aae 100644 --- a/support-files/rpm/server-posttrans.sh +++ b/support-files/rpm/server-posttrans.sh @@ -3,7 +3,7 @@ if [ -r %{restart_flag} ] ; then # only restart the server if it was already running if [ -x /usr/bin/systemctl ] ; then /usr/bin/systemctl daemon-reload > /dev/null 2>&1 - if /usr/bin/systemctl is-active mysql; then + if /usr/bin/systemctl -q is-active mysql; then /usr/bin/systemctl restart mysql > /dev/null 2>&1 else /usr/bin/systemctl try-restart mariadb.service > /dev/null 2>&1 From 0c94001a32da164512f6fc4b75602383c577f924 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 3 Nov 2025 16:56:29 +0100 Subject: [PATCH 51/54] fix merge test to restore the environment include/test_db_charset_latin1.inc should be paired with include/test_db_charset_restore.inc also fix end-of-version test markers --- mysql-test/suite/merge/merge.result | 19 +++++-------------- mysql-test/suite/merge/merge.test | 22 ++++++---------------- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/mysql-test/suite/merge/merge.result b/mysql-test/suite/merge/merge.result index bb149944895..4d872436366 100644 --- a/mysql-test/suite/merge/merge.result +++ b/mysql-test/suite/merge/merge.result @@ -882,6 +882,7 @@ SELECT COUNT(*) FROM t3 WHERE a=0xDF AND b=2; COUNT(*) 2 DROP TABLE t1,t2,t3; +# End of 4.1 tests create table t1 (b bit(1)); create table t2 (b bit(1)); create table tm (b bit(1)) engine = merge union = (t1,t2); @@ -1007,7 +1008,7 @@ ERROR HY000: Unable to open underlying table which is differently defined or of SELECT * FROM m2; a DROP TABLE t1, t2, m1, m2; -End of 5.0 tests +# End of 5.0 tests create table t1 (c1 int, index(c1)); create table t2 (c1 int, index(c1)) engine=merge union=(t1); insert into t1 values (1); @@ -2419,7 +2420,7 @@ check table tm_temp_temp; Table Op Msg_type Msg_text test.tm_temp_temp check status OK drop temporary table t1_temp, tm_temp_temp; -End of 5.1 tests +# End of 5.1 tests # # MDEV-4277: Crash inside mi_killed_in_mariadb() with myisammrg # @@ -2550,7 +2551,7 @@ i a b filler 2 999 999 filler-data-FILLER-DATA-qqq drop table t5; drop table t1,t2,t3,t4; -End of 5.3 tests +# End of 5.3 tests CREATE TABLE t1(a INT, KEY(a)) ENGINE=merge; SELECT MAX(a) FROM t1; MAX(a) @@ -3800,10 +3801,8 @@ test.t1 analyze status Engine-independent statistics collected test.t1 analyze status Table is already up to date DEALLOCATE PREPARE stmt; DROP TABLE t1, tmerge; -# # End of 5.5 tests # -# # Additional coverage for refactoring which is made as part # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege # to allow temp table operations". @@ -3898,11 +3897,8 @@ f foo bar DROP TABLE mrg, t1; -End of 10.5 tests -# # End of 10.0 tests # -# # MDEV-27407 Different ASC/DESC index attributes on MERGE and underlying table can cause wrong results # create table t (a int, key(a desc)) engine=myisam; @@ -3924,10 +3920,8 @@ a 2 1 drop table tm, t; -# # End of 10.8 tests # -# # MDEV-35816 ASAN use-after-poison in st_select_lex::print # CREATE TABLE t1 (a INT); @@ -3964,10 +3958,8 @@ a 4 5 DROP TABLE t1; -# # End of 10.11 tests # -# # MDEV-30088 Assertion `cond_selectivity <= 1.0' failed in get_range_limit_read_cost # CREATE TABLE t1 (a TIMESTAMP, KEY(a)) ENGINE=MRG_MyISAM; @@ -4020,10 +4012,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL i1 5 NULL 1 Using index for group-by drop table t1; set use_stat_tables=default; -# # End of 11.0 tests # -# # MDEV-29174: UPDATE of view that uses MERGE table # CREATE TABLE t1 (a int) ENGINE=MERGE; @@ -4032,3 +4022,4 @@ UPDATE v1 SET a=0; DROP VIEW v1; DROP TABLE t1; # End of 11.1 tests +ALTER DATABASE test CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci; diff --git a/mysql-test/suite/merge/merge.test b/mysql-test/suite/merge/merge.test index deae06fe1c1..22d57b47934 100644 --- a/mysql-test/suite/merge/merge.test +++ b/mysql-test/suite/merge/merge.test @@ -523,7 +523,7 @@ INSERT INTO t2 VALUES ('ss',2),(0xDF,2); SELECT COUNT(*) FROM t3 WHERE a=0xDF AND b=2; DROP TABLE t1,t2,t3; -# End of 4.1 tests +--echo # End of 4.1 tests # # BUG#19648 - Merge table does not work with bit types @@ -632,7 +632,7 @@ SELECT * FROM m1; SELECT * FROM m2; DROP TABLE t1, t2, m1, m2; ---echo End of 5.0 tests +--echo # End of 5.0 tests # @@ -1829,7 +1829,7 @@ alter table tm_temp_temp insert_method=first; check table tm_temp_temp; drop temporary table t1_temp, tm_temp_temp; ---echo End of 5.1 tests +--echo # End of 5.1 tests --echo # --echo # MDEV-4277: Crash inside mi_killed_in_mariadb() with myisammrg @@ -1866,7 +1866,7 @@ select * from t2, t5 where t5.a=999 and t5.b=999; drop table t5; drop table t1,t2,t3,t4; ---echo End of 5.3 tests +--echo # End of 5.3 tests # # BUG#35274 - merge table doesn't need any base tables, gives error 124 when @@ -2773,9 +2773,7 @@ EXECUTE stmt; DEALLOCATE PREPARE stmt; DROP TABLE t1, tmerge; ---echo # --echo # End of 5.5 tests ---echo # --echo # --echo # Additional coverage for refactoring which is made as part @@ -2860,11 +2858,7 @@ CREATE TABLE mrg (f TEXT) ENGINE=MERGE, UNION(t1); SELECT * FROM mrg; DROP TABLE mrg, t1; ---echo End of 10.5 tests - ---echo # --echo # End of 10.0 tests ---echo # --echo # --echo # MDEV-27407 Different ASC/DESC index attributes on MERGE and underlying table can cause wrong results @@ -2886,9 +2880,7 @@ insert into tm () values (); select * from tm; drop table tm, t; ---echo # --echo # End of 10.8 tests ---echo # --echo # --echo # MDEV-35816 ASAN use-after-poison in st_select_lex::print @@ -2904,9 +2896,7 @@ EXECUTE nested; EXECUTE nested; DROP TABLE t1; ---echo # --echo # End of 10.11 tests ---echo # --echo # --echo # MDEV-30088 Assertion `cond_selectivity <= 1.0' failed in get_range_limit_read_cost @@ -2953,9 +2943,8 @@ EXPLAIN SELECT DISTINCT a FROM t1; drop table t1; set use_stat_tables=default; ---echo # --echo # End of 11.0 tests ---echo # + --echo # --echo # MDEV-29174: UPDATE of view that uses MERGE table --echo # @@ -2967,3 +2956,4 @@ DROP VIEW v1; DROP TABLE t1; --echo # End of 11.1 tests +--source include/test_db_charset_restore.inc From d198be392bdbab4361ea7637841cd7a35fd4203e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 3 Nov 2025 19:56:46 +0100 Subject: [PATCH 52/54] fix nullptr-with-nonzero-offset UB --- strings/ctype-uca-scanner_next.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/ctype-uca-scanner_next.inl b/strings/ctype-uca-scanner_next.inl index e8489ddf191..5c78d751890 100644 --- a/strings/ctype-uca-scanner_next.inl +++ b/strings/ctype-uca-scanner_next.inl @@ -81,7 +81,7 @@ MY_FUNCTION_NAME(scanner_next)(my_uca_scanner *scanner, const uint16 *cweight; #if MY_UCA_ASCII_OPTIMIZE && !defined(SCANNER_NEXT_NCHARS) - if (scanner->sbeg + 1 < scanner->send) + if (scanner->send - scanner->sbeg > 1) { const MY_UCA_2BYTES_ITEM *ww; ww= my_uca_level_booster_2bytes_item_addr_const(param->level->booster, From 152ed78d4917ee837b9a7f7a53f32ccbbb07c343 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 4 Nov 2025 01:05:25 +0100 Subject: [PATCH 53/54] MDEV-37345 sequences and prelocking (11.4 version) table->pos_in_table_list is problematic, it can become dangled when an SP is reparsed. Let's avoid it and directly prefer TABLEs where a sequence is ready for inserts. followup for 516f68af9e5d --- sql/sql_base.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 10d650eb1e4..89c7861d610 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2048,16 +2048,12 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) { int distance= ((int) table->reginfo.lock_type - (int) table_list->lock_type) * 2; - TABLE_LIST *tl= thd->locked_tables_mode == LTM_PRELOCKED - ? table->pos_in_table_list : table->pos_in_locked_tables; /* - note, that merge table children are automatically added to - prelocking set in ha_myisammrg::add_children_list(), but their - TABLE_LIST's are on the execution arena, so tl will be invalid - on the second execution. Let's just skip them below. + if we need a table for inserting, make sure it has + its internal tables (a.k.a. sequences) ready */ - if (table_list->parent_l || !tl || - table_list->for_insert_data != tl->for_insert_data) + if (table->internal_tables && + table_list->for_insert_data == !table->internal_tables->table) distance|= 1; /* From aa6a2e6bf05d43c3bb44db50566937a5f97a6580 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 4 Nov 2025 01:05:25 +0100 Subject: [PATCH 54/54] MDEV-37345 sequences and prelocking (11.4 version) table->pos_in_table_list is problematic, it can become dangled when an SP is reparsed. Let's avoid it and directly prefer TABLEs where a sequence is ready for inserts. followup for 516f68af9e5d --- sql/sql_base.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 10d650eb1e4..89c7861d610 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2048,16 +2048,12 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) { int distance= ((int) table->reginfo.lock_type - (int) table_list->lock_type) * 2; - TABLE_LIST *tl= thd->locked_tables_mode == LTM_PRELOCKED - ? table->pos_in_table_list : table->pos_in_locked_tables; /* - note, that merge table children are automatically added to - prelocking set in ha_myisammrg::add_children_list(), but their - TABLE_LIST's are on the execution arena, so tl will be invalid - on the second execution. Let's just skip them below. + if we need a table for inserting, make sure it has + its internal tables (a.k.a. sequences) ready */ - if (table_list->parent_l || !tl || - table_list->for_insert_data != tl->for_insert_data) + if (table->internal_tables && + table_list->for_insert_data == !table->internal_tables->table) distance|= 1; /*