summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2022-08-23 08:47:21 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2022-08-23 08:47:21 +0300
commitfbb2b1f55f4ea1c11a0772766cbb4378324909d2 (patch)
treeff2b586565a7bdbc4f0266ae15a270132f32f01e
parentd65a2b7bde6f735af3669ccbf550f60b2278d816 (diff)
parent55c648a73880013351dfe07edcd2af4a487ad873 (diff)
downloadmariadb-git-fbb2b1f55f4ea1c11a0772766cbb4378324909d2.tar.gz
Merge 10.5 into 10.6
-rw-r--r--mysql-test/main/timezone2.result22
-rw-r--r--mysql-test/main/timezone2.test15
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6.result16
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6.test11
-rw-r--r--sql/sql_class.cc80
-rw-r--r--sql/sql_class.h2
-rw-r--r--storage/innobase/btr/btr0btr.cc4
-rw-r--r--storage/innobase/btr/btr0cur.cc6
-rw-r--r--storage/innobase/btr/btr0sea.cc39
-rw-r--r--storage/innobase/buf/buf0buf.cc12
-rw-r--r--storage/innobase/include/btr0sea.h18
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