diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2022-08-23 08:47:21 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2022-08-23 08:47:21 +0300 |
commit | fbb2b1f55f4ea1c11a0772766cbb4378324909d2 (patch) | |
tree | ff2b586565a7bdbc4f0266ae15a270132f32f01e | |
parent | d65a2b7bde6f735af3669ccbf550f60b2278d816 (diff) | |
parent | 55c648a73880013351dfe07edcd2af4a487ad873 (diff) | |
download | mariadb-git-fbb2b1f55f4ea1c11a0772766cbb4378324909d2.tar.gz |
Merge 10.5 into 10.6
-rw-r--r-- | mysql-test/main/timezone2.result | 22 | ||||
-rw-r--r-- | mysql-test/main/timezone2.test | 15 | ||||
-rw-r--r-- | plugin/type_inet/mysql-test/type_inet/type_inet6.result | 16 | ||||
-rw-r--r-- | plugin/type_inet/mysql-test/type_inet/type_inet6.test | 11 | ||||
-rw-r--r-- | sql/sql_class.cc | 80 | ||||
-rw-r--r-- | sql/sql_class.h | 2 | ||||
-rw-r--r-- | storage/innobase/btr/btr0btr.cc | 4 | ||||
-rw-r--r-- | storage/innobase/btr/btr0cur.cc | 6 | ||||
-rw-r--r-- | storage/innobase/btr/btr0sea.cc | 39 | ||||
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 12 | ||||
-rw-r--r-- | storage/innobase/include/btr0sea.h | 18 |
11 files changed, 177 insertions, 48 deletions
diff --git a/mysql-test/main/timezone2.result b/mysql-test/main/timezone2.result index f943e285951..806255f26f5 100644 --- a/mysql-test/main/timezone2.result +++ b/mysql-test/main/timezone2.result @@ -654,3 +654,25 @@ SET time_zone=DEFAULT; # # End of 10.4 tests # +# +# MDEV-27101 Subquery using the ALL keyword on TIMESTAMP columns produces a wrong result +# +SET time_zone='Europe/Moscow'; +CREATE TABLE t1 (a TIMESTAMP NULL); +SET timestamp=1288477526; +/* this is summer time, earlier */ +INSERT INTO t1 VALUES (NOW()); +SET timestamp=1288477526+3599; +/* this is winter time, later */ +INSERT INTO t1 VALUES (NOW()); +SELECT a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +a UNIX_TIMESTAMP(a) +2010-10-31 02:25:26 1288477526 +2010-10-31 02:25:25 1288481125 +SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a <= ALL (SELECT * FROM t1); +a UNIX_TIMESTAMP(a) +2010-10-31 02:25:26 1288477526 +SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a >= ALL (SELECT * FROM t1); +a UNIX_TIMESTAMP(a) +2010-10-31 02:25:25 1288481125 +DROP TABLE t1; diff --git a/mysql-test/main/timezone2.test b/mysql-test/main/timezone2.test index 6a8c9f258e4..1feb8916871 100644 --- a/mysql-test/main/timezone2.test +++ b/mysql-test/main/timezone2.test @@ -598,3 +598,18 @@ SET time_zone=DEFAULT; --echo # --echo # End of 10.4 tests --echo # + +--echo # +--echo # MDEV-27101 Subquery using the ALL keyword on TIMESTAMP columns produces a wrong result +--echo # + +SET time_zone='Europe/Moscow'; +CREATE TABLE t1 (a TIMESTAMP NULL); +SET timestamp=1288477526; /* this is summer time, earlier */ +INSERT INTO t1 VALUES (NOW()); +SET timestamp=1288477526+3599; /* this is winter time, later */ +INSERT INTO t1 VALUES (NOW()); +SELECT a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a <= ALL (SELECT * FROM t1); +SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a >= ALL (SELECT * FROM t1); +DROP TABLE t1; diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6.result b/plugin/type_inet/mysql-test/type_inet/type_inet6.result index 9f3b8a9715e..c8192f7bde3 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6.result @@ -2213,3 +2213,19 @@ SELECT * FROM companies; id name DROP TABLE divisions; DROP TABLE companies; +# +# MDEV-27099 Subquery using the ALL keyword on INET6 columns produces a wrong result +# +CREATE TABLE t1 (d INET6); +INSERT INTO t1 VALUES ('1::0'), ('12::0'); +SELECT * FROM t1 ORDER BY d; +d +1:: +12:: +SELECT * FROM t1 WHERE d <= ALL (SELECT * FROM t1); +d +1:: +SELECT * FROM t1 WHERE d >= ALL (SELECT * FROM t1); +d +12:: +DROP TABLE t1; diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6.test b/plugin/type_inet/mysql-test/type_inet/type_inet6.test index ef8399d981f..becc063ddc9 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6.test +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6.test @@ -1630,3 +1630,14 @@ DELETE FROM companies WHERE id IN (SELECT company_id FROM divisions); SELECT * FROM companies; DROP TABLE divisions; DROP TABLE companies; + +--echo # +--echo # MDEV-27099 Subquery using the ALL keyword on INET6 columns produces a wrong result +--echo # + +CREATE TABLE t1 (d INET6); +INSERT INTO t1 VALUES ('1::0'), ('12::0'); +SELECT * FROM t1 ORDER BY d; +SELECT * FROM t1 WHERE d <= ALL (SELECT * FROM t1); +SELECT * FROM t1 WHERE d >= ALL (SELECT * FROM t1); +DROP TABLE t1; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7b229082822..d670bbce5f7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3679,6 +3679,41 @@ void select_max_min_finder_subselect::cleanup() } +void select_max_min_finder_subselect::set_op(const Type_handler *th) +{ + if (th->is_val_native_ready()) + { + op= &select_max_min_finder_subselect::cmp_native; + return; + } + + switch (th->cmp_type()) { + case REAL_RESULT: + op= &select_max_min_finder_subselect::cmp_real; + break; + case INT_RESULT: + op= &select_max_min_finder_subselect::cmp_int; + break; + case STRING_RESULT: + op= &select_max_min_finder_subselect::cmp_str; + break; + case DECIMAL_RESULT: + op= &select_max_min_finder_subselect::cmp_decimal; + break; + case TIME_RESULT: + if (th->field_type() == MYSQL_TYPE_TIME) + op= &select_max_min_finder_subselect::cmp_time; + else + op= &select_max_min_finder_subselect::cmp_str; + break; + case ROW_RESULT: + // This case should never be chosen + DBUG_ASSERT(0); + op= 0; + } +} + + int select_max_min_finder_subselect::send_data(List<Item> &items) { DBUG_ENTER("select_max_min_finder_subselect::send_data"); @@ -3697,30 +3732,7 @@ int select_max_min_finder_subselect::send_data(List<Item> &items) if (!cache) { cache= val_item->get_cache(thd); - switch (val_item->cmp_type()) { - case REAL_RESULT: - op= &select_max_min_finder_subselect::cmp_real; - break; - case INT_RESULT: - op= &select_max_min_finder_subselect::cmp_int; - break; - case STRING_RESULT: - op= &select_max_min_finder_subselect::cmp_str; - break; - case DECIMAL_RESULT: - op= &select_max_min_finder_subselect::cmp_decimal; - break; - case TIME_RESULT: - if (val_item->field_type() == MYSQL_TYPE_TIME) - op= &select_max_min_finder_subselect::cmp_time; - else - op= &select_max_min_finder_subselect::cmp_str; - break; - case ROW_RESULT: - // This case should never be chosen - DBUG_ASSERT(0); - op= 0; - } + set_op(val_item->type_handler()); } cache->store(val_item); it->store(0, cache); @@ -3814,6 +3826,26 @@ bool select_max_min_finder_subselect::cmp_str() return (sortcmp(val1, val2, cache->collation.collation) < 0); } + +bool select_max_min_finder_subselect::cmp_native() +{ + NativeBuffer<STRING_BUFFER_USUAL_SIZE> cvalue, mvalue; + Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0); + bool cvalue_is_null= cache->val_native(thd, &cvalue); + bool mvalue_is_null= maxmin->val_native(thd, &mvalue); + + /* Ignore NULLs for ANY and keep them for ALL subqueries */ + if (cvalue_is_null) + return (is_all && !mvalue_is_null) || (!is_all && mvalue_is_null); + if (mvalue_is_null) + return !is_all; + + const Type_handler *th= cache->type_handler(); + return fmax ? th->cmp_native(cvalue, mvalue) > 0 : + th->cmp_native(cvalue, mvalue) < 0; +} + + int select_exists_subselect::send_data(List<Item> &items) { DBUG_ENTER("select_exists_subselect::send_data"); diff --git a/sql/sql_class.h b/sql/sql_class.h index cb58aff5c3e..866aba0d85b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6721,6 +6721,7 @@ class select_max_min_finder_subselect :public select_subselect bool (select_max_min_finder_subselect::*op)(); bool fmax; bool is_all; + void set_op(const Type_handler *ha); public: select_max_min_finder_subselect(THD *thd_arg, Item_subselect *item_arg, bool mx, bool all): @@ -6733,6 +6734,7 @@ public: bool cmp_decimal(); bool cmp_str(); bool cmp_time(); + bool cmp_native(); }; /* EXISTS subselect interface class */ diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 7334a2e1757..3b994c5fa98 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -584,8 +584,8 @@ dberr_t btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr, bool blob, bool space_latched) { ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); -#ifdef BTR_CUR_HASH_ADAPT - if (block->index && !block->index->freed()) +#if defined BTR_CUR_HASH_ADAPT && defined UNIV_DEBUG + if (btr_search_check_marked_free_index(block)) { ut_ad(!blob); ut_ad(page_is_leaf(block->page.frame)); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 7a9480cdf4e..82430f7e7ab 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -283,7 +283,7 @@ latch_block: block->page.fix(); block->page.lock.x_lock(); #ifdef BTR_CUR_HASH_ADAPT - ut_ad(!block->index || !block->index->freed()); + ut_ad(!btr_search_check_marked_free_index(block)); #endif if (UNIV_LIKELY_NULL(rtr_info)) { @@ -7024,7 +7024,7 @@ btr_store_big_rec_extern_fields( rec_block->page.fix(); rec_block->page.lock.x_lock(); #ifdef BTR_CUR_HASH_ADAPT - ut_ad(!rec_block->index || !rec_block->index->freed()); + ut_ad(!btr_search_check_marked_free_index(rec_block)); #endif uint32_t hint_prev = prev_page_no; @@ -7401,7 +7401,7 @@ skip_free: block->fix(); block->page.lock.x_lock(); #ifdef BTR_CUR_HASH_ADAPT - ut_ad(!block->index || !block->index->freed()); + ut_ad(!btr_search_check_marked_free_index(block)); #endif const page_t* page = buf_block_get_frame(ext_block); diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index 137a8b10d9f..2ca4417db37 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -1279,8 +1279,11 @@ fail_and_release_page: index page for which we know that block->buf_fix_count == 0 or it is an index page which has already been removed from the buf_pool.page_hash - i.e.: it is in state BUF_BLOCK_REMOVE_HASH */ -void btr_search_drop_page_hash_index(buf_block_t* block) + i.e.: it is in state BUF_BLOCK_REMOVE_HASH +@param[in] garbage_collect drop ahi only if the index is marked + as freed */ +void btr_search_drop_page_hash_index(buf_block_t* block, + bool garbage_collect) { ulint n_fields; ulint n_bytes; @@ -1316,13 +1319,21 @@ retry: auto part = btr_search_sys.get_part(index_id, block->page.id().space()); + part->latch.rd_lock(SRW_LOCK_CALL); + dict_index_t* index = block->index; bool is_freed = index && index->freed(); if (is_freed) { + part->latch.rd_unlock(); part->latch.wr_lock(SRW_LOCK_CALL); - } else { - part->latch.rd_lock(SRW_LOCK_CALL); + if (index != block->index) { + part->latch.wr_unlock(); + goto retry; + } + } else if (garbage_collect) { + part->latch.rd_unlock(); + return; } assert_block_ahi_valid(block); @@ -1797,12 +1808,13 @@ drop_exit: return; } + ahi_latch->rd_lock(SRW_LOCK_CALL); + if (index->freed()) { + ahi_latch->rd_unlock(); goto drop_exit; } - ahi_latch->rd_lock(SRW_LOCK_CALL); - if (block->index) { uint16_t n_fields = block->curr_n_fields; uint16_t n_bytes = block->curr_n_bytes; @@ -2394,5 +2406,20 @@ btr_search_validate() return(true); } +#ifdef UNIV_DEBUG +bool btr_search_check_marked_free_index(const buf_block_t *block) +{ + const index_id_t index_id= btr_page_get_index_id(block->page.frame); + auto part= btr_search_sys.get_part(index_id, block->page.id().space()); + + part->latch.rd_lock(SRW_LOCK_CALL); + + bool is_freed= block->index && block->index->freed(); + + part->latch.rd_unlock(); + + return is_freed; +} +#endif /* UNIV_DEBUG */ #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */ #endif /* BTR_CUR_HASH_ADAPT */ diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 42055246a12..c26bbda9473 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2761,11 +2761,7 @@ re_evict: && state < buf_page_t::WRITE_FIX)); #ifdef BTR_CUR_HASH_ADAPT - if (dict_index_t* index = block->index) { - if (index->freed()) { - btr_search_drop_page_hash_index(block); - } - } + btr_search_drop_page_hash_index(block, true); #endif /* BTR_CUR_HASH_ADAPT */ dberr_t e; @@ -2823,10 +2819,8 @@ get_latch: } get_latch_valid: #ifdef BTR_CUR_HASH_ADAPT - if (dict_index_t* index = block->index) { - if (index->freed()) { - mtr_t::defer_drop_ahi(block, fix_type); - } + if (block->index) { + mtr_t::defer_drop_ahi(block, fix_type); } #endif /* BTR_CUR_HASH_ADAPT */ mtr->memo_push(block, fix_type); diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h index 106582286a9..b5686602610 100644 --- a/storage/innobase/include/btr0sea.h +++ b/storage/innobase/include/btr0sea.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2021, MariaDB Corporation. +Copyright (c) 2017, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -100,8 +100,11 @@ btr_search_move_or_delete_hash_entries( index page for which we know that block->buf_fix_count == 0 or it is an index page which has already been removed from the buf_pool.page_hash - i.e.: it is in state BUF_BLOCK_REMOVE_HASH */ -void btr_search_drop_page_hash_index(buf_block_t* block); + i.e.: it is in state BUF_BLOCK_REMOVE_HASH +@param[in] garbage_collect drop ahi only if the index is marked + as freed */ +void btr_search_drop_page_hash_index(buf_block_t* block, + bool garbage_collect= false); /** Drop possible adaptive hash index entries when a page is evicted from the buffer pool or freed in a file, or the index is being dropped. @@ -146,16 +149,23 @@ static inline void btr_search_s_lock_all(); /** Unlock all search latches from shared mode. */ static inline void btr_search_s_unlock_all(); +# ifdef UNIV_DEBUG +/** @return if the index is marked as freed */ +bool btr_search_check_marked_free_index(const buf_block_t *block); +# endif /* UNIV_DEBUG */ #else /* BTR_CUR_HASH_ADAPT */ # define btr_search_sys_create() # define btr_search_sys_free() -# define btr_search_drop_page_hash_index(block) +# define btr_search_drop_page_hash_index(block, garbage_collect) # define btr_search_s_lock_all(index) # define btr_search_s_unlock_all(index) # define btr_search_info_update(index, cursor) # define btr_search_move_or_delete_hash_entries(new_block, block) # define btr_search_update_hash_on_insert(cursor, ahi_latch) # define btr_search_update_hash_on_delete(cursor) +# ifdef UNIV_DEBUG +# define btr_search_check_marked_free_index(block) +# endif /* UNIV_DEBUG */ #endif /* BTR_CUR_HASH_ADAPT */ #ifdef BTR_CUR_ADAPT |