From ac963142ee351c9359442cbdc1b20ea0283e6a02 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 24 Nov 2021 23:19:22 -0800 Subject: MDEV-26553 NOT IN subquery construct crashing 10.1 and up This bug was introduced by commit be00e279c6061134a33a8099fd69d4304735d02e The commit was applied for the task MDEV-6480 that allowed to remove top level disjuncts from WHERE conditions if the range optimizer evaluated them as always equal to FALSE/NULL. If such disjuncts are removed the WHERE condition may become an AND formula and if this formula contains multiple equalities the field JOIN::item_equal must be updated to refer to these equalities. The above mentioned commit forgot to do this and it could cause crashes for some queries. Approved by Oleksandr Byelkin --- mysql-test/r/range.result | 24 ++++++++++++++++++++++++ mysql-test/r/range_mrr_icp.result | 24 ++++++++++++++++++++++++ mysql-test/t/range.test | 25 ++++++++++++++++++++++++- sql/sql_select.cc | 6 ++++++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 6a3850c0ed9..f1f949acd3b 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -3201,5 +3201,29 @@ pk i v a b 2 2 4 2 4 drop table t1, t2; # +# MDEV-26553: Always FALSE/NULL disjunct on top level of WHERE is removed +# +create table t1 (a int, b int, index idx(a,b)); +insert into t1 values (1,1), (1,2), (2,1), (2,2), (3,3); +create table t2 (c int); +insert into t2 values (5), (2), (3), (4); +select 1 from t1 s1 +where 1 not in (select 1 from t1 +where ((a = 1 or a = 2) and b = 1) or (b > 5 and b < 1)); +1 +select 1 from t1 s1 +where 1 not in (select 1 from t1 +where ((a = 1 or a = 2) and b = 1) or b = NULL); +1 +select c from t2 +where 2 not in (select 1 from t1 +where ((a=1 or a=2) and b = 1) or (b > 5 and b < 1)); +c +5 +2 +3 +4 +drop table t1,t2; +# # End of 10.2 tests # diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result index 24f42f34ce5..645576fbe42 100644 --- a/mysql-test/r/range_mrr_icp.result +++ b/mysql-test/r/range_mrr_icp.result @@ -3213,6 +3213,30 @@ pk i v a b 2 2 4 2 4 drop table t1, t2; # +# MDEV-26553: Always FALSE/NULL disjunct on top level of WHERE is removed +# +create table t1 (a int, b int, index idx(a,b)); +insert into t1 values (1,1), (1,2), (2,1), (2,2), (3,3); +create table t2 (c int); +insert into t2 values (5), (2), (3), (4); +select 1 from t1 s1 +where 1 not in (select 1 from t1 +where ((a = 1 or a = 2) and b = 1) or (b > 5 and b < 1)); +1 +select 1 from t1 s1 +where 1 not in (select 1 from t1 +where ((a = 1 or a = 2) and b = 1) or b = NULL); +1 +select c from t2 +where 2 not in (select 1 from t1 +where ((a=1 or a=2) and b = 1) or (b > 5 and b < 1)); +c +5 +2 +3 +4 +drop table t1,t2; +# # End of 10.2 tests # set optimizer_switch=@mrr_icp_extra_tmp; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 890377ed977..7369b9d8a16 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -2232,6 +2232,29 @@ select * from t1 inner join t2 on ( t2.b = t1.v or t2.a = t1.pk); drop table t1, t2; --echo # ---echo # End of 10.2 tests +--echo # MDEV-26553: Always FALSE/NULL disjunct on top level of WHERE is removed --echo # +create table t1 (a int, b int, index idx(a,b)); +insert into t1 values (1,1), (1,2), (2,1), (2,2), (3,3); + +create table t2 (c int); +insert into t2 values (5), (2), (3), (4); + +select 1 from t1 s1 + where 1 not in (select 1 from t1 + where ((a = 1 or a = 2) and b = 1) or (b > 5 and b < 1)); + +select 1 from t1 s1 + where 1 not in (select 1 from t1 + where ((a = 1 or a = 2) and b = 1) or b = NULL); + +select c from t2 + where 2 not in (select 1 from t1 + where ((a=1 or a=2) and b = 1) or (b > 5 and b < 1)); + +drop table t1,t2; + +--echo # +--echo # End of 10.2 tests +--echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 54a2facfe9f..47422116e38 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4504,7 +4504,13 @@ make_join_statistics(JOIN *join, List &tables_list, if (*s->on_expr_ref) *s->on_expr_ref= select->cond; else + { join->conds= select->cond; + if (join->conds && join->conds->type() == Item::COND_ITEM && + ((Item_cond*) (join->conds))->functype() == + Item_func::COND_AND_FUNC) + join->cond_equal= &((Item_cond_and*) (join->conds))->m_cond_equal; + } s->quick=select->quick; s->needed_reg=select->needed_reg; -- cgit v1.2.1 From 4e0dcf1083ad905b36c69896bdf0731afc9d7fec Mon Sep 17 00:00:00 2001 From: Martin Beck Date: Sat, 20 Nov 2021 14:22:25 +1100 Subject: MDEV-27088: Server crash on ARM (WMM architecture) due to missing barriers in lf-hash MariaDB server crashes on ARM (weak memory model architecture) while concurrently executing l_find to load node->key and add_to_purgatory to store node->key = NULL. l_find then uses key (which is NULL), to pass it to a comparison function. The specific problem is the out-of-order execution that happens on a weak memory model architecture. Two essential reorderings are possible, which need to be prevented. a) As l_find has no barriers in place between the optimistic read of the key field lf_hash.cc#L117 and the verification of link lf_hash.cc#L124, the processor can reorder the load to happen after the while-loop. In that case, a concurrent thread executing add_to_purgatory on the same node can be scheduled to store NULL at the key field lf_alloc-pin.c#L253 before key is loaded in l_find. b) A node is marked as deleted by a CAS in l_delete lf_hash.cc#L247 and taken off the list with an upfollowing CAS lf_hash.cc#L252. Only if both CAS succeed, the key field is written to by add_to_purgatory. However, due to a missing barrier, the relaxed store of key lf_alloc-pin.c#L253 can be moved ahead of the two CAS operations, which makes the value of the local purgatory list stored by add_to_purgatory visible to all threads operating on the list. As the node is not marked as deleted yet, the same error occurs in l_find. This change three accesses to be atomic. * optimistic read of key in l_find lf_hash.cc#L117 * read of link for verification lf_hash.cc#L124 * write of key in add_to_purgatory lf_alloc-pin.c#L253 Reviewers: Sergei Vojtovich, Sergei Golubchik Fixes: MDEV-23510 / d30c1331a18d875e553f3fcf544997e4f33fb943 --- mysys/lf_alloc-pin.c | 5 +++-- mysys/lf_hash.c | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c index 0dc524be336..880ef44e9ca 100644 --- a/mysys/lf_alloc-pin.c +++ b/mysys/lf_alloc-pin.c @@ -256,8 +256,9 @@ static int ptr_cmp(void **a, void **b) #define add_to_purgatory(PINS, ADDR) \ do \ { \ - *(void **)((char *)(ADDR)+(PINS)->pinbox->free_ptr_offset)= \ - (PINS)->purgatory; \ + my_atomic_storeptr_explicit( \ + (void **)((char *)(ADDR)+(PINS)->pinbox->free_ptr_offset), \ + (PINS)->purgatory, MY_MEMORY_ORDER_RELEASE); \ (PINS)->purgatory= (ADDR); \ (PINS)->purgatory_count++; \ } while (0) diff --git a/mysys/lf_hash.c b/mysys/lf_hash.c index a7553b349de..ca3a377190f 100644 --- a/mysys/lf_hash.c +++ b/mysys/lf_hash.c @@ -111,13 +111,16 @@ retry: cur_hashnr= cursor->curr->hashnr; cur_keylen= cursor->curr->keylen; - cur_key= cursor->curr->key; + cur_key= my_atomic_loadptr_explicit((void **) &cursor->curr->key, + MY_MEMORY_ORDER_ACQUIRE); do { - link= cursor->curr->link; + link= (intptr) my_atomic_loadptr_explicit((void **) &cursor->curr->link, + MY_MEMORY_ORDER_RELAXED); cursor->next= PTR(link); lf_pin(pins, 0, cursor->next); - } while (link != cursor->curr->link && LF_BACKOFF); + } while (link != (intptr) my_atomic_loadptr((void *) &cursor->curr->link) + && LF_BACKOFF); if (!DELETED(link)) { -- cgit v1.2.1 From 17802165a621e5c739e70d3eb427bd1cbaeaba8a Mon Sep 17 00:00:00 2001 From: Martin Beck Date: Wed, 24 Nov 2021 18:46:46 +1100 Subject: MDEV-27088: lf unit tests - cycles insufficient Per bug report, cycles was woefully insufficient to detect any implementation error. --- unittest/mysys/thr_template.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittest/mysys/thr_template.c b/unittest/mysys/thr_template.c index 5f01dfbe055..724fa8036cd 100644 --- a/unittest/mysys/thr_template.c +++ b/unittest/mysys/thr_template.c @@ -60,7 +60,7 @@ int main(int argc __attribute__((unused)), char **argv) pthread_mutex_init(&mutex, 0); -#define CYCLES 3000 +#define CYCLES 30000 #define THREADS 30 diag("N CPUs: %d, atomic ops: %s", my_getncpus(), MY_ATOMIC_MODE); -- cgit v1.2.1 From 214cad8c3b56810574020a5e995d22b804294cf8 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 29 Nov 2021 17:03:21 +0100 Subject: fix ./mtr --manual warning after f5441ef4dac9 --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 809f8794e00..4e00a76422b 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -5128,7 +5128,7 @@ sub mysqld_start ($$) { $mysqld->{'started_opts'}= $extra_opts; my $expect_file= "$opt_vardir/tmp/".$mysqld->name().".expect"; - return $oldexe eq $exe || + return $oldexe eq ($exe || '') || sleep_until_file_created($mysqld->value('pid-file'), $expect_file, $opt_start_timeout, $mysqld->{'proc'}, $warn_seconds); } -- cgit v1.2.1 From 71027eceac31c9f35c94c9893abb072e41867541 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 29 Nov 2021 17:02:31 +0100 Subject: fix srpm builds after fe065f8d90b0 --- cmake/Internal/CPack/CPackRPM.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/Internal/CPack/CPackRPM.cmake b/cmake/Internal/CPack/CPackRPM.cmake index a1040a0161f..d16965be1e9 100644 --- a/cmake/Internal/CPack/CPackRPM.cmake +++ b/cmake/Internal/CPack/CPackRPM.cmake @@ -18,7 +18,8 @@ macro(restore WHAT) endmacro() foreach (WHAT SUMMARY DESCRIPTION) - if(NOT CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_${WHAT}) + if(CPACK_RPM_PACKAGE_COMPONENT AND + NOT CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_${WHAT}) message(FATAL_ERROR "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_${WHAT} is not defined") endif() endforeach() -- cgit v1.2.1