diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2022-08-22 19:49:56 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2022-08-22 19:49:56 +0300 |
commit | 3b656ac8c17b39cf93ec0473b319525fbf1c4499 (patch) | |
tree | b7225a894b0903cee7ca0a5f54bfa7d62d89519a | |
parent | 1d90d6874db367629f45d1284e9efa36557b400a (diff) | |
parent | b68ae6dc1d2bba7f5b9f12bff129cd8066fe6d21 (diff) | |
download | mariadb-git-3b656ac8c17b39cf93ec0473b319525fbf1c4499.tar.gz |
Merge 10.4 into 10.5
-rw-r--r-- | mysql-test/main/timezone2.result | 22 | ||||
-rw-r--r-- | mysql-test/main/timezone2.test | 15 | ||||
-rw-r--r-- | sql/sql_class.cc | 80 | ||||
-rw-r--r-- | sql/sql_class.h | 2 | ||||
-rw-r--r-- | storage/innobase/btr/btr0btr.cc | 5 | ||||
-rw-r--r-- | storage/innobase/btr/btr0sea.cc | 42 | ||||
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 11 | ||||
-rw-r--r-- | storage/innobase/include/btr0sea.h | 18 |
8 files changed, 148 insertions, 47 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/sql/sql_class.cc b/sql/sql_class.cc index c6f06acd206..5ff0a904adc 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3687,6 +3687,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"); @@ -3705,30 +3740,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); @@ -3822,6 +3834,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 87bca3a5f5f..37ffd9a1e32 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6424,6 +6424,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): @@ -6436,6 +6437,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 8c4caf3510a..d4c12090987 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -696,8 +696,9 @@ void btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr, bool blob) { 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 (block->index + && !btr_search_check_marked_free_index(block)) { ut_ad(!blob); ut_ad(page_is_leaf(block->frame)); } diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index 2f75f567933..e70a1587bfe 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -2,7 +2,7 @@ Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. -Copyright (c) 2017, 2021, MariaDB Corporation. +Copyright (c) 2017, 2022, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -1246,8 +1246,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; @@ -1290,18 +1293,25 @@ retry: auto part = btr_search_sys.get_part(index_id, block->page.id().space()); + rw_lock_s_lock(&part->latch); + dict_index_t* index = block->index; bool is_freed = index && index->freed(); if (is_freed) { + rw_lock_s_unlock(&part->latch); rw_lock_x_lock(&part->latch); - } else { - rw_lock_s_lock(&part->latch); + if (index != block->index) { + rw_lock_x_unlock(&part->latch); + goto retry; + } + } else if (garbage_collect) { + rw_lock_s_unlock(&part->latch); + return; } assert_block_ahi_valid(block); - if (!index || !btr_search_enabled) { if (is_freed) { rw_lock_x_unlock(&part->latch); @@ -1774,12 +1784,13 @@ drop_exit: return; } + rw_lock_s_lock(ahi_latch); + if (index->freed()) { + rw_lock_s_unlock(ahi_latch); goto drop_exit; } - rw_lock_s_lock(ahi_latch); - if (block->index) { uint16_t n_fields = block->curr_n_fields; uint16_t n_bytes = block->curr_n_bytes; @@ -2375,5 +2386,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->frame); + auto part= btr_search_sys.get_part(index_id, block->page.id().space()); + + rw_lock_s_lock(&part->latch); + + bool is_freed= block->index && block->index->freed(); + + rw_lock_s_unlock(&part->latch); + + 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 0a13448b9ee..21ea0ec54ca 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2601,18 +2601,14 @@ static void buf_defer_drop_ahi(buf_block_t *block, mtr_memo_type_t fix_type) /* Temporarily release our S-latch. */ rw_lock_s_unlock(&block->lock); rw_lock_x_lock(&block->lock); - 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); rw_lock_x_unlock(&block->lock); rw_lock_s_lock(&block->lock); break; case MTR_MEMO_PAGE_SX_FIX: rw_lock_sx_unlock(&block->lock); rw_lock_x_lock(&block->lock); - 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); rw_lock_x_unlock(&block->lock); rw_lock_sx_lock(&block->lock); break; @@ -2659,8 +2655,7 @@ static buf_block_t* buf_page_mtr_lock(buf_block_t *block, #ifdef BTR_CUR_HASH_ADAPT { - dict_index_t *index= block->index; - if (index && index->freed()) + if (block->index) buf_defer_drop_ahi(block, fix_type); } #endif /* BTR_CUR_HASH_ADAPT */ diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h index db4c54008c2..af01b9a9fba 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, 2020, 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 @@ -96,8 +96,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. @@ -154,21 +157,26 @@ static inline bool btr_search_own_any(ulint mode); /** @return whether this thread holds any of the search latches */ static inline bool btr_search_own_any(); + +/** @return if the index is marked as freed */ +bool btr_search_check_marked_free_index(const buf_block_t *block); #endif /* UNIV_DEBUG */ /** Unlock all search latches from shared mode. */ static inline void btr_search_s_unlock_all(); - #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 |