summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-05-18 17:30:02 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2020-05-18 17:30:02 +0300
commit23047d3ed42eacb5eaa5475a8fa4161550d01c52 (patch)
treee723067fea7cfb663ef7e4777e29ffd7dcd2905d
parentf86d97c3fee0127d83c009e448f419ac857c72c7 (diff)
parentfaf6d0ef3f9323c6d24f8cdb6533ed23d1a6bb40 (diff)
downloadmariadb-git-23047d3ed42eacb5eaa5475a8fa4161550d01c52.tar.gz
Merge 10.4 into 10.5
-rw-r--r--client/mysql.cc19
-rw-r--r--client/mysqltest.cc9
-rw-r--r--include/my_atomic.h45
-rw-r--r--include/my_valgrind.h21
-rw-r--r--include/span.h62
m---------libmariadb0
-rw-r--r--mysql-test/main/custom_aggregate_functions.result36
-rw-r--r--mysql-test/main/custom_aggregate_functions.test38
-rw-r--r--mysql-test/main/func_math.result738
-rw-r--r--mysql-test/main/func_math.test61
-rw-r--r--mysql-test/main/subselect4.result33
-rw-r--r--mysql-test/main/subselect4.test25
-rw-r--r--mysql-test/main/table_value_constr.result11
-rw-r--r--mysql-test/main/table_value_constr.test13
-rw-r--r--mysql-test/main/udf.result6
-rw-r--r--mysql-test/main/udf.test2
-rw-r--r--mysql-test/suite/encryption/r/tempfiles_encrypted.result18
-rw-r--r--mysql-test/suite/encryption/t/innodb_encryption_tables.test2
-rw-r--r--mysql-test/suite/encryption/t/tempfiles_encrypted.opt1
-rw-r--r--mysql-test/suite/encryption/t/tempfiles_encrypted.test23
-rw-r--r--mysql-test/suite/galera/disabled.def2
-rw-r--r--mysql-test/suite/galera/r/MW-328C.result25
-rw-r--r--mysql-test/suite/galera/t/MW-328A.cnf4
-rw-r--r--mysql-test/suite/galera/t/MW-328B.cnf4
-rw-r--r--mysql-test/suite/galera/t/MW-328C.cnf7
-rw-r--r--mysql-test/suite/galera/t/MW-328C.test35
-rw-r--r--mysql-test/suite/galera/t/MW-328D.cnf7
-rw-r--r--mysql-test/suite/galera/t/MW-328E.cnf7
-rw-r--r--mysql-test/suite/innodb/r/analyze_table.result18
-rw-r--r--mysql-test/suite/innodb/t/analyze_table.test33
-rw-r--r--mysql-test/suite/innodb/t/xa_recovery_debug.test4
-rw-r--r--mysql-test/suite/parts/inc/partition_auto_increment.inc11
-rw-r--r--mysql-test/suite/parts/r/partition_auto_increment_innodb.result8
-rw-r--r--mysql-test/suite/parts/r/partition_auto_increment_maria.result8
-rw-r--r--mysql-test/suite/parts/r/partition_auto_increment_memory.result8
-rw-r--r--mysql-test/suite/parts/r/partition_auto_increment_myisam.result8
-rw-r--r--mysql-test/suite/rpl/r/rpl_failed_drop_tbl_binlog.result32
-rw-r--r--mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.test69
-rw-r--r--mysql-test/suite/vcol/r/vcol_misc.result52
-rw-r--r--mysql-test/suite/vcol/t/vcol_misc.test61
-rw-r--r--mysql-test/unstable-tests1
-rw-r--r--mysys/mf_iocache.c7
-rw-r--r--sql/field.cc11
-rw-r--r--sql/field.h16
-rw-r--r--sql/item.h26
-rw-r--r--sql/item_func.cc11
-rw-r--r--sql/item_subselect.cc9
-rw-r--r--sql/item_sum.cc8
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sql_base.cc26
-rw-r--r--sql/sql_repl.cc5
-rw-r--r--sql/sql_statistics.cc1
-rw-r--r--sql/sql_tvc.cc9
-rw-r--r--sql/table.cc6
-rw-r--r--storage/innobase/btr/btr0btr.cc16
-rw-r--r--storage/innobase/btr/btr0cur.cc2
-rw-r--r--storage/innobase/btr/btr0sea.cc217
-rw-r--r--storage/innobase/buf/buf0buf.cc26
-rw-r--r--storage/innobase/buf/buf0lru.cc151
-rw-r--r--storage/innobase/dict/dict0crea.cc7
-rw-r--r--storage/innobase/dict/dict0dict.cc153
-rw-r--r--storage/innobase/dict/dict0mem.cc7
-rw-r--r--storage/innobase/dict/dict0stats.cc9
-rw-r--r--storage/innobase/fil/fil0pagecompress.cc1
-rw-r--r--storage/innobase/fsp/fsp0fsp.cc97
-rw-r--r--storage/innobase/handler/handler0alter.cc14
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc2
-rw-r--r--storage/innobase/include/btr0pcur.h2
-rw-r--r--storage/innobase/include/btr0pcur.ic2
-rw-r--r--storage/innobase/include/btr0sea.h21
-rw-r--r--storage/innobase/include/btr0sea.ic2
-rw-r--r--storage/innobase/include/buf0lru.h11
-rw-r--r--storage/innobase/include/dict0mem.h60
-rw-r--r--storage/innobase/include/fsp0fsp.h42
-rw-r--r--storage/innobase/include/sync0rw.h10
-rw-r--r--storage/innobase/include/sync0rw.ic51
-rw-r--r--storage/innobase/row/row0ftsort.cc7
-rw-r--r--storage/innobase/row/row0import.cc14
-rw-r--r--storage/innobase/row/row0merge.cc10
-rw-r--r--storage/innobase/row/row0mysql.cc32
-rw-r--r--storage/innobase/row/row0purge.cc1
-rw-r--r--storage/innobase/row/row0vers.cc2
-rw-r--r--storage/innobase/srv/srv0srv.cc1
-rw-r--r--storage/innobase/sync/sync0arr.cc10
-rw-r--r--storage/innobase/sync/sync0rw.cc75
-rw-r--r--storage/innobase/trx/trx0purge.cc4
-rw-r--r--storage/innobase/trx/trx0undo.cc4
-rw-r--r--storage/tokudb/mysql-test/tokudb_parts/r/partition_auto_increment_tokudb.result8
89 files changed, 1905 insertions, 872 deletions
diff --git a/client/mysql.cc b/client/mysql.cc
index 99b4efc7012..bb2b98b7d64 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -92,6 +92,9 @@ extern "C" {
#include <conio.h>
#else
#include <readline.h>
+#if !defined(USE_LIBEDIT_INTERFACE)
+#include <history.h>
+#endif
#define HAVE_READLINE
#define USE_POPEN
#endif
@@ -1043,22 +1046,6 @@ static const char *embedded_server_groups[]=
{ "server", "embedded", "mysql_SERVER", "mariadb_SERVER", 0 };
#ifdef HAVE_READLINE
-/*
- HIST_ENTRY is defined for libedit, but not for the real readline
- Need to redefine it for real readline to find it
-*/
-#if !defined(HAVE_HIST_ENTRY)
-typedef struct _hist_entry {
- const char *line;
- const char *data;
-} HIST_ENTRY;
-#endif
-
-extern "C" int add_history(const char *command); /* From readline directory */
-extern "C" int read_history(const char *command);
-extern "C" int write_history(const char *command);
-extern "C" HIST_ENTRY *history_get(int num);
-extern "C" int history_length;
static int not_in_history(const char *line);
static void initialize_readline ();
static void fix_history(String *final_command);
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index 11842bc581e..55c4a66a89d 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -587,9 +587,10 @@ ATTRIBUTE_NORETURN
static void cleanup_and_exit(int exit_code);
ATTRIBUTE_NORETURN
-void really_die(const char *msg);
+static void really_die(const char *msg);
void report_or_die(const char *fmt, ...);
-ATTRIBUTE_NORETURN void die(const char *fmt, ...);
+ATTRIBUTE_NORETURN
+static void die(const char *fmt, ...);
static void make_error_message(char *buf, size_t len, const char *fmt, va_list args);
ATTRIBUTE_NORETURN ATTRIBUTE_FORMAT(printf, 1, 2)
void abort_not_supported_test(const char *fmt, ...);
@@ -1540,7 +1541,7 @@ static void make_error_message(char *buf, size_t len, const char *fmt, va_list a
s+= my_snprintf(s, end -s, "\n");
}
-void die(const char *fmt, ...)
+static void die(const char *fmt, ...)
{
char buff[DIE_BUFF_SIZE];
va_list args;
@@ -1549,7 +1550,7 @@ void die(const char *fmt, ...)
really_die(buff);
}
-void really_die(const char *msg)
+static void really_die(const char *msg)
{
static int dying= 0;
fflush(stdout);
diff --git a/include/my_atomic.h b/include/my_atomic.h
index 1c54c24d455..88f6746ba3d 100644
--- a/include/my_atomic.h
+++ b/include/my_atomic.h
@@ -2,6 +2,7 @@
#define MY_ATOMIC_INCLUDED
/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2018, 2020, MariaDB
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
@@ -169,4 +170,48 @@
my_atomic_casptr((P), (E), (D))
#endif
+#ifdef __cplusplus
+#include <atomic>
+/**
+ A wrapper for std::atomic, defaulting to std::memory_order_relaxed.
+
+ When it comes to atomic loads or stores at std::memory_order_relaxed
+ on IA-32 or AMD64, this wrapper is only introducing some constraints
+ to the C++ compiler, to prevent some optimizations of loads or
+ stores.
+
+ On POWER and ARM, atomic loads and stores involve different instructions
+ from normal loads and stores and will thus incur some overhead.
+
+ Because atomic read-modify-write operations will always incur
+ overhead, we intentionally do not define
+ operator++(), operator--(), operator+=(), operator-=(), or similar,
+ to make the overhead stand out in the users of this code.
+*/
+template <typename Type> class Atomic_relaxed
+{
+ std::atomic<Type> m;
+public:
+ Atomic_relaxed(const Atomic_relaxed<Type> &rhs)
+ { m.store(rhs, std::memory_order_relaxed); }
+ Atomic_relaxed(Type val) : m(val) {}
+ Atomic_relaxed() {}
+
+ operator Type() const { return m.load(std::memory_order_relaxed); }
+ Type operator=(const Type val)
+ { m.store(val, std::memory_order_relaxed); return val; }
+ Type operator=(const Atomic_relaxed<Type> &rhs) { return *this= Type{rhs}; }
+ Type fetch_add(const Type i, std::memory_order o= std::memory_order_relaxed)
+ { return m.fetch_add(i, o); }
+ Type fetch_sub(const Type i, std::memory_order o= std::memory_order_relaxed)
+ { return m.fetch_sub(i, o); }
+ bool compare_exchange_strong(Type& i1, const Type i2,
+ std::memory_order o1= std::memory_order_relaxed,
+ std::memory_order o2= std::memory_order_relaxed)
+ { return m.compare_exchange_strong(i1, i2, o1, o2); }
+ Type exchange(const Type i, std::memory_order o= std::memory_order_relaxed)
+ { return m.exchange(i, o); }
+};
+#endif /* __cplusplus */
+
#endif /* MY_ATOMIC_INCLUDED */
diff --git a/include/my_valgrind.h b/include/my_valgrind.h
index 2c623a044f4..8aaa261fd5b 100644
--- a/include/my_valgrind.h
+++ b/include/my_valgrind.h
@@ -32,6 +32,7 @@
#if defined(HAVE_VALGRIND_MEMCHECK_H) && defined(HAVE_valgrind)
# include <valgrind/memcheck.h>
+# define HAVE_valgrind_or_MSAN
# define MEM_UNDEFINED(a,len) VALGRIND_MAKE_MEM_UNDEFINED(a,len)
# define MEM_MAKE_DEFINED(a,len) VALGRIND_MAKE_MEM_DEFINED(a,len)
# define MEM_NOACCESS(a,len) VALGRIND_MAKE_MEM_NOACCESS(a,len)
@@ -50,6 +51,7 @@ https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning */
# define REDZONE_SIZE 8
#elif __has_feature(memory_sanitizer)
# include <sanitizer/msan_interface.h>
+# define HAVE_valgrind_or_MSAN
# define MEM_UNDEFINED(a,len) __msan_allocated_memory(a,len)
# define MEM_MAKE_DEFINED(a,len) __msan_unpoison(a,len)
# define MEM_NOACCESS(a,len) ((void) 0)
@@ -65,16 +67,19 @@ https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning */
# define REDZONE_SIZE 0
#endif /* HAVE_VALGRIND_MEMCHECK_H */
-#if defined(TRASH_FREED_MEMORY)
-/* NOTE: Do not invoke TRASH_FILL directly! Use TRASH_ALLOC or TRASH_FREE.
-
-The MEM_UNDEFINED() call before memset() is for canceling the effect
-of any previous MEM_NOACCESS(). We must invoke MEM_UNDEFINED() after
-writing the dummy pattern, unless MEM_NOACCESS() is going to be invoked.
-On AddressSanitizer, the MEM_UNDEFINED() in TRASH_ALLOC() has no effect. */
+#ifdef TRASH_FREED_MEMORY
+/*
+ TRASH_FILL() has to call MEM_UNDEFINED() to cancel any effect of TRASH_FREE().
+ This can happen in the case one does
+ TRASH_ALLOC(A,B) ; TRASH_FREE(A,B) ; TRASH_ALLOC(A,B)
+ to reuse the same memory in an internal memory allocator like MEM_ROOT.
+ For my_malloc() and safemalloc() the extra MEM_UNDEFINED is bit of an
+ overkill.
+ TRASH_FILL() is an internal function and should not be used externally.
+*/
#define TRASH_FILL(A,B,C) do { const size_t trash_tmp= (B); MEM_UNDEFINED(A, trash_tmp); memset(A, C, trash_tmp); } while (0)
#else
-#define TRASH_FILL(A,B,C) while (0)
+#define TRASH_FILL(A,B,C) do { MEM_UNDEFINED((A), (B)); } while (0)
#endif
/** Note that some memory became allocated or uninitialized. */
#define TRASH_ALLOC(A,B) do { TRASH_FILL(A,B,0xA5); MEM_UNDEFINED(A,B); } while(0)
diff --git a/include/span.h b/include/span.h
index 0ed0158088c..0e8516933c6 100644
--- a/include/span.h
+++ b/include/span.h
@@ -24,11 +24,33 @@ this program; if not, write to the Free Software Foundation, Inc.,
namespace st_
{
+namespace detail
+{
+
+template <class T> struct remove_cv
+{
+ typedef T type;
+};
+template <class T> struct remove_cv<const T>
+{
+ typedef T type;
+};
+template <class T> struct remove_cv<volatile T>
+{
+ typedef T type;
+};
+template <class T> struct remove_cv<const volatile T>
+{
+ typedef T type;
+};
+
+} // namespace detail
+
template <class ElementType> class span
{
public:
typedef ElementType element_type;
- typedef ElementType value_type;
+ typedef typename detail::remove_cv<ElementType>::type value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef element_type *pointer;
@@ -38,7 +60,6 @@ public:
typedef pointer iterator;
typedef const_pointer const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
span() : data_(NULL), size_(0) {}
@@ -64,73 +85,72 @@ public:
span &operator=(const span &other)
{
- data_= other.data_;
- size_= other.size_;
+ data_= other.data();
+ size_= other.size();
return *this;
}
template <size_t Count> span<element_type> first() const
{
assert(!empty());
- return span(data_, 1);
+ return span(data(), 1);
}
template <size_t Count> span<element_type> last() const
{
assert(!empty());
- return span(data_ + size() - 1, 1);
+ return span(data() + size() - 1, 1);
}
span<element_type> first(size_type count) const
{
assert(!empty());
- return span(data_, 1);
+ return span(data(), 1);
}
span<element_type> last(size_type count) const
{
assert(!empty());
- return span(data_ + size() - 1, 1);
+ return span(data() + size() - 1, 1);
}
span<element_type> subspan(size_type offset, size_type count) const
{
assert(!empty());
assert(size() >= offset + count);
- return span(data_ + offset, count);
+ return span(data() + offset, count);
}
size_type size() const { return size_; }
- size_type size_bytes() const { return size_ * sizeof(ElementType); }
- bool empty() const __attribute__((warn_unused_result)) { return size_ == 0; }
+ size_type size_bytes() const { return size() * sizeof(ElementType); }
+ bool empty() const __attribute__((warn_unused_result))
+ {
+ return size() == 0;
+ }
reference operator[](size_type idx) const
{
assert(size() > idx);
- return data_[idx];
+ return data()[idx];
}
reference front() const
{
assert(!empty());
- return data_[0];
+ return data()[0];
}
reference back() const
{
assert(!empty());
- return data_[size() - 1];
- }
- pointer data() const
- {
- assert(!empty());
- return data_;
+ return data()[size() - 1];
}
+ pointer data() const { return data_; }
iterator begin() const { return data_; }
iterator end() const { return data_ + size_; }
reverse_iterator rbegin() const
{
- return std::reverse_iterator<iterator>(std::advance(end(), -1));
+ return std::reverse_iterator<iterator>(end());
}
reverse_iterator rend() const
{
- return std::reverse_iterator<iterator>(std::advance(begin(), -1));
+ return std::reverse_iterator<iterator>(begin());
}
private:
diff --git a/libmariadb b/libmariadb
-Subproject 2759b87d72926b7c9b5426437a7c8dd15ff5794
+Subproject cdfecebc9932a0dd5516c10505bfe78d79132e7
diff --git a/mysql-test/main/custom_aggregate_functions.result b/mysql-test/main/custom_aggregate_functions.result
index b98954b920e..884bd8b555f 100644
--- a/mysql-test/main/custom_aggregate_functions.result
+++ b/mysql-test/main/custom_aggregate_functions.result
@@ -1154,6 +1154,41 @@ NULL 8
drop function agg_sum;
drop table t1;
#
+# User defined aggregate functions not working correctly when the schema is changed
+#
+CREATE SCHEMA IF NOT EXISTS common_schema;
+CREATE SCHEMA IF NOT EXISTS another_schema;
+DROP FUNCTION IF EXISTS common_schema.add_ints |
+Warnings:
+Note 1305 FUNCTION common_schema.add_ints does not exist
+CREATE FUNCTION common_schema.add_ints(int_1 INT, int_2 INT) RETURNS INT NO SQL
+BEGIN
+RETURN int_1 + int_2;
+END |
+DROP FUNCTION IF EXISTS common_schema.sum_ints |
+Warnings:
+Note 1305 FUNCTION common_schema.sum_ints does not exist
+CREATE AGGREGATE FUNCTION common_schema.sum_ints(int_val INT) RETURNS INT
+BEGIN
+DECLARE result INT DEFAULT 0;
+DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN result;
+LOOP FETCH GROUP NEXT ROW;
+SET result = common_schema.add_ints(result, int_val);
+END LOOP;
+END |
+use common_schema;
+SELECT common_schema.sum_ints(seq) FROM (SELECT 1 seq UNION ALL SELECT 2) t;
+common_schema.sum_ints(seq)
+3
+USE another_schema;
+SELECT common_schema.sum_ints(seq) FROM (SELECT 1 seq UNION ALL SELECT 2) t;
+common_schema.sum_ints(seq)
+3
+drop database common_schema;
+drop database another_schema;
+USE test;
+# End of 10.3 tests
+#
# MDEV-18813 PROCEDURE and anonymous blocks silently ignore FETCH GROUP NEXT ROW
#
CREATE PROCEDURE p1()
@@ -1186,3 +1221,4 @@ STARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH
ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK
DO FETCH GROUP NEXT ROW;
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
+# End of 10.4 tests
diff --git a/mysql-test/main/custom_aggregate_functions.test b/mysql-test/main/custom_aggregate_functions.test
index a10ea44af60..4b6129b5974 100644
--- a/mysql-test/main/custom_aggregate_functions.test
+++ b/mysql-test/main/custom_aggregate_functions.test
@@ -966,6 +966,42 @@ select i, sum(i) from t1 group by i with rollup;
drop function agg_sum;
drop table t1;
+--echo #
+--echo # User defined aggregate functions not working correctly when the schema is changed
+--echo #
+
+CREATE SCHEMA IF NOT EXISTS common_schema;
+CREATE SCHEMA IF NOT EXISTS another_schema;
+DELIMITER |;
+DROP FUNCTION IF EXISTS common_schema.add_ints |
+CREATE FUNCTION common_schema.add_ints(int_1 INT, int_2 INT) RETURNS INT NO SQL
+BEGIN
+ RETURN int_1 + int_2;
+END |
+DROP FUNCTION IF EXISTS common_schema.sum_ints |
+CREATE AGGREGATE FUNCTION common_schema.sum_ints(int_val INT) RETURNS INT
+BEGIN
+ DECLARE result INT DEFAULT 0;
+ DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN result;
+ LOOP FETCH GROUP NEXT ROW;
+ SET result = common_schema.add_ints(result, int_val);
+ END LOOP;
+END |
+
+DELIMITER ;|
+
+use common_schema;
+SELECT common_schema.sum_ints(seq) FROM (SELECT 1 seq UNION ALL SELECT 2) t;
+
+USE another_schema;
+SELECT common_schema.sum_ints(seq) FROM (SELECT 1 seq UNION ALL SELECT 2) t;
+
+drop database common_schema;
+drop database another_schema;
+
+USE test;
+
+--echo # End of 10.3 tests
--echo #
--echo # MDEV-18813 PROCEDURE and anonymous blocks silently ignore FETCH GROUP NEXT ROW
@@ -1016,3 +1052,5 @@ CREATE EVENT ev1
STARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH
ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK
DO FETCH GROUP NEXT ROW;
+
+--echo # End of 10.4 tests
diff --git a/mysql-test/main/func_math.result b/mysql-test/main/func_math.result
index 50936e10cb6..6ed80275cbb 100644
--- a/mysql-test/main/func_math.result
+++ b/mysql-test/main/func_math.result
@@ -1015,6 +1015,742 @@ SELECT -9223372036854775808 MOD -9223372036854775808;
-9223372036854775808 MOD -9223372036854775808
0
#
+# MDEV-22502 MDB crashes in CREATE TABLE AS SELECT when the precision of returning type = 0
+#
+CREATE TABLE t1 (d decimal(5,5));
+INSERT INTO t1 VALUES (0.55555);
+SELECT TRUNCATE(d,0) FROM t1;
+TRUNCATE(d,0)
+0
+CREATE TABLE t2 AS SELECT TRUNCATE(d,0) FROM t1;
+SELECT * FROM t2;
+TRUNCATE(d,0)
+0
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `TRUNCATE(d,0)` decimal(1,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1, t2;
+#
+# MDEV-22503 MDB limits DECIMAL column precision to 16 doing CTAS with floor/ceil over DECIMAL(X,Y) where X > 16
+#
+CREATE TABLE t44 (d1 decimal(38,0) DEFAULT NULL);
+INSERT INTO t44 VALUES (12345678901234567890123456789012345678);
+SELECT FLOOR(d1) FROM t44;
+FLOOR(d1)
+12345678901234567890123456789012345678
+CREATE TABLE t45 AS SELECT FLOOR(d1) FROM t44;
+SELECT * FROM t45;
+FLOOR(d1)
+12345678901234567890123456789012345678
+SHOW CREATE TABLE t45;
+Table Create Table
+t45 CREATE TABLE `t45` (
+ `FLOOR(d1)` decimal(38,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t44, t45;
+CREATE PROCEDURE p1(prec INT, scale INT)
+BEGIN
+DECLARE maxval VARCHAR(128) DEFAULT '';
+SET @type= CONCAT('DECIMAL(', prec, ',', scale,')');
+SET @stmt= CONCAT('CREATE TABLE t1 (a ', @type, ',b ', @type, 'unsigned)');
+PREPARE stmt FROM @stmt;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+SET maxval= CONCAT(REPEAT('9', prec-scale), '.', REPEAT('9',scale));
+INSERT INTO t1 VALUES (maxval, maxval);
+CREATE TABLE t2 AS SELECT a, b, FLOOR(a) AS fa, FLOOR(b) AS fb FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t1, t2;
+END;
+$$
+CREATE PROCEDURE p2(prec INT)
+BEGIN
+DECLARE scale INT DEFAULT 0;
+WHILE scale < prec AND scale <= 30 DO
+CALL p1(prec, scale);
+SET scale= scale + 1;
+END WHILE;
+END;
+$$
+CALL p2(38);
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,0) DEFAULT NULL,
+ `b` decimal(38,0) unsigned DEFAULT NULL,
+ `fa` decimal(38,0) DEFAULT NULL,
+ `fb` decimal(38,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999999999999999999999
+b 99999999999999999999999999999999999999
+fa 99999999999999999999999999999999999999
+fb 99999999999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,1) DEFAULT NULL,
+ `b` decimal(38,1) unsigned DEFAULT NULL,
+ `fa` decimal(37,0) DEFAULT NULL,
+ `fb` decimal(37,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999999999999999999999.9
+b 9999999999999999999999999999999999999.9
+fa 9999999999999999999999999999999999999
+fb 9999999999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,2) DEFAULT NULL,
+ `b` decimal(38,2) unsigned DEFAULT NULL,
+ `fa` decimal(36,0) DEFAULT NULL,
+ `fb` decimal(36,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999999999999999999.99
+b 999999999999999999999999999999999999.99
+fa 999999999999999999999999999999999999
+fb 999999999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,3) DEFAULT NULL,
+ `b` decimal(38,3) unsigned DEFAULT NULL,
+ `fa` decimal(35,0) DEFAULT NULL,
+ `fb` decimal(35,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999999999999999999.999
+b 99999999999999999999999999999999999.999
+fa 99999999999999999999999999999999999
+fb 99999999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,4) DEFAULT NULL,
+ `b` decimal(38,4) unsigned DEFAULT NULL,
+ `fa` decimal(34,0) DEFAULT NULL,
+ `fb` decimal(34,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999999999999999999.9999
+b 9999999999999999999999999999999999.9999
+fa 9999999999999999999999999999999999
+fb 9999999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,5) DEFAULT NULL,
+ `b` decimal(38,5) unsigned DEFAULT NULL,
+ `fa` decimal(33,0) DEFAULT NULL,
+ `fb` decimal(33,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999999999999999.99999
+b 999999999999999999999999999999999.99999
+fa 999999999999999999999999999999999
+fb 999999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,6) DEFAULT NULL,
+ `b` decimal(38,6) unsigned DEFAULT NULL,
+ `fa` decimal(32,0) DEFAULT NULL,
+ `fb` decimal(32,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999999999999999.999999
+b 99999999999999999999999999999999.999999
+fa 99999999999999999999999999999999
+fb 99999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,7) DEFAULT NULL,
+ `b` decimal(38,7) unsigned DEFAULT NULL,
+ `fa` decimal(31,0) DEFAULT NULL,
+ `fb` decimal(31,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999999999999999.9999999
+b 9999999999999999999999999999999.9999999
+fa 9999999999999999999999999999999
+fb 9999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,8) DEFAULT NULL,
+ `b` decimal(38,8) unsigned DEFAULT NULL,
+ `fa` decimal(30,0) DEFAULT NULL,
+ `fb` decimal(30,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999999999999.99999999
+b 999999999999999999999999999999.99999999
+fa 999999999999999999999999999999
+fb 999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,9) DEFAULT NULL,
+ `b` decimal(38,9) unsigned DEFAULT NULL,
+ `fa` decimal(29,0) DEFAULT NULL,
+ `fb` decimal(29,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999999999999.999999999
+b 99999999999999999999999999999.999999999
+fa 99999999999999999999999999999
+fb 99999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,10) DEFAULT NULL,
+ `b` decimal(38,10) unsigned DEFAULT NULL,
+ `fa` decimal(28,0) DEFAULT NULL,
+ `fb` decimal(28,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999999999999.9999999999
+b 9999999999999999999999999999.9999999999
+fa 9999999999999999999999999999
+fb 9999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,11) DEFAULT NULL,
+ `b` decimal(38,11) unsigned DEFAULT NULL,
+ `fa` decimal(27,0) DEFAULT NULL,
+ `fb` decimal(27,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999999999.99999999999
+b 999999999999999999999999999.99999999999
+fa 999999999999999999999999999
+fb 999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,12) DEFAULT NULL,
+ `b` decimal(38,12) unsigned DEFAULT NULL,
+ `fa` decimal(26,0) DEFAULT NULL,
+ `fb` decimal(26,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999999999.999999999999
+b 99999999999999999999999999.999999999999
+fa 99999999999999999999999999
+fb 99999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,13) DEFAULT NULL,
+ `b` decimal(38,13) unsigned DEFAULT NULL,
+ `fa` decimal(25,0) DEFAULT NULL,
+ `fb` decimal(25,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999999999.9999999999999
+b 9999999999999999999999999.9999999999999
+fa 9999999999999999999999999
+fb 9999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,14) DEFAULT NULL,
+ `b` decimal(38,14) unsigned DEFAULT NULL,
+ `fa` decimal(24,0) DEFAULT NULL,
+ `fb` decimal(24,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999999.99999999999999
+b 999999999999999999999999.99999999999999
+fa 999999999999999999999999
+fb 999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,15) DEFAULT NULL,
+ `b` decimal(38,15) unsigned DEFAULT NULL,
+ `fa` decimal(23,0) DEFAULT NULL,
+ `fb` decimal(23,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999999.999999999999999
+b 99999999999999999999999.999999999999999
+fa 99999999999999999999999
+fb 99999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,16) DEFAULT NULL,
+ `b` decimal(38,16) unsigned DEFAULT NULL,
+ `fa` decimal(22,0) DEFAULT NULL,
+ `fb` decimal(22,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999999.9999999999999999
+b 9999999999999999999999.9999999999999999
+fa 9999999999999999999999
+fb 9999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,17) DEFAULT NULL,
+ `b` decimal(38,17) unsigned DEFAULT NULL,
+ `fa` decimal(21,0) DEFAULT NULL,
+ `fb` decimal(21,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999.99999999999999999
+b 999999999999999999999.99999999999999999
+fa 999999999999999999999
+fb 999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,18) DEFAULT NULL,
+ `b` decimal(38,18) unsigned DEFAULT NULL,
+ `fa` decimal(20,0) DEFAULT NULL,
+ `fb` decimal(20,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999.999999999999999999
+b 99999999999999999999.999999999999999999
+fa 99999999999999999999
+fb 99999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,19) DEFAULT NULL,
+ `b` decimal(38,19) unsigned DEFAULT NULL,
+ `fa` decimal(19,0) DEFAULT NULL,
+ `fb` decimal(19,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999.9999999999999999999
+b 9999999999999999999.9999999999999999999
+fa 9999999999999999999
+fb 9999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,20) DEFAULT NULL,
+ `b` decimal(38,20) unsigned DEFAULT NULL,
+ `fa` decimal(18,0) DEFAULT NULL,
+ `fb` bigint(17) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999.99999999999999999999
+b 999999999999999999.99999999999999999999
+fa 999999999999999999
+fb 999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,21) DEFAULT NULL,
+ `b` decimal(38,21) unsigned DEFAULT NULL,
+ `fa` bigint(17) DEFAULT NULL,
+ `fb` bigint(17) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999.999999999999999999999
+b 99999999999999999.999999999999999999999
+fa 99999999999999999
+fb 99999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,22) DEFAULT NULL,
+ `b` decimal(38,22) unsigned DEFAULT NULL,
+ `fa` bigint(17) DEFAULT NULL,
+ `fb` bigint(17) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999.9999999999999999999999
+b 9999999999999999.9999999999999999999999
+fa 9999999999999999
+fb 9999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,23) DEFAULT NULL,
+ `b` decimal(38,23) unsigned DEFAULT NULL,
+ `fa` bigint(17) DEFAULT NULL,
+ `fb` bigint(17) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999.99999999999999999999999
+b 999999999999999.99999999999999999999999
+fa 999999999999999
+fb 999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,24) DEFAULT NULL,
+ `b` decimal(38,24) unsigned DEFAULT NULL,
+ `fa` bigint(17) DEFAULT NULL,
+ `fb` bigint(16) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999.999999999999999999999999
+b 99999999999999.999999999999999999999999
+fa 99999999999999
+fb 99999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,25) DEFAULT NULL,
+ `b` decimal(38,25) unsigned DEFAULT NULL,
+ `fa` bigint(16) DEFAULT NULL,
+ `fb` bigint(15) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999.9999999999999999999999999
+b 9999999999999.9999999999999999999999999
+fa 9999999999999
+fb 9999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,26) DEFAULT NULL,
+ `b` decimal(38,26) unsigned DEFAULT NULL,
+ `fa` bigint(15) DEFAULT NULL,
+ `fb` bigint(14) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999.99999999999999999999999999
+b 999999999999.99999999999999999999999999
+fa 999999999999
+fb 999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,27) DEFAULT NULL,
+ `b` decimal(38,27) unsigned DEFAULT NULL,
+ `fa` bigint(14) DEFAULT NULL,
+ `fb` bigint(13) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999.999999999999999999999999999
+b 99999999999.999999999999999999999999999
+fa 99999999999
+fb 99999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,28) DEFAULT NULL,
+ `b` decimal(38,28) unsigned DEFAULT NULL,
+ `fa` bigint(13) DEFAULT NULL,
+ `fb` bigint(12) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999.9999999999999999999999999999
+b 9999999999.9999999999999999999999999999
+fa 9999999999
+fb 9999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,29) DEFAULT NULL,
+ `b` decimal(38,29) unsigned DEFAULT NULL,
+ `fa` bigint(12) DEFAULT NULL,
+ `fb` bigint(11) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999.99999999999999999999999999999
+b 999999999.99999999999999999999999999999
+fa 999999999
+fb 999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(38,30) DEFAULT NULL,
+ `b` decimal(38,30) unsigned DEFAULT NULL,
+ `fa` bigint(11) DEFAULT NULL,
+ `fb` bigint(10) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999.999999999999999999999999999999
+b 99999999.999999999999999999999999999999
+fa 99999999
+fb 99999999
+CALL p2(30);
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,0) DEFAULT NULL,
+ `b` decimal(30,0) unsigned DEFAULT NULL,
+ `fa` decimal(30,0) DEFAULT NULL,
+ `fb` decimal(31,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999999999999
+b 999999999999999999999999999999
+fa 999999999999999999999999999999
+fb 999999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,1) DEFAULT NULL,
+ `b` decimal(30,1) unsigned DEFAULT NULL,
+ `fa` decimal(29,0) DEFAULT NULL,
+ `fb` decimal(30,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999999999999.9
+b 99999999999999999999999999999.9
+fa 99999999999999999999999999999
+fb 99999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,2) DEFAULT NULL,
+ `b` decimal(30,2) unsigned DEFAULT NULL,
+ `fa` decimal(28,0) DEFAULT NULL,
+ `fb` decimal(29,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999999999999.99
+b 9999999999999999999999999999.99
+fa 9999999999999999999999999999
+fb 9999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,3) DEFAULT NULL,
+ `b` decimal(30,3) unsigned DEFAULT NULL,
+ `fa` decimal(27,0) DEFAULT NULL,
+ `fb` decimal(28,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999999999.999
+b 999999999999999999999999999.999
+fa 999999999999999999999999999
+fb 999999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,4) DEFAULT NULL,
+ `b` decimal(30,4) unsigned DEFAULT NULL,
+ `fa` decimal(26,0) DEFAULT NULL,
+ `fb` decimal(27,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999999999.9999
+b 99999999999999999999999999.9999
+fa 99999999999999999999999999
+fb 99999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,5) DEFAULT NULL,
+ `b` decimal(30,5) unsigned DEFAULT NULL,
+ `fa` decimal(25,0) DEFAULT NULL,
+ `fb` decimal(26,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999999999.99999
+b 9999999999999999999999999.99999
+fa 9999999999999999999999999
+fb 9999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,6) DEFAULT NULL,
+ `b` decimal(30,6) unsigned DEFAULT NULL,
+ `fa` decimal(24,0) DEFAULT NULL,
+ `fb` decimal(25,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999999.999999
+b 999999999999999999999999.999999
+fa 999999999999999999999999
+fb 999999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,7) DEFAULT NULL,
+ `b` decimal(30,7) unsigned DEFAULT NULL,
+ `fa` decimal(23,0) DEFAULT NULL,
+ `fb` decimal(24,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999999.9999999
+b 99999999999999999999999.9999999
+fa 99999999999999999999999
+fb 99999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,8) DEFAULT NULL,
+ `b` decimal(30,8) unsigned DEFAULT NULL,
+ `fa` decimal(22,0) DEFAULT NULL,
+ `fb` decimal(23,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999999.99999999
+b 9999999999999999999999.99999999
+fa 9999999999999999999999
+fb 9999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,9) DEFAULT NULL,
+ `b` decimal(30,9) unsigned DEFAULT NULL,
+ `fa` decimal(21,0) DEFAULT NULL,
+ `fb` decimal(22,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999999.999999999
+b 999999999999999999999.999999999
+fa 999999999999999999999
+fb 999999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,10) DEFAULT NULL,
+ `b` decimal(30,10) unsigned DEFAULT NULL,
+ `fa` decimal(20,0) DEFAULT NULL,
+ `fb` decimal(21,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999999.9999999999
+b 99999999999999999999.9999999999
+fa 99999999999999999999
+fb 99999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,11) DEFAULT NULL,
+ `b` decimal(30,11) unsigned DEFAULT NULL,
+ `fa` decimal(19,0) DEFAULT NULL,
+ `fb` decimal(20,0) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999999.99999999999
+b 9999999999999999999.99999999999
+fa 9999999999999999999
+fb 9999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,12) DEFAULT NULL,
+ `b` decimal(30,12) unsigned DEFAULT NULL,
+ `fa` decimal(18,0) DEFAULT NULL,
+ `fb` bigint(17) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999999.999999999999
+b 999999999999999999.999999999999
+fa 999999999999999999
+fb 999999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,13) DEFAULT NULL,
+ `b` decimal(30,13) unsigned DEFAULT NULL,
+ `fa` bigint(17) DEFAULT NULL,
+ `fb` bigint(17) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999999.9999999999999
+b 99999999999999999.9999999999999
+fa 99999999999999999
+fb 99999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,14) DEFAULT NULL,
+ `b` decimal(30,14) unsigned DEFAULT NULL,
+ `fa` bigint(17) DEFAULT NULL,
+ `fb` bigint(17) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999999.99999999999999
+b 9999999999999999.99999999999999
+fa 9999999999999999
+fb 9999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,15) DEFAULT NULL,
+ `b` decimal(30,15) unsigned DEFAULT NULL,
+ `fa` bigint(17) DEFAULT NULL,
+ `fb` bigint(17) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999999.999999999999999
+b 999999999999999.999999999999999
+fa 999999999999999
+fb 999999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,16) DEFAULT NULL,
+ `b` decimal(30,16) unsigned DEFAULT NULL,
+ `fa` bigint(17) DEFAULT NULL,
+ `fb` bigint(16) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999999.9999999999999999
+b 99999999999999.9999999999999999
+fa 99999999999999
+fb 99999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,17) DEFAULT NULL,
+ `b` decimal(30,17) unsigned DEFAULT NULL,
+ `fa` bigint(16) DEFAULT NULL,
+ `fb` bigint(15) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999999.99999999999999999
+b 9999999999999.99999999999999999
+fa 9999999999999
+fb 9999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,18) DEFAULT NULL,
+ `b` decimal(30,18) unsigned DEFAULT NULL,
+ `fa` bigint(15) DEFAULT NULL,
+ `fb` bigint(14) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999999.999999999999999999
+b 999999999999.999999999999999999
+fa 999999999999
+fb 999999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,19) DEFAULT NULL,
+ `b` decimal(30,19) unsigned DEFAULT NULL,
+ `fa` bigint(14) DEFAULT NULL,
+ `fb` bigint(13) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999999.9999999999999999999
+b 99999999999.9999999999999999999
+fa 99999999999
+fb 99999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,20) DEFAULT NULL,
+ `b` decimal(30,20) unsigned DEFAULT NULL,
+ `fa` bigint(13) DEFAULT NULL,
+ `fb` bigint(12) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999999.99999999999999999999
+b 9999999999.99999999999999999999
+fa 9999999999
+fb 9999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,21) DEFAULT NULL,
+ `b` decimal(30,21) unsigned DEFAULT NULL,
+ `fa` bigint(12) DEFAULT NULL,
+ `fb` bigint(11) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999999.999999999999999999999
+b 999999999.999999999999999999999
+fa 999999999
+fb 999999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,22) DEFAULT NULL,
+ `b` decimal(30,22) unsigned DEFAULT NULL,
+ `fa` bigint(11) DEFAULT NULL,
+ `fb` bigint(10) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999999.9999999999999999999999
+b 99999999.9999999999999999999999
+fa 99999999
+fb 99999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,23) DEFAULT NULL,
+ `b` decimal(30,23) unsigned DEFAULT NULL,
+ `fa` bigint(10) DEFAULT NULL,
+ `fb` int(9) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999999.99999999999999999999999
+b 9999999.99999999999999999999999
+fa 9999999
+fb 9999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,24) DEFAULT NULL,
+ `b` decimal(30,24) unsigned DEFAULT NULL,
+ `fa` int(9) DEFAULT NULL,
+ `fb` int(8) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999999.999999999999999999999999
+b 999999.999999999999999999999999
+fa 999999
+fb 999999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,25) DEFAULT NULL,
+ `b` decimal(30,25) unsigned DEFAULT NULL,
+ `fa` int(8) DEFAULT NULL,
+ `fb` int(7) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99999.9999999999999999999999999
+b 99999.9999999999999999999999999
+fa 99999
+fb 99999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,26) DEFAULT NULL,
+ `b` decimal(30,26) unsigned DEFAULT NULL,
+ `fa` int(7) DEFAULT NULL,
+ `fb` int(6) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9999.99999999999999999999999999
+b 9999.99999999999999999999999999
+fa 9999
+fb 9999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,27) DEFAULT NULL,
+ `b` decimal(30,27) unsigned DEFAULT NULL,
+ `fa` int(6) DEFAULT NULL,
+ `fb` int(5) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 999.999999999999999999999999999
+b 999.999999999999999999999999999
+fa 999
+fb 999
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,28) DEFAULT NULL,
+ `b` decimal(30,28) unsigned DEFAULT NULL,
+ `fa` int(5) DEFAULT NULL,
+ `fb` int(4) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 99.9999999999999999999999999999
+b 99.9999999999999999999999999999
+fa 99
+fb 99
+Table t2
+Create Table CREATE TABLE `t2` (
+ `a` decimal(30,29) DEFAULT NULL,
+ `b` decimal(30,29) unsigned DEFAULT NULL,
+ `fa` int(4) DEFAULT NULL,
+ `fb` int(3) unsigned DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+a 9.99999999999999999999999999999
+b 9.99999999999999999999999999999
+fa 9
+fb 9
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+#
# End of 10.1 tests
#
#
@@ -1466,7 +2202,7 @@ SET @val = 'a';
EXECUTE stmt1 USING @val;
CRC32(?)
3904355907
-DEALLOCATE PREPARE stmt;
+DEALLOCATE PREPARE stmt1;
SET NAMES utf8;
CREATE TABLE t1 (a TEXT) CHARACTER SET = utf8;
LOAD DATA INFILE '../../std_data/loaddata_utf8.dat' INTO TABLE t1 CHARACTER SET utf8;
diff --git a/mysql-test/main/func_math.test b/mysql-test/main/func_math.test
index 37f63bd103c..38c930fb927 100644
--- a/mysql-test/main/func_math.test
+++ b/mysql-test/main/func_math.test
@@ -715,6 +715,65 @@ SELECT 9223372036854775808 MOD -9223372036854775808;
SELECT -9223372036854775808 MOD 9223372036854775808;
SELECT -9223372036854775808 MOD -9223372036854775808;
+--echo #
+--echo # MDEV-22502 MDB crashes in CREATE TABLE AS SELECT when the precision of returning type = 0
+--echo #
+
+CREATE TABLE t1 (d decimal(5,5));
+INSERT INTO t1 VALUES (0.55555);
+SELECT TRUNCATE(d,0) FROM t1;
+CREATE TABLE t2 AS SELECT TRUNCATE(d,0) FROM t1;
+SELECT * FROM t2;
+SHOW CREATE TABLE t2;
+DROP TABLE t1, t2;
+
+
+--echo #
+--echo # MDEV-22503 MDB limits DECIMAL column precision to 16 doing CTAS with floor/ceil over DECIMAL(X,Y) where X > 16
+--echo #
+
+CREATE TABLE t44 (d1 decimal(38,0) DEFAULT NULL);
+INSERT INTO t44 VALUES (12345678901234567890123456789012345678);
+SELECT FLOOR(d1) FROM t44;
+CREATE TABLE t45 AS SELECT FLOOR(d1) FROM t44;
+SELECT * FROM t45;
+SHOW CREATE TABLE t45;
+DROP TABLE t44, t45;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1(prec INT, scale INT)
+BEGIN
+ DECLARE maxval VARCHAR(128) DEFAULT '';
+ SET @type= CONCAT('DECIMAL(', prec, ',', scale,')');
+ SET @stmt= CONCAT('CREATE TABLE t1 (a ', @type, ',b ', @type, 'unsigned)');
+ PREPARE stmt FROM @stmt;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ SET maxval= CONCAT(REPEAT('9', prec-scale), '.', REPEAT('9',scale));
+ INSERT INTO t1 VALUES (maxval, maxval);
+ CREATE TABLE t2 AS SELECT a, b, FLOOR(a) AS fa, FLOOR(b) AS fb FROM t1;
+ SHOW CREATE TABLE t2;
+ SELECT * FROM t2;
+ DROP TABLE t1, t2;
+END;
+$$
+CREATE PROCEDURE p2(prec INT)
+BEGIN
+ DECLARE scale INT DEFAULT 0;
+ WHILE scale < prec AND scale <= 30 DO
+ CALL p1(prec, scale);
+ SET scale= scale + 1;
+ END WHILE;
+END;
+$$
+DELIMITER ;$$
+--vertical_results
+CALL p2(38);
+CALL p2(30);
+--horizontal_results
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
--echo #
@@ -1013,7 +1072,7 @@ DROP FUNCTION crc32_func;
PREPARE stmt1 FROM 'SELECT CRC32(?)';
SET @val = 'a';
EXECUTE stmt1 USING @val;
-DEALLOCATE PREPARE stmt;
+DEALLOCATE PREPARE stmt1;
# Test case for checksum on contents of a file
SET NAMES utf8;
diff --git a/mysql-test/main/subselect4.result b/mysql-test/main/subselect4.result
index 82b75f5daad..0240cbaf3f4 100644
--- a/mysql-test/main/subselect4.result
+++ b/mysql-test/main/subselect4.result
@@ -2535,6 +2535,38 @@ c1
1
drop table t1;
#
+# MDEV-22498: SIGSEGV in Bitmap<64u>::merge on SELECT
+#
+set @save_sql_select_limit= @@sql_select_limit;
+SET sql_select_limit=0;
+CREATE TABLE t1(b INT, c INT);
+CREATE TABLE t2(a INT, b INT);
+INSERT INTO t1 VALUES (1,1),(2,2),(3,3);
+INSERT INTO t2 VALUES (1,1),(2,2),(3,3);
+EXPLAIN EXTENDED SELECT sum(a), t2.a, t2.b FROM t2 HAVING t2.a IN (SELECT t2.b FROM t1);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Zero limit
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1276 Field or reference 'test.t2.b' of SELECT #2 was resolved in SELECT #1
+Note 1276 Field or reference 'test.t2.b' of SELECT #2 was resolved in SELECT #1
+Note 1003 /* select#1 */ select sum(`test`.`t2`.`a`) AS `sum(a)`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` having <in_optimizer>(`test`.`t2`.`a`,<exists>(/* select#2 */ select `test`.`t2`.`b` from `test`.`t1` where <cache>(`test`.`t2`.`a`) = `test`.`t2`.`b`))
+SELECT sum(a), t2.a, t2.b FROM t2 HAVING t2.a IN (SELECT t2.b FROM t1);
+sum(a) a b
+SET @@sql_select_limit= @save_sql_select_limit;
+EXPLAIN EXTENDED SELECT sum(a), t2.a, t2.b FROM t2 HAVING t2.a IN (SELECT t2.b FROM t1);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1276 Field or reference 'test.t2.b' of SELECT #2 was resolved in SELECT #1
+Note 1276 Field or reference 'test.t2.b' of SELECT #2 was resolved in SELECT #1
+Note 1003 /* select#1 */ select sum(`test`.`t2`.`a`) AS `sum(a)`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` having <expr_cache><`test`.`t2`.`a`,`test`.`t2`.`b`>(<in_optimizer>(`test`.`t2`.`a`,<exists>(/* select#2 */ select `test`.`t2`.`b` from `test`.`t1` where <cache>(`test`.`t2`.`a`) = `test`.`t2`.`b`)))
+SELECT sum(a), t2.a, t2.b FROM t2 HAVING t2.a IN (SELECT t2.b FROM t1);
+sum(a) a b
+6 1 1
+DROP TABLE t1,t2;
+#
# MDEV-19134: EXISTS() slower if ORDER BY is defined
#
create table t0 (a int);
@@ -2582,3 +2614,4 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 100
drop table t0, t1, t2;
+# End of 10.4 tests
diff --git a/mysql-test/main/subselect4.test b/mysql-test/main/subselect4.test
index bc8db41c505..6dc8736b64c 100644
--- a/mysql-test/main/subselect4.test
+++ b/mysql-test/main/subselect4.test
@@ -2079,6 +2079,30 @@ select (select c1 from t1 group by c1,c2 order by c1 limit 1) as x;
drop table t1;
--echo #
+--echo # MDEV-22498: SIGSEGV in Bitmap<64u>::merge on SELECT
+--echo #
+
+set @save_sql_select_limit= @@sql_select_limit;
+SET sql_select_limit=0;
+
+CREATE TABLE t1(b INT, c INT);
+CREATE TABLE t2(a INT, b INT);
+INSERT INTO t1 VALUES (1,1),(2,2),(3,3);
+INSERT INTO t2 VALUES (1,1),(2,2),(3,3);
+
+let $query=
+SELECT sum(a), t2.a, t2.b FROM t2 HAVING t2.a IN (SELECT t2.b FROM t1);
+
+eval EXPLAIN EXTENDED $query;
+eval $query;
+
+SET @@sql_select_limit= @save_sql_select_limit;
+
+eval EXPLAIN EXTENDED $query;
+eval $query;
+DROP TABLE t1,t2;
+
+--echo #
--echo # MDEV-19134: EXISTS() slower if ORDER BY is defined
--echo #
create table t0 (a int);
@@ -2118,3 +2142,4 @@ select * from t1 where t1.a in (select t2.a from t2 order by t2.b);
drop table t0, t1, t2;
+--echo # End of 10.4 tests
diff --git a/mysql-test/main/table_value_constr.result b/mysql-test/main/table_value_constr.result
index 38e1a54082c..321c7f8542a 100644
--- a/mysql-test/main/table_value_constr.result
+++ b/mysql-test/main/table_value_constr.result
@@ -2599,3 +2599,14 @@ a
2
1
drop view v1;
+#
+# MDEV-22560 Crash on a table value constructor with an SP variable
+#
+BEGIN NOT ATOMIC
+DECLARE a INT DEFAULT 0;
+VALUES (a) UNION SELECT 1;
+END;
+$$
+a
+0
+1
diff --git a/mysql-test/main/table_value_constr.test b/mysql-test/main/table_value_constr.test
index 4464eb7b77b..e7843c604dd 100644
--- a/mysql-test/main/table_value_constr.test
+++ b/mysql-test/main/table_value_constr.test
@@ -1326,3 +1326,16 @@ create view v1 as with t(a) as (values (2), (1)) select a from t;
show create view v1;
select * from v1;
drop view v1;
+
+
+--echo #
+--echo # MDEV-22560 Crash on a table value constructor with an SP variable
+--echo #
+
+DELIMITER $$;
+BEGIN NOT ATOMIC
+ DECLARE a INT DEFAULT 0;
+ VALUES (a) UNION SELECT 1;
+END;
+$$
+DELIMITER ;$$
diff --git a/mysql-test/main/udf.result b/mysql-test/main/udf.result
index 4077a85c813..8ad21e68c71 100644
--- a/mysql-test/main/udf.result
+++ b/mysql-test/main/udf.result
@@ -30,9 +30,9 @@ lookup("127.0.0.1")
127.0.0.1
select lookup(127,0,0,1);
ERROR HY000: Can't initialize function 'lookup'; Wrong arguments to lookup; Use the source
-select lookup("localhost");
-lookup("localhost")
-127.0.0.1
+select lookup("localhost") rlike '^127\.\\d+\.\\d+.\\d+$';
+lookup("localhost") rlike '^127\.\\d+\.\\d+.\\d+$'
+1
select reverse_lookup();
ERROR HY000: Can't initialize function 'reverse_lookup'; Wrong number of arguments to reverse_lookup; Use the source
select reverse_lookup("127.0.0.1");
diff --git a/mysql-test/main/udf.test b/mysql-test/main/udf.test
index bb8493135aa..640d5567574 100644
--- a/mysql-test/main/udf.test
+++ b/mysql-test/main/udf.test
@@ -47,7 +47,7 @@ select lookup();
select lookup("127.0.0.1");
--error ER_CANT_INITIALIZE_UDF
select lookup(127,0,0,1);
-select lookup("localhost");
+select lookup("localhost") rlike '^127\.\\d+\.\\d+.\\d+$';
--error ER_CANT_INITIALIZE_UDF
select reverse_lookup();
diff --git a/mysql-test/suite/encryption/r/tempfiles_encrypted.result b/mysql-test/suite/encryption/r/tempfiles_encrypted.result
new file mode 100644
index 00000000000..d08cb33e0fc
--- /dev/null
+++ b/mysql-test/suite/encryption/r/tempfiles_encrypted.result
@@ -0,0 +1,18 @@
+#
+# Tests when the temporary files are encrypted
+#
+select @@encrypt_tmp_files;
+@@encrypt_tmp_files
+1
+#
+# MDEV-22556: Incorrect result for window function when using encrypt-tmp-files=ON
+#
+set @save_sort_buffer_size=@@sort_buffer_size;
+set sort_buffer_size= 2000;
+create table t1( a DECIMAL(12,0) DEFAULT NULL, b VARCHAR(20) DEFAULT NULL, c DECIMAL(12,0) DEFAULT NULL)engine=INNODB;
+insert into t1 select seq, seq, seq from seq_1_to_5000;
+select count(*) from (select a, b, c, ROW_NUMBER() OVER (PARTITION BY a) FROM t1)q;
+count(*)
+5000
+set @@sort_buffer_size=@save_sort_buffer_size;
+drop table t1;
diff --git a/mysql-test/suite/encryption/t/innodb_encryption_tables.test b/mysql-test/suite/encryption/t/innodb_encryption_tables.test
index bc762faf12e..d03bc890ba4 100644
--- a/mysql-test/suite/encryption/t/innodb_encryption_tables.test
+++ b/mysql-test/suite/encryption/t/innodb_encryption_tables.test
@@ -1,6 +1,8 @@
-- source include/have_innodb.inc
-- source include/have_example_key_management_plugin.inc
-- source include/not_embedded.inc
+# We can't run this test under valgrind as it 'takes forever'
+-- source include/not_valgrind.inc
create table innodb_normal(c1 bigint not null, b char(200)) engine=innodb;
create table innodb_compact(c1 bigint not null, b char(200)) engine=innodb row_format=compact;
diff --git a/mysql-test/suite/encryption/t/tempfiles_encrypted.opt b/mysql-test/suite/encryption/t/tempfiles_encrypted.opt
new file mode 100644
index 00000000000..81877a8d1c5
--- /dev/null
+++ b/mysql-test/suite/encryption/t/tempfiles_encrypted.opt
@@ -0,0 +1 @@
+--encrypt-tmp_files=ON
diff --git a/mysql-test/suite/encryption/t/tempfiles_encrypted.test b/mysql-test/suite/encryption/t/tempfiles_encrypted.test
new file mode 100644
index 00000000000..96b981c1c06
--- /dev/null
+++ b/mysql-test/suite/encryption/t/tempfiles_encrypted.test
@@ -0,0 +1,23 @@
+--echo #
+--echo # Tests when the temporary files are encrypted
+--echo #
+
+source include/have_file_key_management_plugin.inc;
+source include/have_sequence.inc;
+source include/have_innodb.inc;
+
+select @@encrypt_tmp_files;
+
+--echo #
+--echo # MDEV-22556: Incorrect result for window function when using encrypt-tmp-files=ON
+--echo #
+
+set @save_sort_buffer_size=@@sort_buffer_size;
+set sort_buffer_size= 2000;
+create table t1( a DECIMAL(12,0) DEFAULT NULL, b VARCHAR(20) DEFAULT NULL, c DECIMAL(12,0) DEFAULT NULL)engine=INNODB;
+insert into t1 select seq, seq, seq from seq_1_to_5000;
+select count(*) from (select a, b, c, ROW_NUMBER() OVER (PARTITION BY a) FROM t1)q;
+
+set @@sort_buffer_size=@save_sort_buffer_size;
+
+drop table t1;
diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def
index e1868260af1..81970cd22aa 100644
--- a/mysql-test/suite/galera/disabled.def
+++ b/mysql-test/suite/galera/disabled.def
@@ -15,8 +15,6 @@ GCF-939 : MDEV-21520 galera.GCF-939
MDEV-16509 : MDEV-21523 galera.MDEV-16509
MDEV-20225 : MDEV-20886 galera.MDEV-20225
MW-286 : MDEV-18464 Killing thread can cause mutex deadlock if done concurrently with Galera/replication victim kill
-MW-328A : MDEV-21483 galera.MW-328A galera.MW-328B
-MW-328B : MDEV-21483 galera.MW-328A galera.MW-328B
MW-329 : MDEV-19962 Galera test failure on MW-329
galera.galera_defaults : MDEV-21494 Galera test sporadic failure on galera.galera_defaults
galera_as_slave_replication_bundle : MDEV-15785 OPTION_GTID_BEGIN is set in Gtid_log_event::do_apply_event()
diff --git a/mysql-test/suite/galera/r/MW-328C.result b/mysql-test/suite/galera/r/MW-328C.result
new file mode 100644
index 00000000000..7a00bb718de
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-328C.result
@@ -0,0 +1,25 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1);
+CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
+CREATE PROCEDURE proc_update ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+UPDATE t1 SET f2 = LEFT(MD5(RAND()), 4);
+END WHILE;
+END|
+connect node_1X, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1X;
+CALL proc_update();;
+connection node_2;
+SET SESSION wsrep_retry_autocommit = 10000;
+connection node_1;
+connection node_1X;
+Got one of the listed errors
+connection node_1;
+DROP PROCEDURE proc_update;
+DROP TABLE t1, t2;
+CALL mtr.add_suppression("conflict state ABORTED after post commit");
diff --git a/mysql-test/suite/galera/t/MW-328A.cnf b/mysql-test/suite/galera/t/MW-328A.cnf
index a10ea88bdf2..e68f891792c 100644
--- a/mysql-test/suite/galera/t/MW-328A.cnf
+++ b/mysql-test/suite/galera/t/MW-328A.cnf
@@ -1,7 +1,7 @@
!include ../galera_2nodes.cnf
[mysqld.1]
-wsrep-debug=ON
+wsrep-debug=SERVER
[mysqld.2]
-wsrep-debug=ON
+wsrep-debug=SERVER
diff --git a/mysql-test/suite/galera/t/MW-328B.cnf b/mysql-test/suite/galera/t/MW-328B.cnf
index a10ea88bdf2..e68f891792c 100644
--- a/mysql-test/suite/galera/t/MW-328B.cnf
+++ b/mysql-test/suite/galera/t/MW-328B.cnf
@@ -1,7 +1,7 @@
!include ../galera_2nodes.cnf
[mysqld.1]
-wsrep-debug=ON
+wsrep-debug=SERVER
[mysqld.2]
-wsrep-debug=ON
+wsrep-debug=SERVER
diff --git a/mysql-test/suite/galera/t/MW-328C.cnf b/mysql-test/suite/galera/t/MW-328C.cnf
new file mode 100644
index 00000000000..e68f891792c
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328C.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep-debug=SERVER
+
+[mysqld.2]
+wsrep-debug=SERVER
diff --git a/mysql-test/suite/galera/t/MW-328C.test b/mysql-test/suite/galera/t/MW-328C.test
new file mode 100644
index 00000000000..7241dfbdbca
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328C.test
@@ -0,0 +1,35 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+#
+
+#
+# Make sure that a high value of wsrep_retry_autocommit
+# masks all deadlock errors
+#
+
+--source include/galera_cluster.inc
+--source suite/galera/t/MW-328-header.inc
+
+--connection node_2
+--let $count = 100
+
+SET SESSION wsrep_retry_autocommit = 10000;
+
+--disable_query_log
+
+while ($count)
+{
+ --error 0
+ INSERT IGNORE INTO t2 SELECT f2 FROM t1;
+
+ --disable_result_log
+ --error 0
+ SELECT 1 FROM DUAL;
+ --enable_result_log
+
+ --dec $count
+}
+
+--enable_query_log
+
+--source suite/galera/t/MW-328-footer.inc
diff --git a/mysql-test/suite/galera/t/MW-328D.cnf b/mysql-test/suite/galera/t/MW-328D.cnf
new file mode 100644
index 00000000000..e68f891792c
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328D.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep-debug=SERVER
+
+[mysqld.2]
+wsrep-debug=SERVER
diff --git a/mysql-test/suite/galera/t/MW-328E.cnf b/mysql-test/suite/galera/t/MW-328E.cnf
new file mode 100644
index 00000000000..e68f891792c
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328E.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep-debug=SERVER
+
+[mysqld.2]
+wsrep-debug=SERVER
diff --git a/mysql-test/suite/innodb/r/analyze_table.result b/mysql-test/suite/innodb/r/analyze_table.result
index 57095b725eb..830130821da 100644
--- a/mysql-test/suite/innodb/r/analyze_table.result
+++ b/mysql-test/suite/innodb/r/analyze_table.result
@@ -1,26 +1,16 @@
-CREATE PROCEDURE populate_t1()
-BEGIN
-DECLARE i int DEFAULT 1;
-START TRANSACTION;
-WHILE (i <= 1000000) DO
-INSERT INTO t1 VALUES (i, i, CONCAT('a', i));
-SET i = i + 1;
-END WHILE;
-COMMIT;
-END|
+set use_stat_tables='preferably';
CREATE TABLE t1(
class INT,
id INT,
title VARCHAR(100)
) ENGINE=InnoDB;
+insert into t1 select seq, seq, concat('a', seq) from seq_1_to_500;
SELECT COUNT(*) FROM t1;
COUNT(*)
-1000000
-SET GLOBAL innodb_stats_persistent_sample_pages=2000;
+500
+set @@max_heap_table_size=16384;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
DROP TABLE t1;
-DROP PROCEDURE populate_t1;
-SET GLOBAL innodb_stats_persistent_sample_pages=default;
diff --git a/mysql-test/suite/innodb/t/analyze_table.test b/mysql-test/suite/innodb/t/analyze_table.test
index e9db3668f02..538eed04ba4 100644
--- a/mysql-test/suite/innodb/t/analyze_table.test
+++ b/mysql-test/suite/innodb/t/analyze_table.test
@@ -1,23 +1,11 @@
-#
-# BUG#22385442 - INNODB: DIFFICULT TO FIND FREE BLOCKS IN THE BUFFER POOL
-#
-
--source include/have_innodb.inc
---source include/big_test.inc
+--source include/have_sequence.inc
-DELIMITER |;
-CREATE PROCEDURE populate_t1()
-BEGIN
- DECLARE i int DEFAULT 1;
+#
+# MDEV-22073 MSAN use-of-uninitialized-value in collect_statistics_for_table()
+#
- START TRANSACTION;
- WHILE (i <= 1000000) DO
- INSERT INTO t1 VALUES (i, i, CONCAT('a', i));
- SET i = i + 1;
- END WHILE;
- COMMIT;
-END|
-DELIMITER ;|
+set use_stat_tables='preferably';
CREATE TABLE t1(
class INT,
@@ -25,18 +13,11 @@ CREATE TABLE t1(
title VARCHAR(100)
) ENGINE=InnoDB;
--- disable_query_log
-CALL populate_t1();
--- enable_query_log
+insert into t1 select seq, seq, concat('a', seq) from seq_1_to_500;
SELECT COUNT(*) FROM t1;
-SET GLOBAL innodb_stats_persistent_sample_pages=2000;
-
+set @@max_heap_table_size=16384;
ANALYZE TABLE t1;
DROP TABLE t1;
-
-DROP PROCEDURE populate_t1;
-
-SET GLOBAL innodb_stats_persistent_sample_pages=default;
diff --git a/mysql-test/suite/innodb/t/xa_recovery_debug.test b/mysql-test/suite/innodb/t/xa_recovery_debug.test
index 21a38854adb..ada2940ed9c 100644
--- a/mysql-test/suite/innodb/t/xa_recovery_debug.test
+++ b/mysql-test/suite/innodb/t/xa_recovery_debug.test
@@ -4,6 +4,10 @@
# Embedded server does not support restarting
--source include/not_embedded.inc
+--disable_query_log
+FLUSH TABLES;
+--enable_query_log
+
--echo #
--echo # Bug#20872655 XA ROLLBACK IS NOT CRASH-SAFE
--echo #
diff --git a/mysql-test/suite/parts/inc/partition_auto_increment.inc b/mysql-test/suite/parts/inc/partition_auto_increment.inc
index 199c8680864..4392d04db8a 100644
--- a/mysql-test/suite/parts/inc/partition_auto_increment.inc
+++ b/mysql-test/suite/parts/inc/partition_auto_increment.inc
@@ -861,6 +861,17 @@ SELECT * FROM t1;
DROP TABLE t1;
}
+if (!$skip_update)
+{
+--echo #
+--echo # MDEV-19622 Assertion failures in
+--echo # ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table
+--echo #
+CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a);
+INSERT INTO t1 VALUES (1,1),(2,2);
+UPDATE t1 SET pk = 0;
+DROP TABLE t1;
+}
--echo ##############################################################################
}
diff --git a/mysql-test/suite/parts/r/partition_auto_increment_innodb.result b/mysql-test/suite/parts/r/partition_auto_increment_innodb.result
index 6250f28eb00..76f1ddfceae 100644
--- a/mysql-test/suite/parts/r/partition_auto_increment_innodb.result
+++ b/mysql-test/suite/parts/r/partition_auto_increment_innodb.result
@@ -1101,4 +1101,12 @@ SELECT * FROM t1;
a
0
DROP TABLE t1;
+#
+# MDEV-19622 Assertion failures in
+# ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table
+#
+CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a);
+INSERT INTO t1 VALUES (1,1),(2,2);
+UPDATE t1 SET pk = 0;
+DROP TABLE t1;
##############################################################################
diff --git a/mysql-test/suite/parts/r/partition_auto_increment_maria.result b/mysql-test/suite/parts/r/partition_auto_increment_maria.result
index 5acce3e9492..5a3902475a9 100644
--- a/mysql-test/suite/parts/r/partition_auto_increment_maria.result
+++ b/mysql-test/suite/parts/r/partition_auto_increment_maria.result
@@ -1148,4 +1148,12 @@ SELECT * FROM t1;
a
0
DROP TABLE t1;
+#
+# MDEV-19622 Assertion failures in
+# ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table
+#
+CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a);
+INSERT INTO t1 VALUES (1,1),(2,2);
+UPDATE t1 SET pk = 0;
+DROP TABLE t1;
##############################################################################
diff --git a/mysql-test/suite/parts/r/partition_auto_increment_memory.result b/mysql-test/suite/parts/r/partition_auto_increment_memory.result
index e622ddaa259..c395f8ed0c9 100644
--- a/mysql-test/suite/parts/r/partition_auto_increment_memory.result
+++ b/mysql-test/suite/parts/r/partition_auto_increment_memory.result
@@ -1129,4 +1129,12 @@ SELECT * FROM t1;
a
0
DROP TABLE t1;
+#
+# MDEV-19622 Assertion failures in
+# ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table
+#
+CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a);
+INSERT INTO t1 VALUES (1,1),(2,2);
+UPDATE t1 SET pk = 0;
+DROP TABLE t1;
##############################################################################
diff --git a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result
index 4e67094b327..792423096b5 100644
--- a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result
+++ b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result
@@ -1148,4 +1148,12 @@ SELECT * FROM t1;
a
0
DROP TABLE t1;
+#
+# MDEV-19622 Assertion failures in
+# ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table
+#
+CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a);
+INSERT INTO t1 VALUES (1,1),(2,2);
+UPDATE t1 SET pk = 0;
+DROP TABLE t1;
##############################################################################
diff --git a/mysql-test/suite/rpl/r/rpl_failed_drop_tbl_binlog.result b/mysql-test/suite/rpl/r/rpl_failed_drop_tbl_binlog.result
deleted file mode 100644
index df36fa82e0f..00000000000
--- a/mysql-test/suite/rpl/r/rpl_failed_drop_tbl_binlog.result
+++ /dev/null
@@ -1,32 +0,0 @@
-include/master-slave.inc
-[connection master]
-create table t1 (a int) engine=innodb;
-create table t2 (b longblob) engine=innodb;
-create table t3 (c int) engine=innodb;
-insert into t2 values (repeat('b',1024*1024));
-insert into t2 select * from t2;
-insert into t2 select * from t2;
-insert into t2 select * from t2;
-insert into t2 select * from t2;
-set debug_sync='rm_table_no_locks_before_delete_table SIGNAL nogo WAIT_FOR go EXECUTE 2';
-drop table t1, t2, t3;
-connect foo,localhost,root;
-set debug_sync='now SIGNAL go';
-kill query CONNECTION_ID;
-connection master;
-ERROR 70100: Query execution was interrupted
-"Tables t2 and t3 should be listed"
-SHOW TABLES;
-Tables_in_test
-t2
-t3
-include/show_binlog_events.inc
-Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Gtid # # GTID #-#-#
-master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
-connection slave;
-drop table t2, t3;
-connection master;
-set debug_sync='RESET';
-drop table t2, t3;
-include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.test b/mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.test
deleted file mode 100644
index 1d544891a9c..00000000000
--- a/mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.test
+++ /dev/null
@@ -1,69 +0,0 @@
-# ==== Purpose ====
-#
-# Check that when the execution of a DROP TABLE command with single table
-# fails it should not be written to the binary log. Also test that when the
-# execution of DROP TABLE command with multiple tables fails the command
-# should be written into the binary log.
-#
-# ==== Implementation ====
-#
-# Steps:
-# 0 - Create tables named t1, t2, t3
-# 1 - Execute DROP TABLE t1,t2,t3 command.
-# 2 - Kill the DROP TABLE command while it is trying to drop table 't2'.
-# 3 - Verify that tables t2,t3 are present after the DROP command execution
-# was interrupted.
-# 4 - Check that table 't1' is present in binary log as part of DROP
-# command.
-#
-# ==== References ====
-#
-# MDEV-20348: DROP TABLE IF EXISTS killed on master but was replicated.
-#
-
---source include/have_innodb.inc
---source include/have_debug_sync.inc
---source include/have_binlog_format_statement.inc
---source include/master-slave.inc
-
-if (!`select @@GLOBAL.innodb_adaptive_hash_index`)
-{
- --skip Need innodb_adaptive_hash_index
-}
-
-create table t1 (a int) engine=innodb;
-create table t2 (b longblob) engine=innodb;
-create table t3 (c int) engine=innodb;
-insert into t2 values (repeat('b',1024*1024));
-insert into t2 select * from t2;
-insert into t2 select * from t2;
-insert into t2 select * from t2;
-insert into t2 select * from t2;
-let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
-
-let $id=`select connection_id()`;
-set debug_sync='rm_table_no_locks_before_delete_table SIGNAL nogo WAIT_FOR go EXECUTE 2';
-send drop table t1, t2, t3;
-
-connect foo,localhost,root;
-set debug_sync='now SIGNAL go';
-let $wait_condition=select 1 from information_schema.processlist where state like 'debug sync point:%';
-source include/wait_condition.inc;
---replace_result $id CONNECTION_ID
-eval kill query $id;
-
-connection master;
-error ER_QUERY_INTERRUPTED;
-reap;
-
---echo "Tables t2 and t3 should be listed"
-SHOW TABLES;
---source include/show_binlog_events.inc
---sync_slave_with_master
-drop table t2, t3;
-
-connection master;
-set debug_sync='RESET';
-drop table t2, t3;
-
-source include/rpl_end.inc;
diff --git a/mysql-test/suite/vcol/r/vcol_misc.result b/mysql-test/suite/vcol/r/vcol_misc.result
index 6afdd120d26..1df31a4dfab 100644
--- a/mysql-test/suite/vcol/r/vcol_misc.result
+++ b/mysql-test/suite/vcol/r/vcol_misc.result
@@ -427,6 +427,26 @@ aaa
Warnings:
Warning 1918 Encountered illegal value '\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7' when converting to DOUBLE
#
+# MDEV-22579 No error when inserting DEFAULT(non_virtual_column) into a virtual column
+#
+SET sql_mode=STRICT_ALL_TABLES;
+CREATE OR REPLACE TABLE t1 (
+a INT NOT NULL DEFAULT 10,
+b INT AS (a+1) VIRTUAL
+) ENGINE=MyISAM;
+INSERT INTO t1 (b) VALUES (10);
+ERROR HY000: The value specified for generated column 'b' in table 't1' has been ignored
+INSERT INTO t1 (b) VALUES (DEFAULT(a));
+ERROR HY000: The value specified for generated column 'b' in table 't1' has been ignored
+INSERT INTO t1 (b) VALUES (DEFAULT);
+INSERT INTO t1 VALUES (10,10);
+ERROR HY000: The value specified for generated column 'b' in table 't1' has been ignored
+INSERT INTO t1 VALUES (10,DEFAULT(a));
+ERROR HY000: The value specified for generated column 'b' in table 't1' has been ignored
+INSERT INTO t1 VALUES (10, DEFAULT);
+DROP TABLE t1;
+SET sql_mode=DEFAULT;
+#
# End of 10.1 tests
#
#
@@ -481,5 +501,37 @@ Warning 1264 Out of range value for column 'vi' at row 1
DROP TABLE t1;
SET @sql_mode=@old_sql_mode;
#
+# MDEV-22579 No error when inserting DEFAULT(non_virtual_column) into a virtual column
+# 10.2+ specific part
+#
+SET sql_mode=STRICT_ALL_TABLES;
+CREATE OR REPLACE TABLE t1 (
+a INT NOT NULL DEFAULT 10,
+b INT AS (a+1) VIRTUAL
+) ENGINE=MyISAM;
+EXECUTE IMMEDIATE 'INSERT INTO t1 (b) VALUES(?)' USING DEFAULT;
+EXECUTE IMMEDIATE 'INSERT INTO t1 (b) VALUES(?)' USING IGNORE;
+INSERT INTO t1 (b) VALUES (DEFAULT);
+INSERT INTO t1 (b) VALUES (IGNORE);
+SELECT * FROM t1;
+a b
+10 11
+10 11
+10 11
+10 11
+DELETE FROM t1;
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES(10,?)' USING DEFAULT;
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES(11,?)' USING IGNORE;
+INSERT INTO t1 VALUES (12,DEFAULT);
+INSERT INTO t1 VALUES (13,IGNORE);
+SELECT * FROM t1;
+a b
+10 11
+11 12
+12 13
+13 14
+DROP TABLE t1;
+SET sql_mode=DEFAULT;
+#
# End of 10.2 tests
#
diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test
index 39f4f4142e6..1bbd18d6eab 100644
--- a/mysql-test/suite/vcol/t/vcol_misc.test
+++ b/mysql-test/suite/vcol/t/vcol_misc.test
@@ -385,6 +385,36 @@ SELECT COLUMN_GET(@aaa, 'price' AS DECIMAL) aaa;
SELECT COLUMN_GET(@aaa, 'price' AS INT) aaa;
SELECT COLUMN_GET(@aaa, 'price' AS DOUBLE) aaa;
+
+--echo #
+--echo # MDEV-22579 No error when inserting DEFAULT(non_virtual_column) into a virtual column
+--echo #
+
+SET sql_mode=STRICT_ALL_TABLES;
+CREATE OR REPLACE TABLE t1 (
+ a INT NOT NULL DEFAULT 10,
+ b INT AS (a+1) VIRTUAL
+) ENGINE=MyISAM;
+
+# Testing with a column list
+
+--error ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN
+INSERT INTO t1 (b) VALUES (10);
+--error ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN
+INSERT INTO t1 (b) VALUES (DEFAULT(a));
+INSERT INTO t1 (b) VALUES (DEFAULT);
+
+# Testing without a column list
+--error ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN
+INSERT INTO t1 VALUES (10,10);
+--error ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN
+INSERT INTO t1 VALUES (10,DEFAULT(a));
+INSERT INTO t1 VALUES (10, DEFAULT);
+
+DROP TABLE t1;
+SET sql_mode=DEFAULT;
+
+
--echo #
--echo # End of 10.1 tests
--echo #
@@ -443,5 +473,36 @@ DROP TABLE t1;
SET @sql_mode=@old_sql_mode;
--echo #
+--echo # MDEV-22579 No error when inserting DEFAULT(non_virtual_column) into a virtual column
+--echo # 10.2+ specific part
+--echo #
+
+SET sql_mode=STRICT_ALL_TABLES;
+CREATE OR REPLACE TABLE t1 (
+ a INT NOT NULL DEFAULT 10,
+ b INT AS (a+1) VIRTUAL
+) ENGINE=MyISAM;
+
+# Testing with column list
+
+EXECUTE IMMEDIATE 'INSERT INTO t1 (b) VALUES(?)' USING DEFAULT;
+EXECUTE IMMEDIATE 'INSERT INTO t1 (b) VALUES(?)' USING IGNORE;
+INSERT INTO t1 (b) VALUES (DEFAULT);
+INSERT INTO t1 (b) VALUES (IGNORE);
+SELECT * FROM t1;
+DELETE FROM t1;
+
+# Testing without column list
+
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES(10,?)' USING DEFAULT;
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES(11,?)' USING IGNORE;
+INSERT INTO t1 VALUES (12,DEFAULT);
+INSERT INTO t1 VALUES (13,IGNORE);
+SELECT * FROM t1;
+
+DROP TABLE t1;
+SET sql_mode=DEFAULT;
+
+--echo #
--echo # End of 10.2 tests
--echo #
diff --git a/mysql-test/unstable-tests b/mysql-test/unstable-tests
index 64b47463ba3..70eab5d2740 100644
--- a/mysql-test/unstable-tests
+++ b/mysql-test/unstable-tests
@@ -217,7 +217,6 @@ main.type_int : Modified in 10.4.12
main.type_newdecimal : MDEV-20532 - Floating point differences
main.type_ranges : MDEV-20532 - Floating point differences
main.type_time : Modified in 10.4.12
-main.udf : MDEV-21976: Fails on Ubuntu Bionic 18.04, our Travis-CI platform
main.union_crash-714 : Modified in 10.4.12
main.upgrade_MDEV-19650 : Added in 10.4.13
main.userstat : MDEV-12904 - SSL errors
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
index b3aa494a58c..c7cb7510b60 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -515,8 +515,11 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
if (info->type == WRITE_CACHE)
info->end_of_file= my_b_tell(info);
else
- info->end_of_file= mysql_file_seek(info->file, 0L, MY_SEEK_END,
- MYF(0));
+ {
+ if (!(info->myflags & MY_ENCRYPT))
+ info->end_of_file= mysql_file_seek(info->file, 0L,
+ MY_SEEK_END, MYF(0));
+ }
}
/* flush cache if we want to reuse it */
if (!clear_cache && my_b_flush_io_cache(info,1))
diff --git a/sql/field.cc b/sql/field.cc
index 6234de43ec8..0f5caed57f6 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1455,7 +1455,7 @@ void Field::error_generated_column_function_is_not_allowed(THD *thd,
QT_ITEM_IDENT_SKIP_TABLE_NAMES));
my_error(ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED,
MYF(error ? 0 : ME_WARNING),
- tmp.c_ptr(), vcol_info->get_vcol_type_name(),
+ tmp.c_ptr_safe(), vcol_info->get_vcol_type_name(),
const_cast<const char*>(field_name.str));
}
@@ -7680,6 +7680,15 @@ my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
}
+#ifdef HAVE_valgrind_or_MSAN
+void Field_varstring::mark_unused_memory_as_defined()
+{
+ uint used_length= get_length();
+ MEM_MAKE_DEFINED(get_data() + used_length, field_length - used_length);
+}
+#endif
+
+
int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
uint max_len) const
{
diff --git a/sql/field.h b/sql/field.h
index d709a84e0fe..bef73705f60 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -977,6 +977,19 @@ public:
DBUG_ASSERT(ls.length < UINT_MAX32);
return store(ls.str, (uint) ls.length, cs);
}
+
+#ifdef HAVE_valgrind_or_MSAN
+ /**
+ Mark unused memory in the field as defined. Mainly used to ensure
+ that if we write full field to disk (for example in
+ Count_distinct_field::add(), we don't write unitalized data to
+ disk which would confuse valgrind or MSAN.
+ */
+ virtual void mark_unused_memory_as_defined() {}
+#else
+ void mark_unused_memory_as_defined() {}
+#endif
+
virtual double val_real()=0;
virtual longlong val_int()=0;
/*
@@ -4096,6 +4109,9 @@ public:
}
int store(const char *to,size_t length,CHARSET_INFO *charset) override;
using Field_str::store;
+#ifdef HAVE_valgrind_or_MSAN
+ void mark_unused_memory_as_defined() override;
+#endif
double val_real() override;
longlong val_int() override;
String *val_str(String *, String *) override;
diff --git a/sql/item.h b/sql/item.h
index c5fd5d074f6..cb11b5d8773 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1592,7 +1592,14 @@ public:
a constant expression. Used in the optimizer to propagate basic constants.
*/
virtual bool basic_const_item() const { return 0; }
- /*
+ /**
+ Determines if the expression is allowed as
+ a virtual column assignment source:
+ INSERT INTO t1 (vcol) VALUES (10) -> error
+ INSERT INTO t1 (vcol) VALUES (NULL) -> ok
+ */
+ virtual bool vcol_assignment_allowed_value() const { return false; }
+ /**
Test if "this" is an ORDER position (rather than an expression).
Notes:
- can be called before fix_fields().
@@ -3616,6 +3623,7 @@ public:
collation.set(cs, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII);
}
enum Type type() const { return NULL_ITEM; }
+ bool vcol_assignment_allowed_value() const { return true; }
double val_real();
longlong val_int();
String *val_str(String *str);
@@ -3861,6 +3869,21 @@ public:
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
+ bool vcol_assignment_allowed_value() const
+ {
+ switch (state) {
+ case NULL_VALUE:
+ case DEFAULT_VALUE:
+ case IGNORE_VALUE:
+ return true;
+ case NO_VALUE:
+ case SHORT_DATA_VALUE:
+ case LONG_DATA_VALUE:
+ break;
+ }
+ return false;
+ }
+
Item_param(THD *thd, const LEX_CSTRING *name_arg,
uint pos_in_query_arg, uint len_in_query_arg);
@@ -6255,6 +6278,7 @@ public:
Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a)
:Item_field(thd, context_arg) {}
enum Type type() const { return DEFAULT_VALUE_ITEM; }
+ bool vcol_assignment_allowed_value() const { return arg == NULL; }
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **);
void cleanup();
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 52eeaf10cd5..da185f9878b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2184,6 +2184,12 @@ longlong Item_func_bit_neg::val_int()
void Item_func_int_val::fix_length_and_dec_int_or_decimal()
{
+ /*
+ The INT branch of this code should be revised.
+ It creates too large data types, e.g.
+ CREATE OR REPLACE TABLE t2 AS SELECT FLOOR(9999999.999) AS fa;
+ results in a BININT(10) column, while INT(7) should probably be enough.
+ */
ulonglong tmp_max_length= (ulonglong ) args[0]->max_length -
(args[0]->decimals ? args[0]->decimals + 1 : 0) + 2;
max_length= tmp_max_length > (ulonglong) UINT_MAX32 ?
@@ -2198,6 +2204,9 @@ void Item_func_int_val::fix_length_and_dec_int_or_decimal()
*/
if (args[0]->max_length - args[0]->decimals >= DECIMAL_LONGLONG_DIGITS - 2)
{
+ fix_char_length(
+ my_decimal_precision_to_length_no_truncation(
+ args[0]->decimal_int_part(), 0, false));
set_handler(&type_handler_newdecimal);
}
else
@@ -2314,6 +2323,8 @@ void Item_func_round::fix_length_and_dec_decimal(uint decimals_to_set)
set_handler(&type_handler_newdecimal);
unsigned_flag= args[0]->unsigned_flag;
decimals= decimals_to_set;
+ if (!precision)
+ precision= 1; // DECIMAL(0,0) -> DECIMAL(1,0)
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 4bbb33d4eb7..be78f333951 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -2192,10 +2192,13 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
}
else
{
+ /*
+ No need to use real_item for the item, as the ref items that are possible
+ in the subquery either belong to views or to the parent select.
+ For such case we need to refer to the reference and not to the original
+ item.
+ */
Item *item= (Item*) select_lex->item_list.head();
- if (item->type() != REF_ITEM ||
- ((Item_ref*)item)->ref_type() != Item_ref::VIEW_REF)
- item= item->real_item();
if (select_lex->table_list.elements)
{
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 052ac173747..b676186f571 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1387,10 +1387,12 @@ Item_sum_sp::execute()
bool res;
uint old_server_status= thd->server_status;
- /* We set server status so we can send a signal to exit from the
- function with the return value. */
+ /*
+ We set server status so we can send a signal to exit from the
+ function with the return value.
+ */
- thd->server_status= SERVER_STATUS_LAST_ROW_SENT;
+ thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
res= Item_sp::execute(thd, &null_value, args, arg_count);
thd->server_status= old_server_status;
return res;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 1b273b19c33..d5ec2060c02 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -3134,6 +3134,8 @@ const char *sql_ex_info::init(const char *buf, const char *buf_end,
}
else
{
+ if (buf_end - buf < 7)
+ return 0; // Wrong data
field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1;
field_term = buf++; // Use first byte in string
enclosed= buf++;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index f840904def3..e61164e8e40 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -4648,7 +4648,7 @@ sp_instr_agg_cfetch::execute(THD *thd, uint *nextp)
else
{
thd->spcont->pause_state= FALSE;
- if (thd->server_status == SERVER_STATUS_LAST_ROW_SENT)
+ if (thd->server_status & SERVER_STATUS_LAST_ROW_SENT)
{
my_message(ER_SP_FETCH_NO_DATA,
ER_THD(thd, ER_SP_FETCH_NO_DATA), MYF(0));
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b5064fe9fd9..3413b3787bd 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -8375,11 +8375,9 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
if (table->next_number_field &&
rfield->field_index == table->next_number_field->field_index)
table->auto_increment_field_not_null= TRUE;
- Item::Type type= value->type();
const bool skip_sys_field= rfield->vers_sys_field(); // TODO: && !thd->vers_modify_history() [MDEV-16546]
if ((rfield->vcol_info || skip_sys_field) &&
- type != Item::DEFAULT_VALUE_ITEM &&
- type != Item::NULL_ITEM &&
+ !value->vcol_assignment_allowed_value() &&
table->s->table_category != TABLE_CATEGORY_TEMPORARY)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
@@ -8660,20 +8658,16 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
if (field->field_index == autoinc_index)
table->auto_increment_field_not_null= TRUE;
- if (unlikely(field->vcol_info) || (vers_sys_field && !ignore_errors))
+ if ((unlikely(field->vcol_info) || (vers_sys_field && !ignore_errors)) &&
+ !value->vcol_assignment_allowed_value() &&
+ table->s->table_category != TABLE_CATEGORY_TEMPORARY)
{
- Item::Type type= value->type();
- if (type != Item::DEFAULT_VALUE_ITEM &&
- type != Item::NULL_ITEM &&
- table->s->table_category != TABLE_CATEGORY_TEMPORARY)
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN,
- ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN),
- field->field_name.str, table->s->table_name.str);
- if (vers_sys_field)
- continue;
- }
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN,
+ ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN),
+ field->field_name.str, table->s->table_name.str);
+ if (vers_sys_field)
+ continue;
}
if (use_value)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 55e5e940b19..83ae25c962d 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -2006,7 +2006,7 @@ send_event_to_slave(binlog_send_info *info, Log_event_type event_type,
pos= my_b_tell(log);
if (repl_semisync_master.update_sync_header(info->thd,
- (uchar*) packet->ptr(),
+ (uchar*) packet->c_ptr_safe(),
info->log_file_name + info->dirlen,
pos, &need_sync))
{
@@ -2030,7 +2030,8 @@ send_event_to_slave(binlog_send_info *info, Log_event_type event_type,
}
}
- if (need_sync && repl_semisync_master.flush_net(info->thd, packet->c_ptr()))
+ if (need_sync && repl_semisync_master.flush_net(info->thd,
+ packet->c_ptr_safe()))
{
info->error= ER_UNKNOWN_ERROR;
return "Failed to run hook 'after_send_event'";
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 55e8e52c052..a6c489f02be 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1671,6 +1671,7 @@ public:
*/
virtual bool add()
{
+ table_field->mark_unused_memory_as_defined();
return tree->unique_add(table_field->ptr);
}
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 678dd81709e..e228b3ca211 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -52,7 +52,14 @@ bool fix_fields_for_tvc(THD *thd, List_iterator_fast<List_item> &li)
while ((item= it++))
{
- if (item->fix_fields(thd, 0))
+ /*
+ Some items have already been fixed.
+ For example Item_splocal items get fixed in
+ Item_splocal::append_for_log(), which is called from subst_spvars()
+ while replacing their values to NAME_CONST()s.
+ So fix only those that have not been.
+ */
+ if (item->fix_fields_if_needed(thd, 0))
DBUG_RETURN(true);
}
}
diff --git a/sql/table.cc b/sql/table.cc
index 92e3d2e4800..98d299afb37 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -7219,6 +7219,12 @@ void TABLE::mark_columns_needed_for_update()
}
need_signal= true;
}
+ else
+ {
+ if (found_next_number_field)
+ mark_auto_increment_column();
+ }
+
if (file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_DELETE)
{
/*
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 0a4fb9e1c2b..9658f4cf2a2 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -717,8 +717,10 @@ void btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
{
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
#ifdef BTR_CUR_HASH_ADAPT
- ut_ad(!block->index || !blob);
- ut_ad(!block->index || page_is_leaf(block->frame));
+ if (block->index && !block->index->freed()) {
+ ut_ad(!blob);
+ ut_ad(page_is_leaf(block->frame));
+ }
#endif
ut_ad(index->table->space_id == block->page.id.space());
/* The root page is freed by btr_free_root(). */
@@ -743,8 +745,7 @@ void btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
? PAGE_HEADER + PAGE_BTR_SEG_LEAF
: PAGE_HEADER + PAGE_BTR_SEG_TOP];
fseg_free_page(seg_header,
- index->table->space, block->page.id.page_no(),
- block->index != NULL, mtr);
+ index->table->space, block->page.id.page_no(), mtr);
/* The page was marked free in the allocation bitmap, but it
should remain exclusively latched until mtr_t::commit() or until it
@@ -987,8 +988,7 @@ static void btr_free_root(buf_block_t *block, mtr_t *mtr, bool invalidate)
}
/* Free the entire segment in small steps. */
- while (!fseg_free_step(PAGE_HEADER + PAGE_BTR_SEG_TOP + block->frame,
- true, mtr));
+ while (!fseg_free_step(PAGE_HEADER + PAGE_BTR_SEG_TOP + block->frame, mtr));
}
/** Prepare to free a B-tree.
@@ -1204,7 +1204,7 @@ leaf_loop:
fsp0fsp. */
bool finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_LEAF,
- true, &mtr);
+ &mtr);
mtr_commit(&mtr);
if (!finished) {
@@ -1224,7 +1224,7 @@ top_loop:
#endif /* UNIV_BTR_DEBUG */
finished = fseg_free_step_not_header(
- root + PAGE_HEADER + PAGE_BTR_SEG_TOP, true, &mtr);
+ root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
mtr_commit(&mtr);
if (!finished) {
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index 00e1599229a..8f97d674d15 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -3360,7 +3360,7 @@ btr_cur_optimistic_insert(
page_t* page;
rec_t* dummy;
bool leaf;
- bool reorg;
+ bool reorg __attribute__((unused));
bool inherit = true;
ulint rec_size;
dberr_t err;
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 3891d3963b8..cd2ee953994 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -191,15 +191,8 @@ static
void
btr_search_check_free_space_in_heap(const dict_index_t* index)
{
- hash_table_t* table;
- mem_heap_t* heap;
-
- ut_ad(!btr_search_own_any(RW_LOCK_S));
- ut_ad(!btr_search_own_any(RW_LOCK_X));
-
- table = btr_get_search_table(index);
-
- heap = table->heap;
+ hash_table_t* table = btr_get_search_table(index);
+ mem_heap_t* heap = table->heap;
/* Note that we peek the value of heap->free_block without reserving
the latch: this is ok, because we will not guarantee that there will
@@ -335,20 +328,29 @@ void btr_search_sys_free()
/** Set index->ref_count = 0 on all indexes of a table.
@param[in,out] table table handler */
-static
-void
-btr_search_disable_ref_count(
- dict_table_t* table)
+static void btr_search_disable_ref_count(dict_table_t *table)
{
- dict_index_t* index;
-
- ut_ad(mutex_own(&dict_sys.mutex));
+ for (dict_index_t *index= dict_table_get_first_index(table); index;
+ index= dict_table_get_next_index(index))
+ index->search_info->ref_count= 0;
+}
- for (index = dict_table_get_first_index(table);
- index != NULL;
- index = dict_table_get_next_index(index)) {
- index->search_info->ref_count = 0;
- }
+/** Lazily free detached metadata when removing the last reference. */
+ATTRIBUTE_COLD static void btr_search_lazy_free(dict_index_t *index)
+{
+ ut_ad(index->freed());
+ dict_table_t *table= index->table;
+ /* Perform the skipped steps of dict_index_remove_from_cache_low(). */
+ UT_LIST_REMOVE(table->freed_indexes, index);
+ rw_lock_free(&index->lock);
+ dict_mem_index_free(index);
+
+ if (!UT_LIST_GET_LEN(table->freed_indexes) &&
+ !UT_LIST_GET_LEN(table->indexes))
+ {
+ ut_ad(table->id == 0);
+ dict_mem_table_free(table);
+ }
}
/** Disable the adaptive hash search system and empty the index.
@@ -420,31 +422,6 @@ void btr_search_enable()
btr_search_x_unlock_all();
}
-/** Returns the value of ref_count. The value is protected by latch.
-@param[in] info search info
-@param[in] index index identifier
-@return ref_count value. */
-ulint
-btr_search_info_get_ref_count(
- btr_search_t* info,
- dict_index_t* index)
-{
- ulint ret = 0;
-
- if (!btr_search_enabled) {
- return(ret);
- }
-
- ut_ad(info);
-
- rw_lock_t* ahi_latch = btr_get_search_latch(index);
- rw_lock_s_lock(ahi_latch);
- ret = info->ref_count;
- rw_lock_s_unlock(ahi_latch);
-
- return(ret);
-}
-
/** Updates the search info of an index about hash successes. NOTE that info
is NOT protected by any semaphore, to save CPU time! Do not assume its fields
are consistent.
@@ -637,30 +614,28 @@ btr_search_update_hash_ref(
buf_block_t* block,
const btr_cur_t* cursor)
{
- dict_index_t* index;
- ulint fold;
- rec_t* rec;
-
ut_ad(cursor->flag == BTR_CUR_HASH_FAIL);
- ut_ad(rw_lock_own(btr_get_search_latch(cursor->index), RW_LOCK_X));
+
ut_ad(rw_lock_own_flagged(&block->lock,
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
ut_ad(page_align(btr_cur_get_rec(cursor)) == block->frame);
ut_ad(page_is_leaf(block->frame));
assert_block_ahi_valid(block);
- index = block->index;
-
- if (!index) {
+ dict_index_t* index = block->index;
+ if (!index || !info->n_hash_potential) {
return;
}
ut_ad(block->page.id.space() == index->table->space_id);
ut_ad(index == cursor->index);
ut_ad(!dict_index_is_ibuf(index));
+ rw_lock_t* const latch = btr_get_search_latch(index);
+ rw_lock_x_lock(latch);
+ ut_ad(!block->index || block->index == index);
- if ((info->n_hash_potential > 0)
+ if (block->index
&& (block->curr_n_fields == info->n_fields)
&& (block->curr_n_bytes == info->n_bytes)
&& (block->curr_left_side == info->left_side)) {
@@ -668,18 +643,18 @@ btr_search_update_hash_ref(
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
rec_offs_init(offsets_);
- rec = btr_cur_get_rec(cursor);
+ const rec_t* rec = btr_cur_get_rec(cursor);
if (!page_rec_is_user_rec(rec)) {
-
- return;
+ goto func_exit;
}
- fold = rec_fold(rec,
- rec_get_offsets(rec, index, offsets_, true,
- ULINT_UNDEFINED, &heap),
- block->curr_n_fields,
- block->curr_n_bytes, index->id);
+ ulint fold = rec_fold(
+ rec,
+ rec_get_offsets(rec, index, offsets_, true,
+ ULINT_UNDEFINED, &heap),
+ block->curr_n_fields,
+ block->curr_n_bytes, index->id);
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -689,6 +664,9 @@ btr_search_update_hash_ref(
MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_ADDED);
}
+
+func_exit:
+ rw_lock_x_unlock(latch);
}
/** Checks if a guessed position for a tree cursor is right. Note that if
@@ -847,6 +825,8 @@ inline void buf_pool_t::clear_hash_index()
ut_ad(!resizing);
ut_ad(!btr_search_enabled);
+ std::set<dict_index_t*> garbage;
+
for (chunk_t *chunk= chunks + n_chunks; chunk-- != chunks; )
{
for (buf_block_t *block= chunk->blocks, * const end= block + chunk->size;
@@ -855,8 +835,9 @@ inline void buf_pool_t::clear_hash_index()
dict_index_t *index= block->index;
assert_block_ahi_valid(block);
- /* We can clear block->index block->n_pointers when
+ /* We can clear block->index and block->n_pointers when
btr_search_own_all(RW_LOCK_X); see the comments in buf0buf.h */
+
if (!index)
{
# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
@@ -877,9 +858,14 @@ inline void buf_pool_t::clear_hash_index()
# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
block->n_pointers= 0;
# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ if (index->freed())
+ garbage.insert(index);
block->index= nullptr;
}
}
+
+ for (dict_index_t *index : garbage)
+ btr_search_lazy_free(index);
}
/** Get a buffer block from an adaptive hash index pointer.
@@ -943,7 +929,6 @@ btr_search_guess_on_hash(
rw_lock_t* ahi_latch,
mtr_t* mtr)
{
- const rec_t* rec;
ulint fold;
index_id_t index_id;
@@ -952,7 +937,7 @@ btr_search_guess_on_hash(
ahi_latch, RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
if (!btr_search_enabled) {
- return(FALSE);
+ return false;
}
ut_ad(!index->is_ibuf());
@@ -969,16 +954,14 @@ btr_search_guess_on_hash(
any latch here! */
if (info->n_hash_potential == 0) {
-
- return(FALSE);
+ return false;
}
cursor->n_fields = info->n_fields;
cursor->n_bytes = info->n_bytes;
if (dtuple_get_n_fields(tuple) < btr_search_get_n_fields(cursor)) {
-
- return(FALSE);
+ return false;
}
index_id = index->id;
@@ -992,6 +975,7 @@ btr_search_guess_on_hash(
cursor->flag = BTR_CUR_HASH;
rw_lock_t* use_latch = ahi_latch ? NULL : btr_get_search_latch(index);
+ const rec_t* rec;
if (use_latch) {
rw_lock_s_lock(use_latch);
@@ -1004,18 +988,17 @@ btr_search_guess_on_hash(
ut_ad(rw_lock_own(ahi_latch, RW_LOCK_S));
}
- rec = (rec_t*) ha_search_and_get_data(
- btr_get_search_table(index), fold);
+ rec = static_cast<const rec_t*>(
+ ha_search_and_get_data(btr_get_search_table(index), fold));
- if (rec == NULL) {
+ if (!rec) {
if (use_latch) {
fail:
rw_lock_s_unlock(use_latch);
}
btr_search_failure(info, cursor);
-
- return(FALSE);
+ return false;
}
buf_block_t* block = buf_pool.block_from_ahi(rec);
@@ -1031,8 +1014,11 @@ fail:
goto fail;
}
+ const bool fail = index != block->index
+ && index_id == block->index->id;
+ ut_a(!fail || block->index->freed());
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
- DBUG_ASSERT(block->page.status != buf_page_t::FREED);
+ DBUG_ASSERT(fail || block->page.status != buf_page_t::FREED);
buf_page_set_accessed(&block->page);
buf_block_buf_fix_inc(block, __FILE__, __LINE__);
@@ -1062,20 +1048,27 @@ got_no_latch:
rw_lock_s_unlock(use_latch);
buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH);
+ if (UNIV_UNLIKELY(fail)) {
+ btr_search_drop_page_hash_index(block);
+ goto fail_and_release_page;
+ }
+ } else if (UNIV_UNLIKELY(index != block->index
+ && index_id == block->index->id)) {
+ ut_a(block->index->freed());
+ goto fail_and_release_page;
}
if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
ut_ad(buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH);
+fail_and_release_page:
if (!ahi_latch) {
-
btr_leaf_page_release(block, latch_mode, mtr);
}
btr_search_failure(info, cursor);
-
- return(FALSE);
+ return false;
}
ut_ad(page_rec_is_user_rec(rec));
@@ -1091,14 +1084,7 @@ got_no_latch:
right. */
if (index_id != btr_page_get_index_id(block->frame)
|| !btr_search_check_guess(cursor, !!ahi_latch, tuple, mode)) {
-
- if (!ahi_latch) {
- btr_leaf_page_release(block, latch_mode, mtr);
- }
-
- btr_search_failure(info, cursor);
-
- return(FALSE);
+ goto fail_and_release_page;
}
if (info->n_hash_potential < BTR_SEARCH_BUILD_LIMIT + 5) {
@@ -1176,32 +1162,28 @@ void btr_search_drop_page_hash_index(buf_block_t* block)
ulint* folds;
ulint i;
mem_heap_t* heap;
- const dict_index_t* index;
rec_offs* offsets;
rw_lock_t* latch;
- btr_search_t* info;
retry:
- /* Do a dirty check on block->index, return if the block is
- not in the adaptive hash index. */
- index = block->index;
/* This debug check uses a dirty read that could theoretically cause
false positives while buf_pool.clear_hash_index() is executing. */
assert_block_ahi_valid(block);
ut_ad(!btr_search_own_any(RW_LOCK_S));
ut_ad(!btr_search_own_any(RW_LOCK_X));
- if (index == NULL) {
+ if (!block->index) {
return;
}
ut_ad(block->page.buf_fix_count == 0
|| buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH
|| rw_lock_own_flagged(&block->lock,
- RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
+ RW_LOCK_FLAG_X | RW_LOCK_FLAG_S
+ | RW_LOCK_FLAG_SX));
ut_ad(page_is_leaf(block->frame));
- /* We must not dereference index here, because it could be freed
+ /* We must not dereference block->index here, because it could be freed
if (index->table->n_ref_count == 0 && !mutex_own(&dict_sys.mutex)).
Determine the ahi_slot based on the block contents. */
@@ -1216,18 +1198,12 @@ retry:
rw_lock_s_lock(latch);
assert_block_ahi_valid(block);
- if (block->index == NULL) {
+ if (!block->index) {
rw_lock_s_unlock(latch);
return;
}
- /* The index associated with a block must remain the
- same, because we are holding block->lock or the block is
- not accessible by other threads (BUF_BLOCK_REMOVE_HASH),
- or the index is not accessible to other threads
- (buf_fix_count == 0 when DROP TABLE or similar is executing
- buf_LRU_drop_page_hash_for_tablespace()). */
- ut_a(index == block->index);
+ dict_index_t* index = block->index;
#ifdef MYSQL_INDEX_DISABLE_AHI
ut_ad(!index->disable_ahi);
#endif
@@ -1235,7 +1211,7 @@ retry:
ut_ad(block->page.id.space() == index->table->space_id);
ut_a(index_id == index->id);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
#ifdef UNIV_DEBUG
switch (dict_index_get_online_status(index)) {
case ONLINE_INDEX_CREATION:
@@ -1343,9 +1319,14 @@ next_rec:
folds[i], page);
}
- info = btr_search_get_info(block->index);
- ut_a(info->ref_count > 0);
- info->ref_count--;
+ switch (index->search_info->ref_count--) {
+ case 0:
+ ut_error;
+ case 1:
+ if (index->freed()) {
+ btr_search_lazy_free(index);
+ }
+ }
block->index = NULL;
@@ -1446,11 +1427,12 @@ btr_search_build_page_hash_index(
ut_ad(ahi_latch == btr_get_search_latch(index));
ut_ad(index);
ut_ad(block->page.id.space() == index->table->space_id);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
ut_ad(page_is_leaf(block->frame));
ut_ad(rw_lock_own_flagged(&block->lock,
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
+ ut_ad(block->page.id.page_no() >= 3);
rw_lock_s_lock(ahi_latch);
@@ -1643,11 +1625,7 @@ btr_search_info_update_slow(btr_search_t* info, btr_cur_t* cursor)
btr_search_n_hash_fail++;
#endif /* UNIV_SEARCH_PERF_STAT */
- rw_lock_x_lock(ahi_latch);
-
btr_search_update_hash_ref(info, block, cursor);
-
- rw_lock_x_unlock(ahi_latch);
}
if (build_index) {
@@ -1765,7 +1743,7 @@ void btr_search_update_hash_on_delete(btr_cur_t* cursor)
ut_ad(block->page.id.space() == index->table->space_id);
ut_a(index == cursor->index);
ut_a(block->curr_n_fields > 0 || block->curr_n_bytes > 0);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
table = btr_get_search_table(index);
@@ -1836,7 +1814,7 @@ btr_search_update_hash_node_on_insert(btr_cur_t* cursor, rw_lock_t* ahi_latch)
}
ut_a(cursor->index == index);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
rw_lock_x_lock(ahi_latch);
if (!block->index) {
@@ -1889,8 +1867,6 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor, rw_lock_t* ahi_latch)
ulint next_fold = 0; /* remove warning (??? bug ???) */
ulint n_fields;
ulint n_bytes;
- ibool left_side;
- bool locked = false;
mem_heap_t* heap = NULL;
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
rec_offs* offsets = offsets_;
@@ -1930,11 +1906,11 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor, rw_lock_t* ahi_latch)
ut_a(!index->disable_ahi);
#endif
ut_a(index == cursor->index);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
n_fields = block->curr_n_fields;
n_bytes = block->curr_n_bytes;
- left_side = block->curr_left_side;
+ const bool left_side = block->curr_left_side;
ins_rec = page_rec_get_next_const(rec);
next_rec = page_rec_get_next_const(ins_rec);
@@ -1951,6 +1927,8 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor, rw_lock_t* ahi_latch)
n_bytes, index->id);
}
+ bool locked = false;
+
if (!page_rec_is_infimum(rec) && !rec_is_metadata(rec, *index)) {
offsets = rec_get_offsets(
rec, index, offsets, true,
@@ -2009,7 +1987,6 @@ check_next_rec:
}
if (ins_fold != next_fold) {
-
if (!locked) {
locked = true;
rw_lock_x_lock(ahi_latch);
@@ -2135,7 +2112,7 @@ btr_search_hash_table_validate(ulint hash_table_id)
== BUF_BLOCK_REMOVE_HASH);
}
- ut_a(!dict_index_is_ibuf(block->index));
+ ut_ad(!dict_index_is_ibuf(block->index));
ut_ad(block->page.id.space()
== block->index->table->space_id);
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 4d38ded88fe..0c0d82efcb1 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -3231,7 +3231,7 @@ static buf_block_t* buf_page_mtr_lock(buf_block_t *block,
{
case RW_NO_LATCH:
fix_type= MTR_MEMO_BUF_FIX;
- break;
+ goto done;
case RW_S_LATCH:
rw_lock_s_lock_inline(&block->lock, 0, file, line);
fix_type= MTR_MEMO_PAGE_S_FIX;
@@ -3247,6 +3247,15 @@ static buf_block_t* buf_page_mtr_lock(buf_block_t *block,
break;
}
+#ifdef BTR_CUR_HASH_ADAPT
+ {
+ dict_index_t *index= block->index;
+ if (index && index->freed())
+ btr_search_drop_page_hash_index(block);
+ }
+#endif /* BTR_CUR_HASH_ADAPT */
+
+done:
mtr_memo_push(mtr, block, fix_type);
return block;
}
@@ -3578,6 +3587,7 @@ evict_from_pool:
mutex_exit(&buf_pool.mutex);
return(NULL);
}
+
break;
default:
ut_error;
@@ -4538,6 +4548,12 @@ buf_page_create(
rw_lock_x_unlock(hash_lock);
buf_block_free(free_block);
+#ifdef BTR_CUR_HASH_ADAPT
+ if (block->page.state == BUF_BLOCK_FILE_PAGE
+ && UNIV_LIKELY_NULL(block->index)) {
+ btr_search_drop_page_hash_index(block);
+ }
+#endif /* BTR_CUR_HASH_ADAPT */
if (!recv_recovery_is_on()) {
/* FIXME: Remove the redundant lookup and avoid
@@ -5015,9 +5031,8 @@ buf_page_io_complete(buf_page_t* bpage, bool dblwr, bool evict)
err = buf_page_check_corrupt(bpage, space);
-database_corrupted:
-
if (err != DB_SUCCESS) {
+database_corrupted:
/* Not a real corruption if it was triggered by
error injection */
DBUG_EXECUTE_IF(
@@ -5034,6 +5049,11 @@ database_corrupted:
goto page_not_corrupt;
);
+ if (uncompressed && bpage->zip.data) {
+ memset(reinterpret_cast<buf_block_t*>(bpage)
+ ->frame, 0, srv_page_size);
+ }
+
if (err == DB_PAGE_CORRUPTED) {
ib::error()
<< "Database page corruption on disk"
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 2ee0c02d964..eb20aca98a0 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -210,157 +210,6 @@ bool buf_LRU_evict_from_unzip_LRU()
}
#ifdef BTR_CUR_HASH_ADAPT
-/** Attempts to drop page hash index on a batch of pages belonging to a
-particular space id.
-@param[in] space_id space id
-@param[in] arr array of page_no
-@param[in] count number of entries in array */
-static
-void
-buf_LRU_drop_page_hash_batch(ulint space_id, const ulint* arr, ulint count)
-{
- ut_ad(count <= BUF_LRU_DROP_SEARCH_SIZE);
-
- for (const ulint* const end = arr + count; arr != end; ) {
- /* While our only caller
- buf_LRU_drop_page_hash_for_tablespace()
- is being executed for DROP TABLE or similar,
- the table cannot be evicted from the buffer pool. */
- btr_search_drop_page_hash_when_freed(
- page_id_t(space_id, *arr++));
- }
-}
-
-/******************************************************************//**
-When doing a DROP TABLE/DISCARD TABLESPACE we have to drop all page
-hash index entries belonging to that table. This function tries to
-do that in batch. Note that this is a 'best effort' attempt and does
-not guarantee that ALL hash entries will be removed.
-@param[in] id space id */
-static
-void
-buf_LRU_drop_page_hash_for_tablespace(ulint id)
-{
- ulint* page_arr = static_cast<ulint*>(ut_malloc_nokey(
- sizeof(ulint) * BUF_LRU_DROP_SEARCH_SIZE));
-
- ulint num_entries = 0;
-
- mutex_enter(&buf_pool.mutex);
-
-scan_again:
- for (buf_page_t* bpage = UT_LIST_GET_LAST(buf_pool.LRU);
- bpage != NULL;
- /* No op */) {
-
- buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
-
- ut_a(buf_page_in_file(bpage));
-
- if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE
- || bpage->id.space() != id
- || bpage->io_fix != BUF_IO_NONE) {
- /* Compressed pages are never hashed.
- Skip blocks of other tablespaces.
- Skip I/O-fixed blocks (to be dealt with later). */
-next_page:
- bpage = prev_bpage;
- continue;
- }
-
- buf_block_t* block = reinterpret_cast<buf_block_t*>(bpage);
-
- mutex_enter(&block->mutex);
-
- /* This debug check uses a dirty read that could
- theoretically cause false positives while
- buf_pool.clear_hash_index() is executing.
- (Other conflicting access paths to the adaptive hash
- index should not be possible, because when a
- tablespace is being discarded or dropped, there must
- be no concurrect access to the contained tables.) */
- assert_block_ahi_valid(block);
-
- bool skip = bpage->buf_fix_count > 0 || !block->index;
-
- mutex_exit(&block->mutex);
-
- if (skip) {
- /* Skip this block, because there are
- no adaptive hash index entries
- pointing to it, or because we cannot
- drop them due to the buffer-fix. */
- goto next_page;
- }
-
- /* Store the page number so that we can drop the hash
- index in a batch later. */
- page_arr[num_entries] = bpage->id.page_no();
- ut_a(num_entries < BUF_LRU_DROP_SEARCH_SIZE);
- ++num_entries;
-
- if (num_entries < BUF_LRU_DROP_SEARCH_SIZE) {
- goto next_page;
- }
-
- /* Array full. We release the buf_pool.mutex to obey
- the latching order. */
- mutex_exit(&buf_pool.mutex);
-
- buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
-
- num_entries = 0;
-
- mutex_enter(&buf_pool.mutex);
-
- /* Note that we released the buf_pool mutex above
- after reading the prev_bpage during processing of a
- page_hash_batch (i.e.: when the array was full).
- Because prev_bpage could belong to a compressed-only
- block, it may have been relocated, and thus the
- pointer cannot be trusted. Because bpage is of type
- buf_block_t, it is safe to dereference.
-
- bpage can change in the LRU list. This is OK because
- this function is a 'best effort' to drop as many
- search hash entries as possible and it does not
- guarantee that ALL such entries will be dropped. */
-
- /* If, however, bpage has been removed from LRU list
- to the free list then we should restart the scan.
- bpage->state is protected by buf_pool mutex. */
- if (bpage != NULL
- && buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
-
- goto scan_again;
- }
- }
-
- mutex_exit(&buf_pool.mutex);
-
- /* Drop any remaining batch of search hashed pages. */
- buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
- ut_free(page_arr);
-}
-
-/** Try to drop the adaptive hash index for a tablespace.
-@param[in,out] table table
-@return whether anything was dropped */
-bool buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table)
-{
- for (dict_index_t* index = dict_table_get_first_index(table);
- index != NULL;
- index = dict_table_get_next_index(index)) {
- if (btr_search_info_get_ref_count(btr_search_get_info(index),
- index)) {
- buf_LRU_drop_page_hash_for_tablespace(table->space_id);
- return true;
- }
- }
-
- return false;
-}
-
/**
While flushing (or removing dirty) pages from a tablespace we don't
want to hog the CPU and resources. Release the buffer pool and block
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index a5a7fe9f2d7..4a2212d1c41 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -26,7 +26,9 @@ Created 1/8/1996 Heikki Tuuri
#include "dict0crea.h"
#include "btr0pcur.h"
-#include "btr0btr.h"
+#ifdef BTR_CUR_HASH_ADAPT
+# include "btr0sea.h"
+#endif /* BTR_CUR_HASH_ADAPT */
#include "page0page.h"
#include "mach0data.h"
#include "dict0boot.h"
@@ -1300,6 +1302,9 @@ dict_create_index_step(
&node->table->fts->cache->init_lock);
}
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!node->index->search_info->ref_count);
+#endif /* BTR_CUR_HASH_ADAPT */
dict_index_remove_from_cache(node->table, node->index);
node->index = NULL;
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index d129432d59c..28876716375 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1249,25 +1249,12 @@ dict_table_can_be_evicted(
}
#ifdef BTR_CUR_HASH_ADAPT
+ /* We cannot really evict the table if adaptive hash
+ index entries are pointing to any of its indexes. */
for (dict_index_t* index = dict_table_get_first_index(table);
index != NULL;
index = dict_table_get_next_index(index)) {
-
- btr_search_t* info = btr_search_get_info(index);
-
- /* We are not allowed to free the in-memory index
- struct dict_index_t until all entries in the adaptive
- hash index that point to any of the page belonging to
- his b-tree index are dropped. This is so because
- dropping of these entries require access to
- dict_index_t struct. To avoid such scenario we keep
- a count of number of such pages in the search_info and
- only free the dict_index_t struct when this count
- drops to zero.
-
- See also: dict_index_remove_from_cache_low() */
-
- if (btr_search_info_get_ref_count(info, index) > 0) {
+ if (index->n_ahi_pages()) {
return(FALSE);
}
}
@@ -1279,6 +1266,70 @@ dict_table_can_be_evicted(
return(FALSE);
}
+#ifdef BTR_CUR_HASH_ADAPT
+/** @return a clone of this */
+dict_index_t *dict_index_t::clone() const
+{
+ ut_ad(n_fields);
+ ut_ad(!(type & (DICT_IBUF | DICT_SPATIAL | DICT_FTS)));
+ ut_ad(online_status == ONLINE_INDEX_COMPLETE);
+ ut_ad(is_committed());
+ ut_ad(!is_dummy);
+ ut_ad(!parser);
+ ut_ad(!online_log);
+ ut_ad(!rtr_track);
+
+ const size_t size= sizeof *this + n_fields * sizeof(*fields) +
+#ifdef BTR_CUR_ADAPT
+ sizeof *search_info +
+#endif
+ 1 + strlen(name) +
+ n_uniq * (sizeof *stat_n_diff_key_vals +
+ sizeof *stat_n_sample_sizes +
+ sizeof *stat_n_non_null_key_vals);
+
+ mem_heap_t* heap= mem_heap_create(size);
+ dict_index_t *index= static_cast<dict_index_t*>(mem_heap_dup(heap, this,
+ sizeof *this));
+ *index= *this;
+ rw_lock_create(index_tree_rw_lock_key, &index->lock, SYNC_INDEX_TREE);
+ index->heap= heap;
+ index->name= mem_heap_strdup(heap, name);
+ index->fields= static_cast<dict_field_t*>
+ (mem_heap_dup(heap, fields, n_fields * sizeof *fields));
+#ifdef BTR_CUR_ADAPT
+ index->search_info= btr_search_info_create(index->heap);
+#endif /* BTR_CUR_ADAPT */
+ index->stat_n_diff_key_vals= static_cast<ib_uint64_t*>
+ (mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_diff_key_vals));
+ index->stat_n_sample_sizes= static_cast<ib_uint64_t*>
+ (mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_sample_sizes));
+ index->stat_n_non_null_key_vals= static_cast<ib_uint64_t*>
+ (mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_non_null_key_vals));
+ mutex_create(LATCH_ID_ZIP_PAD_MUTEX, &index->zip_pad.mutex);
+ return index;
+}
+
+/** Clone this index for lazy dropping of the adaptive hash.
+@return this or a clone */
+dict_index_t *dict_index_t::clone_if_needed()
+{
+ if (!search_info->ref_count)
+ return this;
+ dict_index_t *prev= UT_LIST_GET_PREV(indexes, this);
+
+ UT_LIST_REMOVE(table->indexes, this);
+ UT_LIST_ADD_LAST(table->freed_indexes, this);
+ dict_index_t *index= clone();
+ set_freed();
+ if (prev)
+ UT_LIST_INSERT_AFTER(table->indexes, prev, index);
+ else
+ UT_LIST_ADD_FIRST(table->indexes, index);
+ return index;
+}
+#endif /* BTR_CUR_HASH_ADAPT */
+
/**********************************************************************//**
Make room in the table cache by evicting an unused table. The unused table
should not be part of FK relationship and currently not used in any user
@@ -1919,9 +1970,19 @@ void dict_sys_t::remove(dict_table_t* table, bool lru, bool keep)
mutex_free(&table->autoinc_mutex);
- if (!keep) {
- dict_mem_table_free(table);
+ if (keep) {
+ return;
+ }
+
+#ifdef BTR_CUR_HASH_ADAPT
+ if (UNIV_UNLIKELY(UT_LIST_GET_LEN(table->freed_indexes) != 0)) {
+ table->vc_templ = NULL;
+ table->id = 0;
+ return;
}
+#endif /* BTR_CUR_HASH_ADAPT */
+
+ dict_mem_table_free(table);
}
/****************************************************************//**
@@ -2099,6 +2160,8 @@ dict_index_remove_from_cache_low(
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
ut_ad(mutex_own(&dict_sys.mutex));
+ ut_ad(table->id);
+ ut_ad(!index->freed());
/* No need to acquire the dict_index_t::lock here because
there can't be any active operations on this index (or table). */
@@ -2108,13 +2171,22 @@ dict_index_remove_from_cache_low(
row_log_free(index->online_log);
}
+ /* Remove the index from the list of indexes of the table */
+ UT_LIST_REMOVE(table->indexes, index);
+
+ /* The index is being dropped, remove any compression stats for it. */
+ if (!lru_evict && DICT_TF_GET_ZIP_SSIZE(index->table->flags)) {
+ mutex_enter(&page_zip_stat_per_index_mutex);
+ page_zip_stat_per_index.erase(index->id);
+ mutex_exit(&page_zip_stat_per_index_mutex);
+ }
+
+ /* Remove the index from affected virtual column index list */
+ index->detach_columns();
+
#ifdef BTR_CUR_HASH_ADAPT
/* We always create search info whether or not adaptive
hash index is enabled or not. */
- btr_search_t* info = btr_search_get_info(index);
- ulint retries = 0;
- ut_ad(info);
-
/* We are not allowed to free the in-memory index struct
dict_index_t until all entries in the adaptive hash index
that point to any of the page belonging to his b-tree index
@@ -2124,31 +2196,15 @@ dict_index_remove_from_cache_low(
only free the dict_index_t struct when this count drops to
zero. See also: dict_table_can_be_evicted() */
- do {
- if (!btr_search_info_get_ref_count(info, index)
- || !buf_LRU_drop_page_hash_for_tablespace(table)) {
- break;
- }
-
- ut_a(++retries < 10000);
- } while (srv_shutdown_state == SRV_SHUTDOWN_NONE || !lru_evict);
+ if (index->n_ahi_pages()) {
+ index->set_freed();
+ UT_LIST_ADD_LAST(table->freed_indexes, index);
+ return;
+ }
#endif /* BTR_CUR_HASH_ADAPT */
rw_lock_free(&index->lock);
- /* The index is being dropped, remove any compression stats for it. */
- if (!lru_evict && DICT_TF_GET_ZIP_SSIZE(index->table->flags)) {
- mutex_enter(&page_zip_stat_per_index_mutex);
- page_zip_stat_per_index.erase(index->id);
- mutex_exit(&page_zip_stat_per_index_mutex);
- }
-
- /* Remove the index from the list of indexes of the table */
- UT_LIST_REMOVE(table->indexes, index);
-
- /* Remove the index from affected virtual column index list */
- index->detach_columns();
-
dict_mem_index_free(index);
}
@@ -5075,10 +5131,7 @@ dict_index_zip_pad_update(
beyond max pad size. */
if (info->pad + ZIP_PAD_INCR
< (srv_page_size * zip_pad_max) / 100) {
- /* Use atomics even though we have the mutex.
- This is to ensure that we are able to read
- info->pad atomically. */
- info->pad += ZIP_PAD_INCR;
+ info->pad.fetch_add(ZIP_PAD_INCR);
MONITOR_INC(MONITOR_PAD_INCREMENTS);
}
@@ -5095,11 +5148,7 @@ dict_index_zip_pad_update(
padding. */
if (info->n_rounds >= ZIP_PAD_SUCCESSFUL_ROUND_LIMIT
&& info->pad > 0) {
-
- /* Use atomics even though we have the mutex.
- This is to ensure that we are able to read
- info->pad atomically. */
- info->pad -= ZIP_PAD_INCR;
+ info->pad.fetch_sub(ZIP_PAD_INCR);
info->n_rounds = 0;
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index a6a7951a758..22a77a7a220 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -157,6 +157,9 @@ dict_mem_table_create(
lock_table_lock_list_init(&table->locks);
UT_LIST_INIT(table->indexes, &dict_index_t::indexes);
+#ifdef BTR_CUR_HASH_ADAPT
+ UT_LIST_INIT(table->freed_indexes, &dict_index_t::indexes);
+#endif /* BTR_CUR_HASH_ADAPT */
table->heap = heap;
@@ -216,6 +219,10 @@ dict_mem_table_free(
{
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
+ ut_ad(UT_LIST_GET_LEN(table->indexes) == 0);
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(UT_LIST_GET_LEN(table->freed_indexes) == 0);
+#endif /* BTR_CUR_HASH_ADAPT */
ut_d(table->cached = FALSE);
if (dict_table_has_fts_index(table)
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index a63798dc321..1111bcb1cf0 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -419,6 +419,9 @@ dict_stats_table_clone_create(
t->corrupted = table->corrupted;
UT_LIST_INIT(t->indexes, &dict_index_t::indexes);
+#ifdef BTR_CUR_HASH_ADAPT
+ UT_LIST_INIT(t->freed_indexes, &dict_index_t::indexes);
+#endif /* BTR_CUR_HASH_ADAPT */
for (index = dict_table_get_first_index(table);
index != NULL;
@@ -4028,6 +4031,9 @@ test_dict_stats_save()
table.stat_clustered_index_size = TEST_CLUSTERED_INDEX_SIZE;
table.stat_sum_of_other_index_sizes = TEST_SUM_OF_OTHER_INDEX_SIZES;
UT_LIST_INIT(table.indexes, &dict_index_t::indexes);
+#ifdef BTR_CUR_HASH_ADAPT
+ UT_LIST_INIT(table.freed_indexes, &dict_index_t::indexes);
+#endif /* BTR_CUR_HASH_ADAPT */
UT_LIST_ADD_LAST(table.indexes, &index1);
UT_LIST_ADD_LAST(table.indexes, &index2);
ut_d(table.magic_n = DICT_TABLE_MAGIC_N);
@@ -4177,6 +4183,9 @@ test_dict_stats_fetch_from_ps()
/* craft a dummy dict_table_t */
table.name.m_name = (char*) (TEST_DATABASE_NAME "/" TEST_TABLE_NAME);
UT_LIST_INIT(table.indexes, &dict_index_t::indexes);
+#ifdef BTR_CUR_HASH_ADAPT
+ UT_LIST_INIT(table.freed_indexes, &dict_index_t::indexes);
+#endif /* BTR_CUR_HASH_ADAPT */
UT_LIST_ADD_LAST(table.indexes, &index1);
UT_LIST_ADD_LAST(table.indexes, &index2);
ut_d(table.magic_n = DICT_TABLE_MAGIC_N);
diff --git a/storage/innobase/fil/fil0pagecompress.cc b/storage/innobase/fil/fil0pagecompress.cc
index d3cdacf5125..d3f6a9af72f 100644
--- a/storage/innobase/fil/fil0pagecompress.cc
+++ b/storage/innobase/fil/fil0pagecompress.cc
@@ -27,7 +27,6 @@ Updated 14/02/2015
#include "fil0fil.h"
#include "fil0pagecompress.h"
-#include <debug_sync.h>
#include <my_dbug.h>
#include "mem0mem.h"
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index ef162abf39a..90d62835856 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -2485,8 +2485,6 @@ try_to_extend:
@param[in] seg_inode segment inode
@param[in,out] space tablespace
@param[in] offset page number
-@param[in] ahi whether we may need to drop the adaptive
-hash index
@param[in,out] mtr mini-transaction */
static
void
@@ -2495,9 +2493,6 @@ fseg_free_page_low(
buf_block_t* iblock,
fil_space_t* space,
page_no_t offset,
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi,
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr)
{
ib_id_t descr_id;
@@ -2510,15 +2505,6 @@ fseg_free_page_low(
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
ut_ad(iblock->frame == page_align(seg_inode));
ut_d(space->modify_check(*mtr));
-#ifdef BTR_CUR_HASH_ADAPT
- /* Drop search system page hash index if the page is found in
- the pool and is hashed */
-
- if (ahi) {
- btr_search_drop_page_hash_when_freed(
- page_id_t(space->id, offset));
- }
-#endif /* BTR_CUR_HASH_ADAPT */
buf_block_t* xdes;
xdes_t* descr = xdes_get_descriptor(space, offset, &xdes, mtr);
@@ -2607,26 +2593,16 @@ fseg_free_page_low(
mtr->free(page_id_t(space->id, offset));
}
-#ifndef BTR_CUR_HASH_ADAPT
-# define fseg_free_page_low(inode, space, offset, ahi, mtr) \
- fseg_free_page_low(inode, space, offset, mtr)
-#endif /* !BTR_CUR_HASH_ADAPT */
-
/** Free a page in a file segment.
@param[in,out] seg_header file segment header
@param[in,out] space tablespace
@param[in] offset page number
-@param[in] ahi whether we may need to drop the adaptive
-hash index
@param[in,out] mtr mini-transaction */
void
-fseg_free_page_func(
+fseg_free_page(
fseg_header_t* seg_header,
fil_space_t* space,
ulint offset,
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi,
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr)
{
DBUG_ENTER("fseg_free_page");
@@ -2644,7 +2620,7 @@ fseg_free_page_func(
fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr);
}
- fseg_free_page_low(seg_inode, iblock, space, offset, ahi, mtr);
+ fseg_free_page_low(seg_inode, iblock, space, offset, mtr);
buf_page_free(page_id_t(space->id, offset), mtr, __FILE__, __LINE__);
@@ -2683,8 +2659,6 @@ fseg_page_is_free(fil_space_t* space, unsigned page)
@param[in,out] seg_inode segment inode
@param[in,out] space tablespace
@param[in] page page number in the extent
-@param[in] ahi whether we may need to drop
- the adaptive hash index
@param[in,out] mtr mini-transaction */
MY_ATTRIBUTE((nonnull))
static
@@ -2694,12 +2668,8 @@ fseg_free_extent(
buf_block_t* iblock,
fil_space_t* space,
ulint page,
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi,
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr)
{
- ulint first_page_in_extent;
ut_ad(mtr != NULL);
@@ -2712,23 +2682,9 @@ fseg_free_extent(
== FSEG_MAGIC_N_VALUE);
ut_d(space->modify_check(*mtr));
- first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
-
-#ifdef BTR_CUR_HASH_ADAPT
- if (ahi) {
- for (ulint i = 0; i < FSP_EXTENT_SIZE; i++) {
- if (!xdes_is_free(descr, i)) {
- /* Drop search system page hash index
- if the page is found in the pool and
- is hashed */
-
- btr_search_drop_page_hash_when_freed(
- page_id_t(space->id,
- first_page_in_extent + i));
- }
- }
- }
-#endif /* BTR_CUR_HASH_ADAPT */
+#if defined BTR_CUR_HASH_ADAPT || defined UNIV_DEBUG
+ const ulint first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
+#endif /* BTR_CUR_HASH_ADAPT || UNIV_DEBUG */
const uint16_t xoffset= uint16_t(descr - xdes->frame + XDES_FLST_NODE);
const uint16_t ioffset= uint16_t(seg_inode - iblock->frame);
@@ -2762,27 +2718,18 @@ fseg_free_extent(
}
}
-#ifndef BTR_CUR_HASH_ADAPT
-# define fseg_free_extent(inode, iblock, space, page, ahi, mtr) \
- fseg_free_extent(inode, iblock, space, page, mtr)
-#endif /* !BTR_CUR_HASH_ADAPT */
-
/**********************************************************************//**
Frees part of a segment. This function can be used to free a segment by
repeatedly calling this function in different mini-transactions. Doing
the freeing in a single mini-transaction might result in too big a
mini-transaction.
-@return true if freeing completed */
+@return whether the freeing was completed */
bool
-fseg_free_step_func(
+fseg_free_step(
fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
resides on the first page of the frag list
of the segment, this pointer becomes obsolete
after the last freeing step */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint n;
@@ -2822,7 +2769,7 @@ fseg_free_step_func(
if (descr != NULL) {
/* Free the extent held by the segment */
page = xdes_get_offset(descr);
- fseg_free_extent(inode, iblock, space, page, ahi, mtr);
+ fseg_free_extent(inode, iblock, space, page, mtr);
DBUG_RETURN(false);
}
@@ -2839,7 +2786,7 @@ fseg_free_step_func(
fseg_free_page_low(
inode, iblock, space,
fseg_get_nth_frag_page_no(inode, n, mtr),
- ahi, mtr);
+ mtr);
n = fseg_find_last_used_frag_page_slot(inode, mtr);
@@ -2856,15 +2803,11 @@ fseg_free_step_func(
/**********************************************************************//**
Frees part of a segment. Differs from fseg_free_step because this function
leaves the header page unfreed.
-@return true if freeing completed, except the header page */
+@return whether the freeing was completed, except for the header page */
bool
-fseg_free_step_not_header_func(
+fseg_free_step_not_header(
fseg_header_t* header, /*!< in: segment header which must reside on
the first fragment page of the segment */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint n;
@@ -2891,30 +2834,24 @@ fseg_free_step_not_header_func(
if (descr != NULL) {
/* Free the extent held by the segment */
page = xdes_get_offset(descr);
-
- fseg_free_extent(inode, iblock, space, page, ahi, mtr);
-
- return(false);
+ fseg_free_extent(inode, iblock, space, page, mtr);
+ return false;
}
/* Free a frag page */
n = fseg_find_last_used_frag_page_slot(inode, mtr);
- if (n == ULINT_UNDEFINED) {
- ut_error;
- }
+ ut_a(n != ULINT_UNDEFINED);
page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
if (page_no == page_get_page_no(page_align(header))) {
-
- return(true);
+ return true;
}
- fseg_free_page_low(inode, iblock, space, page_no, ahi, mtr);
-
- return(false);
+ fseg_free_page_low(inode, iblock, space, page_no, mtr);
+ return false;
}
/** Returns the first extent descriptor for a segment.
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 61bc6eec47e..7720c7f0897 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -1024,6 +1024,7 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
for (ulint i = 0; i < num_to_add_index; i++) {
if (!add_index[i]->is_committed()) {
add_index[i]->detach_columns();
+ add_index[i]->n_fields = 0;
}
}
}
@@ -11117,21 +11118,14 @@ foreign_fail:
|| (ctx0->is_instant()
&& m_prebuilt->table->n_v_cols
&& ha_alter_info->handler_flags & ALTER_STORED_COLUMN_ORDER)) {
+ /* FIXME: this workaround does not seem to work with
+ partitioned tables */
DBUG_ASSERT(ctx0->old_table->get_ref_count() == 1);
trx_commit_for_mysql(m_prebuilt->trx);
-#ifdef BTR_CUR_HASH_ADAPT
- if (btr_search_enabled) {
- btr_search_disable(false);
- btr_search_enable();
- }
-#endif /* BTR_CUR_HASH_ADAPT */
- char tb_name[FN_REFLEN];
+ char tb_name[NAME_LEN * 2 + 1 + 1];
strcpy(tb_name, m_prebuilt->table->name.m_name);
-
- tb_name[strlen(m_prebuilt->table->name.m_name)] = 0;
-
dict_table_close(m_prebuilt->table, true, false);
if (ctx0->is_instant()) {
for (unsigned i = ctx0->old_n_v_cols; i--; ) {
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index a9474295af8..e09866c32c5 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -1951,7 +1951,7 @@ ibuf_remove_free_page(void)
compile_time_assert(IBUF_SPACE_ID == 0);
fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
- fil_system.sys_space, page_no, false, &mtr);
+ fil_system.sys_space, page_no, &mtr);
const page_id_t page_id(IBUF_SPACE_ID, page_no);
diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h
index 1ffc2eb4d76..bceb35a6969 100644
--- a/storage/innobase/include/btr0pcur.h
+++ b/storage/innobase/include/btr0pcur.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, 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
diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic
index 4c3c3359262..9c99da42b97 100644
--- a/storage/innobase/include/btr0pcur.ic
+++ b/storage/innobase/include/btr0pcur.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2019, MariaDB Corporation.
+Copyright (c) 2015, 2020, 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
diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h
index cc62c4cad77..c77faed50e1 100644
--- a/storage/innobase/include/btr0sea.h
+++ b/storage/innobase/include/btr0sea.h
@@ -48,15 +48,6 @@ void btr_search_disable(bool need_mutex);
/** Enable the adaptive hash search system. */
void btr_search_enable();
-/** Returns the value of ref_count. The value is protected by latch.
-@param[in] info search info
-@param[in] index index identifier
-@return ref_count value. */
-ulint
-btr_search_info_get_ref_count(
- btr_search_t* info,
- dict_index_t* index);
-
/*********************************************************************//**
Updates the search info. */
UNIV_INLINE
@@ -272,6 +263,18 @@ struct btr_search_t{
};
#ifdef BTR_CUR_HASH_ADAPT
+/** @return number of leaf pages pointed to by the adaptive hash index */
+inline ulint dict_index_t::n_ahi_pages() const
+{
+ if (!btr_search_enabled)
+ return 0;
+ rw_lock_t *latch = btr_get_search_latch(this);
+ rw_lock_s_lock(latch);
+ ulint ref_count= search_info->ref_count;
+ rw_lock_s_unlock(latch);
+ return ref_count;
+}
+
/** The hash index system */
struct btr_search_sys_t{
hash_table_t** hash_tables; /*!< the adaptive hash tables,
diff --git a/storage/innobase/include/btr0sea.ic b/storage/innobase/include/btr0sea.ic
index 17bc7e555bd..9db0084ce59 100644
--- a/storage/innobase/include/btr0sea.ic
+++ b/storage/innobase/include/btr0sea.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2018, MariaDB Corporation.
+Copyright (c) 2018, 2020, 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
diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h
index 9ed42f4eed0..eebe7bf5f1d 100644
--- a/storage/innobase/include/buf0lru.h
+++ b/storage/innobase/include/buf0lru.h
@@ -45,17 +45,6 @@ These are low-level functions
/** Minimum LRU list length for which the LRU_old pointer is defined */
#define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */
-#ifdef BTR_CUR_HASH_ADAPT
-struct dict_table_t;
-/** Try to drop the adaptive hash index for a tablespace.
-@param[in,out] table table
-@return whether anything was dropped */
-bool buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table)
- MY_ATTRIBUTE((warn_unused_result,nonnull));
-#else
-# define buf_LRU_drop_page_hash_for_tablespace(table)
-#endif /* BTR_CUR_HASH_ADAPT */
-
/** Empty the flush list for all pages belonging to a tablespace.
@param[in] id tablespace identifier
@param[in] flush whether to write the pages to files
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index e3b3ffbeb91..1691cb22512 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -932,7 +932,7 @@ an uncompressed page should be left as padding to avoid compression
failures. This estimate is based on a self-adapting heuristic. */
struct zip_pad_info_t {
SysMutex mutex; /*!< mutex protecting the info */
- Atomic_counter<ulint>
+ Atomic_relaxed<ulint>
pad; /*!< number of bytes used as pad */
ulint success;/*!< successful compression ops during
current round */
@@ -960,7 +960,10 @@ struct dict_index_t {
mem_heap_t* heap; /*!< memory heap */
id_name_t name; /*!< index name */
dict_table_t* table; /*!< back pointer to table */
- unsigned page:32;/*!< index tree root page number */
+ /** root page number, or FIL_NULL if the index has been detached
+ from storage (DISCARD TABLESPACE or similar),
+ or 1 if the index is in table->freed_indexes */
+ unsigned page:32;
unsigned merge_threshold:6;
/*!< In the pessimistic delete, if the page
data size drops below this limit in percent,
@@ -1105,19 +1108,11 @@ struct dict_index_t {
/* @} */
private:
/** R-tree split sequence number */
- std::atomic<node_seq_t> rtr_ssn;
+ Atomic_relaxed<node_seq_t> rtr_ssn;
public:
-
- void set_ssn(node_seq_t ssn)
- {
- rtr_ssn.store(ssn, std::memory_order_relaxed);
- }
- node_seq_t assign_ssn()
- {
- node_seq_t ssn= rtr_ssn.fetch_add(1, std::memory_order_relaxed);
- return ssn + 1;
- }
- node_seq_t ssn() const { return rtr_ssn.load(std::memory_order_relaxed); }
+ void set_ssn(node_seq_t ssn) { rtr_ssn= ssn; }
+ node_seq_t assign_ssn() { return rtr_ssn.fetch_add(1) + 1; }
+ node_seq_t ssn() const { return rtr_ssn; }
rtr_info_track_t*
rtr_track;/*!< tracking all R-Tree search cursors */
@@ -1216,8 +1211,6 @@ public:
for (unsigned i = 0; i < n_fields; i++) {
fields[i].col->detach(*this);
}
-
- n_fields = 0;
}
}
@@ -1280,15 +1273,29 @@ public:
bool
vers_history_row(const rec_t* rec, bool &history_row);
- /** Reconstruct the clustered index fields. */
- inline void reconstruct_fields();
+ /** Reconstruct the clustered index fields. */
+ inline void reconstruct_fields();
- /** Check if the index contains a column or a prefix of that column.
- @param[in] n column number
- @param[in] is_virtual whether it is a virtual col
- @return whether the index contains the column or its prefix */
- bool contains_col_or_prefix(ulint n, bool is_virtual) const
- MY_ATTRIBUTE((warn_unused_result));
+ /** Check if the index contains a column or a prefix of that column.
+ @param[in] n column number
+ @param[in] is_virtual whether it is a virtual col
+ @return whether the index contains the column or its prefix */
+ bool contains_col_or_prefix(ulint n, bool is_virtual) const
+ MY_ATTRIBUTE((warn_unused_result));
+
+#ifdef BTR_CUR_HASH_ADAPT
+ /** @return a clone of this */
+ dict_index_t* clone() const;
+ /** Clone this index for lazy dropping of the adaptive hash index.
+ @return this or a clone */
+ dict_index_t* clone_if_needed();
+ /** @return number of leaf pages pointed to by the adaptive hash index */
+ inline ulint n_ahi_pages() const;
+ /** @return whether mark_freed() had been invoked */
+ bool freed() const { return UNIV_UNLIKELY(page == 1); }
+ /** Note that the index is waiting for btr_search_lazy_free() */
+ void set_freed() { ut_ad(!freed()); page= 1; }
+#endif /* BTR_CUR_HASH_ADAPT */
/** This ad-hoc class is used by record_size_info only. */
class record_size_info_t {
@@ -2062,6 +2069,11 @@ public:
/** List of indexes of the table. */
UT_LIST_BASE_NODE_T(dict_index_t) indexes;
+#ifdef BTR_CUR_HASH_ADAPT
+ /** List of detached indexes that are waiting to be freed along with
+ the last adaptive hash index entry */
+ UT_LIST_BASE_NODE_T(dict_index_t) freed_indexes;
+#endif /* BTR_CUR_HASH_ADAPT */
/** List of foreign key constraints in the table. These refer to
columns in other tables. */
diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h
index 7a945f3a59e..7a1385598db 100644
--- a/storage/innobase/include/fsp0fsp.h
+++ b/storage/innobase/include/fsp0fsp.h
@@ -487,25 +487,13 @@ fsp_reserve_free_extents(
@param[in,out] seg_header file segment header
@param[in,out] space tablespace
@param[in] offset page number
-@param[in] ahi whether we may need to drop the adaptive
-hash index
@param[in,out] mtr mini-transaction */
void
-fseg_free_page_func(
+fseg_free_page(
fseg_header_t* seg_header,
fil_space_t* space,
ulint offset,
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi,
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr);
-#ifdef BTR_CUR_HASH_ADAPT
-# define fseg_free_page(header, space, offset, ahi, mtr) \
- fseg_free_page_func(header, space, offset, ahi, mtr)
-#else /* BTR_CUR_HASH_ADAPT */
-# define fseg_free_page(header, space, offset, ahi, mtr) \
- fseg_free_page_func(header, space, offset, mtr)
-#endif /* BTR_CUR_HASH_ADAPT */
/** Determine whether a page is free.
@param[in,out] space tablespace
@param[in] page page number
@@ -518,45 +506,25 @@ Frees part of a segment. This function can be used to free a segment
by repeatedly calling this function in different mini-transactions.
Doing the freeing in a single mini-transaction might result in
too big a mini-transaction.
-@return TRUE if freeing completed */
+@return whether the freeing was completed */
bool
-fseg_free_step_func(
+fseg_free_step(
fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
resides on the first page of the frag list
of the segment, this pointer becomes obsolete
after the last freeing step */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr) /*!< in/out: mini-transaction */
MY_ATTRIBUTE((warn_unused_result));
-#ifdef BTR_CUR_HASH_ADAPT
-# define fseg_free_step(header, ahi, mtr) fseg_free_step_func(header, ahi, mtr)
-#else /* BTR_CUR_HASH_ADAPT */
-# define fseg_free_step(header, ahi, mtr) fseg_free_step_func(header, mtr)
-#endif /* BTR_CUR_HASH_ADAPT */
/**********************************************************************//**
Frees part of a segment. Differs from fseg_free_step because this function
leaves the header page unfreed.
-@return true if freeing completed, except the header page */
+@return whether the freeing was completed, except for the header page */
bool
-fseg_free_step_not_header_func(
+fseg_free_step_not_header(
fseg_header_t* header, /*!< in: segment header which must reside on
the first fragment page of the segment */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr) /*!< in/out: mini-transaction */
MY_ATTRIBUTE((warn_unused_result));
-#ifdef BTR_CUR_HASH_ADAPT
-# define fseg_free_step_not_header(header, ahi, mtr) \
- fseg_free_step_not_header_func(header, ahi, mtr)
-#else /* BTR_CUR_HASH_ADAPT */
-# define fseg_free_step_not_header(header, ahi, mtr) \
- fseg_free_step_not_header_func(header, mtr)
-#endif /* BTR_CUR_HASH_ADAPT */
/** Reset the page type.
Data files created before MySQL 5.1.48 may contain garbage in FIL_PAGE_TYPE.
diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h
index bf47cb8fe88..48528eb4d30 100644
--- a/storage/innobase/include/sync0rw.h
+++ b/storage/innobase/include/sync0rw.h
@@ -2,7 +2,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -568,11 +568,11 @@ struct rw_lock_t
: public latch_t
#endif /* UNIV_DEBUG */
{
- /** Holds the state of the lock. */
- std::atomic<int32_t> lock_word;
+ /** Holds the state of the lock. */
+ Atomic_relaxed<int32_t> lock_word;
- /** 1: there are waiters */
- std::atomic<int32_t> waiters;
+ /** 0=no waiters, 1=waiters for X or SX lock exist */
+ Atomic_relaxed<uint32_t> waiters;
/** number of granted SX locks. */
volatile ulint sx_recursive;
diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic
index 0296ef065ff..cb8436d8f89 100644
--- a/storage/innobase/include/sync0rw.ic
+++ b/storage/innobase/include/sync0rw.ic
@@ -77,7 +77,7 @@ rw_lock_get_writer(
/*===============*/
const rw_lock_t* lock) /*!< in: rw-lock */
{
- auto lock_word = lock->lock_word.load(std::memory_order_relaxed);
+ int32_t lock_word = lock->lock_word;
ut_ad(lock_word <= X_LOCK_DECR);
if (lock_word > X_LOCK_HALF_DECR) {
@@ -109,7 +109,7 @@ rw_lock_get_reader_count(
/*=====================*/
const rw_lock_t* lock) /*!< in: rw-lock */
{
- auto lock_word = lock->lock_word.load(std::memory_order_relaxed);
+ int32_t lock_word = lock->lock_word;
ut_ad(lock_word <= X_LOCK_DECR);
if (lock_word > X_LOCK_HALF_DECR) {
@@ -145,7 +145,7 @@ rw_lock_get_x_lock_count(
/*=====================*/
const rw_lock_t* lock) /*!< in: rw-lock */
{
- auto lock_copy = lock->lock_word.load(std::memory_order_relaxed);
+ int32_t lock_copy = lock->lock_word;
ut_ad(lock_copy <= X_LOCK_DECR);
if (lock_copy == 0 || lock_copy == -X_LOCK_HALF_DECR) {
@@ -178,7 +178,7 @@ rw_lock_get_sx_lock_count(
const rw_lock_t* lock) /*!< in: rw-lock */
{
#ifdef UNIV_DEBUG
- auto lock_copy = lock->lock_word.load(std::memory_order_relaxed);
+ int32_t lock_copy = lock->lock_word;
ut_ad(lock_copy <= X_LOCK_DECR);
@@ -209,7 +209,7 @@ rw_lock_lock_word_decr(
int32_t amount, /*!< in: amount to decrement */
int32_t threshold) /*!< in: threshold of judgement */
{
- auto lock_copy = lock->lock_word.load(std::memory_order_relaxed);
+ int32_t lock_copy = lock->lock_word;
while (lock_copy > threshold) {
if (lock->lock_word.compare_exchange_strong(
@@ -352,26 +352,20 @@ rw_lock_s_unlock_func(
#endif /* UNIV_DEBUG */
rw_lock_t* lock) /*!< in/out: rw-lock */
{
-#ifdef UNIV_DEBUG
- auto dbg_lock_word = lock->lock_word.load(std::memory_order_relaxed);
- ut_ad(dbg_lock_word > -X_LOCK_DECR);
- ut_ad(dbg_lock_word != 0);
- ut_ad(dbg_lock_word < X_LOCK_DECR);
-#endif
-
ut_d(rw_lock_remove_debug_info(lock, pass, RW_LOCK_S));
/* Increment lock_word to indicate 1 less reader */
- auto lock_word = lock->lock_word.fetch_add(
- 1, std::memory_order_release) + 1;
- if (lock_word == 0 || lock_word == -X_LOCK_HALF_DECR) {
+ int32_t lock_word = lock->lock_word.fetch_add(1);
+ if (lock_word == -1 || lock_word == -X_LOCK_HALF_DECR - 1) {
/* wait_ex waiter exists. It may not be asleep, but we signal
anyway. We do not wake other waiters, because they can't
exist without wait_ex waiter and wait_ex waiter goes first.*/
os_event_set(lock->wait_ex_event);
sync_array_object_signalled();
-
+ } else {
+ ut_ad(lock_word > -X_LOCK_DECR);
+ ut_ad(lock_word < X_LOCK_DECR);
}
ut_ad(rw_lock_validate(lock));
@@ -389,10 +383,7 @@ rw_lock_x_unlock_func(
#endif /* UNIV_DEBUG */
rw_lock_t* lock) /*!< in/out: rw-lock */
{
- auto lock_word = lock->lock_word.load(std::memory_order_relaxed);
-
- ut_ad(lock_word == 0 || lock_word == -X_LOCK_HALF_DECR
- || lock_word <= -X_LOCK_DECR);
+ int32_t lock_word = lock->lock_word;
if (lock_word == 0) {
/* Last caller in a possible recursive chain. */
@@ -414,21 +405,19 @@ rw_lock_x_unlock_func(
We need to signal read/write waiters.
We do not need to signal wait_ex waiters, since they cannot
exist when there is a writer. */
- if (lock->waiters.load(std::memory_order_relaxed)) {
- lock->waiters.store(0, std::memory_order_relaxed);
+ if (lock->waiters) {
+ lock->waiters = 0;
os_event_set(lock->event);
sync_array_object_signalled();
}
} else if (lock_word == -X_LOCK_DECR
|| lock_word == -(X_LOCK_DECR + X_LOCK_HALF_DECR)) {
/* There are 2 x-locks */
- lock->lock_word.fetch_add(X_LOCK_DECR,
- std::memory_order_relaxed);
+ lock->lock_word.fetch_add(X_LOCK_DECR);
} else {
/* There are more than 2 x-locks. */
ut_ad(lock_word < -X_LOCK_DECR);
- lock->lock_word.fetch_add(1,
- std::memory_order_relaxed);
+ lock->lock_word.fetch_add(1);
}
ut_ad(rw_lock_validate(lock));
@@ -454,8 +443,7 @@ rw_lock_sx_unlock_func(
ut_d(rw_lock_remove_debug_info(lock, pass, RW_LOCK_SX));
if (lock->sx_recursive == 0) {
- auto lock_word =
- lock->lock_word.load(std::memory_order_relaxed);
+ int32_t lock_word = lock->lock_word;
/* Last caller in a possible recursive chain. */
if (lock_word > 0) {
lock->writer_thread = 0;
@@ -472,8 +460,8 @@ rw_lock_sx_unlock_func(
waiters. We do not need to signal wait_ex waiters,
since they cannot exist when there is an sx-lock
holder. */
- if (lock->waiters.load(std::memory_order_relaxed)) {
- lock->waiters.store(0, std::memory_order_relaxed);
+ if (lock->waiters) {
+ lock->waiters = 0;
os_event_set(lock->event);
sync_array_object_signalled();
}
@@ -481,8 +469,7 @@ rw_lock_sx_unlock_func(
/* still has x-lock */
ut_ad(lock_word == -X_LOCK_HALF_DECR ||
lock_word <= -(X_LOCK_DECR + X_LOCK_HALF_DECR));
- lock->lock_word.fetch_add(X_LOCK_HALF_DECR,
- std::memory_order_relaxed);
+ lock->lock_word.fetch_add(X_LOCK_HALF_DECR);
}
}
diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc
index 9993ab0fa62..e1b71f21dc8 100644
--- a/storage/innobase/row/row0ftsort.cc
+++ b/storage/innobase/row/row0ftsort.cc
@@ -1497,10 +1497,11 @@ row_fts_build_sel_tree(
sel_tree[i + start] = int(i);
}
- for (i = treelevel; --i; ) {
+ i = treelevel;
+ do {
row_fts_build_sel_tree_level(
- sel_tree, i, mrec, offsets, index);
- }
+ sel_tree, --i, mrec, offsets, index);
+ } while (i > 0);
return(treelevel);
}
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index 880b64616e8..36e1bc9fab3 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -26,6 +26,9 @@ Created 2012-02-08 by Sunny Bains.
#include "row0import.h"
#include "btr0pcur.h"
+#ifdef BTR_CUR_HASH_ADAPT
+# include "btr0sea.h"
+#endif
#include "que0que.h"
#include "dict0boot.h"
#include "dict0load.h"
@@ -4048,15 +4051,12 @@ row_import_for_mysql(
index entries that point to cached garbage pages in the buffer
pool, because PageConverter::operator() only evicted those
pages that were replaced by the imported pages. We must
- discard all remaining adaptive hash index entries, because the
+ detach any remaining adaptive hash index entries, because the
adaptive hash index must be a subset of the table contents;
false positives are not tolerated. */
- while (buf_LRU_drop_page_hash_for_tablespace(table)) {
- if (trx_is_interrupted(trx)
- || srv_shutdown_state != SRV_SHUTDOWN_NONE) {
- err = DB_INTERRUPTED;
- break;
- }
+ for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); index;
+ index = UT_LIST_GET_NEXT(indexes, index)) {
+ index = index->clone_if_needed();
}
#endif /* BTR_CUR_HASH_ADAPT */
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 0508b92e6d0..27a9d441dbd 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -46,6 +46,9 @@ Completed by Sunny Bains and Marko Makela
#include "row0vers.h"
#include "handler0alter.h"
#include "btr0bulk.h"
+#ifdef BTR_CUR_ADAPT
+# include "btr0sea.h"
+#endif /* BTR_CUR_ADAPT */
#include "ut0stage.h"
#include "fil0crypt.h"
@@ -197,7 +200,6 @@ public:
&ins_cur, 0,
__FILE__, __LINE__, &mtr);
-
error = btr_cur_pessimistic_insert(
flag, &ins_cur, &ins_offsets,
&row_heap, dtuple, &rec,
@@ -1957,8 +1959,7 @@ row_merge_read_clustered_index(
goto scan_next;
}
- if (clust_index->lock.waiters.load(
- std::memory_order_relaxed)) {
+ if (clust_index->lock.waiters) {
/* There are waiters on the clustered
index tree lock, likely the purge
thread. Store and restore the cursor
@@ -3872,6 +3873,9 @@ row_merge_drop_indexes(
we should exclude FTS entries from
prebuilt->ins_node->entry_list
in ins_node_create_entry_list(). */
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!index->search_info->ref_count);
+#endif /* BTR_CUR_HASH_ADAPT */
dict_index_remove_from_cache(
table, index);
index = prev;
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 9e945da79d8..640db10907a 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -2563,6 +2563,9 @@ row_create_index_for_mysql(
UT_BITS_IN_BYTES(unsigned(index->n_nullable)));
err = dict_create_index_tree_in_mem(index, trx);
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!index->search_info->ref_count);
+#endif /* BTR_CUR_HASH_ADAPT */
if (err != DB_SUCCESS) {
dict_index_remove_from_cache(table, index);
@@ -3400,35 +3403,6 @@ row_drop_table_for_mysql(
ut_ad(!(table->stats_bg_flag & BG_STAT_IN_PROGRESS));
if (!table->no_rollback()) {
if (table->space != fil_system.sys_space) {
-#ifdef BTR_CUR_HASH_ADAPT
- /* On DISCARD TABLESPACE, we would not drop the
- adaptive hash index entries. If the tablespace is
- missing here, delete-marking the record in SYS_INDEXES
- would not free any pages in the buffer pool. Thus,
- dict_index_remove_from_cache() would hang due to
- adaptive hash index entries existing in the buffer
- pool. To prevent this hang, and also to guarantee
- that btr_search_drop_page_hash_when_freed() will avoid
- calling btr_search_drop_page_hash_index() while we
- hold the InnoDB dictionary lock, we will drop any
- adaptive hash index entries upfront. */
- const bool immune = is_temp_name
- || create_failed
- || sqlcom == SQLCOM_CREATE_TABLE
- || strstr(table->name.m_name, "/FTS");
-
- while (buf_LRU_drop_page_hash_for_tablespace(table)) {
- if ((!immune && trx_is_interrupted(trx))
- || srv_shutdown_state
- != SRV_SHUTDOWN_NONE) {
- err = DB_INTERRUPTED;
- table->to_be_dropped = false;
- dict_table_close(table, true, false);
- goto funct_exit;
- }
- }
-#endif /* BTR_CUR_HASH_ADAPT */
-
/* Delete the link file if used. */
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
RemoteDatafile::delete_link_file(name);
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index 9f1a7bc702e..9934ede605b 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -46,7 +46,6 @@ Created 3/14/1997 Heikki Tuuri
#include "handler.h"
#include "ha_innodb.h"
#include "fil0fil.h"
-#include "debug_sync.h"
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index a0d0d5d1ad4..9295dee931e 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -459,8 +459,6 @@ row_vers_build_clust_v_col(
ut_ad(dict_index_has_virtual(index));
ut_ad(index->table == clust_index->table);
- DEBUG_SYNC(current_thd, "ib_clust_v_col_before_row_allocated");
-
innobase_allocate_row_for_vcol(thd, index,
&local_heap,
&maria_table,
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index 726fe613f46..26d217ed0ad 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -2173,7 +2173,6 @@ void release_thd(THD *thd, void *ctx)
}
-
/*
Called by timer when purge coordinator decides
to delay processing of purge records.
diff --git a/storage/innobase/sync/sync0arr.cc b/storage/innobase/sync/sync0arr.cc
index 4f2f384a5ef..05fb8d76979 100644
--- a/storage/innobase/sync/sync0arr.cc
+++ b/storage/innobase/sync/sync0arr.cc
@@ -2,7 +2,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2013, 2019, MariaDB Corporation.
+Copyright (c) 2013, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -595,8 +595,8 @@ sync_array_cell_print(
#endif
"\n",
rw_lock_get_reader_count(rwlock),
- rwlock->waiters.load(std::memory_order_relaxed),
- rwlock->lock_word.load(std::memory_order_relaxed),
+ uint32_t{rwlock->waiters},
+ int32_t{rwlock->lock_word},
innobase_basename(rwlock->last_x_file_name),
rwlock->last_x_line
#if 0 /* JAN: TODO: FIX LATER */
@@ -1384,10 +1384,10 @@ sync_arr_fill_sys_semphore_waits_table(
//fields[SYS_SEMAPHORE_WAITS_HOLDER_LINE]->set_notnull();
OK(fields[SYS_SEMAPHORE_WAITS_READERS]->store(rw_lock_get_reader_count(rwlock), true));
OK(fields[SYS_SEMAPHORE_WAITS_WAITERS_FLAG]->store(
- rwlock->waiters.load(std::memory_order_relaxed),
+ rwlock->waiters,
true));
OK(fields[SYS_SEMAPHORE_WAITS_LOCK_WORD]->store(
- rwlock->lock_word.load(std::memory_order_relaxed),
+ rwlock->lock_word,
true));
OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_LAST_WRITER_FILE], innobase_basename(rwlock->last_x_file_name)));
OK(fields[SYS_SEMAPHORE_WAITS_LAST_WRITER_LINE]->store(rwlock->last_x_line, true));
diff --git a/storage/innobase/sync/sync0rw.cc b/storage/innobase/sync/sync0rw.cc
index 6f22d640298..638896a9a86 100644
--- a/storage/innobase/sync/sync0rw.cc
+++ b/storage/innobase/sync/sync0rw.cc
@@ -2,7 +2,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -202,11 +202,8 @@ rw_lock_create_func(
new(lock) rw_lock_t();
#endif /* UNIV_DEBUG */
- /* If this is the very first time a synchronization object is
- created, then the following call initializes the sync system. */
-
- lock->lock_word.store(X_LOCK_DECR, std::memory_order_relaxed);
- lock->waiters.store(0, std::memory_order_relaxed);
+ lock->lock_word = X_LOCK_DECR;
+ lock->waiters = 0;
lock->sx_recursive = 0;
lock->writer_thread= 0;
@@ -252,7 +249,7 @@ rw_lock_free_func(
rw_lock_t* lock) /*!< in/out: rw-lock */
{
ut_ad(rw_lock_validate(lock));
- ut_a(lock->lock_word.load(std::memory_order_relaxed) == X_LOCK_DECR);
+ ut_a(lock->lock_word == X_LOCK_DECR);
mutex_enter(&rw_lock_list_mutex);
@@ -289,12 +286,15 @@ rw_lock_s_lock_spin(
ut_ad(rw_lock_validate(lock));
+ rw_lock_stats.rw_s_spin_wait_count.inc();
+
lock_loop:
/* Spin waiting for the writer field to become free */
HMT_low();
+ ulint j = i;
while (i < srv_n_spin_wait_rounds &&
- lock->lock_word.load(std::memory_order_relaxed) <= 0) {
+ lock->lock_word <= 0) {
ut_delay(srv_spin_wait_delay);
i++;
}
@@ -304,7 +304,7 @@ lock_loop:
os_thread_yield();
}
- ++spin_count;
+ spin_count += lint(i - j);
/* We try once again to obtain the lock */
if (rw_lock_s_lock_low(lock, pass, file_name, line)) {
@@ -412,10 +412,10 @@ rw_lock_x_lock_wait_func(
sync_array_t* sync_arr;
int64_t count_os_wait = 0;
- ut_ad(lock->lock_word.load(std::memory_order_relaxed) <= threshold);
+ ut_ad(lock->lock_word <= threshold);
HMT_low();
- while (lock->lock_word.load(std::memory_order_relaxed) < threshold) {
+ while (lock->lock_word < threshold) {
ut_delay(srv_spin_wait_delay);
if (i < srv_n_spin_wait_rounds) {
@@ -424,7 +424,7 @@ rw_lock_x_lock_wait_func(
}
/* If there is still a reader, then go to sleep.*/
- ++n_spins;
+ n_spins += i;
sync_cell_t* cell;
@@ -434,8 +434,7 @@ rw_lock_x_lock_wait_func(
i = 0;
/* Check lock_word to ensure wake-up isn't missed.*/
- if (lock->lock_word.load(std::memory_order_relaxed) < threshold) {
-
+ if (lock->lock_word < threshold) {
++count_os_wait;
/* Add debug info as it is needed to detect possible
@@ -524,17 +523,15 @@ rw_lock_x_lock_low(
file_name, line);
} else {
- auto lock_word = lock->lock_word.load(std::memory_order_relaxed);
+ int32_t lock_word = lock->lock_word;
/* At least one X lock by this thread already
exists. Add another. */
if (lock_word == 0
|| lock_word == -X_LOCK_HALF_DECR) {
- lock->lock_word.fetch_sub(X_LOCK_DECR,
- std::memory_order_relaxed);
+ lock->lock_word.fetch_sub(X_LOCK_DECR);
} else {
ut_ad(lock_word <= -X_LOCK_DECR);
- lock->lock_word.fetch_sub(1,
- std::memory_order_relaxed);
+ lock->lock_word.fetch_sub(1);
}
}
@@ -657,6 +654,12 @@ rw_lock_x_lock_func(
ut_ad(rw_lock_validate(lock));
ut_ad(!rw_lock_own(lock, RW_LOCK_S));
+ if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
+ /* Locking succeeded */
+ return;
+ }
+ rw_lock_stats.rw_x_spin_wait_count.inc();
+
lock_loop:
if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
@@ -676,14 +679,15 @@ lock_loop:
/* Spin waiting for the lock_word to become free */
HMT_low();
+ ulint j = i;
while (i < srv_n_spin_wait_rounds
- && lock->lock_word.load(std::memory_order_relaxed) <= X_LOCK_HALF_DECR) {
+ && lock->lock_word <= X_LOCK_HALF_DECR) {
ut_delay(srv_spin_wait_delay);
i++;
}
HMT_medium();
- spin_count += lint(i);
+ spin_count += lint(i - j);
if (i >= srv_n_spin_wait_rounds) {
@@ -751,11 +755,17 @@ rw_lock_sx_lock_func(
sync_array_t* sync_arr;
lint spin_count = 0;
int64_t count_os_wait = 0;
- lint spin_wait_count = 0;
ut_ad(rw_lock_validate(lock));
ut_ad(!rw_lock_own(lock, RW_LOCK_S));
+ if (rw_lock_sx_lock_low(lock, pass, file_name, line)) {
+ /* Locking succeeded */
+ return;
+ }
+
+ rw_lock_stats.rw_sx_spin_wait_count.inc();
+
lock_loop:
if (rw_lock_sx_lock_low(lock, pass, file_name, line)) {
@@ -767,23 +777,21 @@ lock_loop:
}
rw_lock_stats.rw_sx_spin_round_count.add(spin_count);
- rw_lock_stats.rw_sx_spin_wait_count.add(spin_wait_count);
/* Locking succeeded */
return;
} else {
- ++spin_wait_count;
-
/* Spin waiting for the lock_word to become free */
+ ulint j = i;
while (i < srv_n_spin_wait_rounds
- && lock->lock_word.load(std::memory_order_relaxed) <= X_LOCK_HALF_DECR) {
+ && lock->lock_word <= X_LOCK_HALF_DECR) {
ut_delay(srv_spin_wait_delay);
i++;
}
- spin_count += lint(i);
+ spin_count += lint(i - j);
if (i >= srv_n_spin_wait_rounds) {
@@ -815,7 +823,6 @@ lock_loop:
}
rw_lock_stats.rw_sx_spin_round_count.add(spin_count);
- rw_lock_stats.rw_sx_spin_wait_count.add(spin_wait_count);
/* Locking succeeded */
return;
@@ -841,13 +848,11 @@ rw_lock_validate(
/*=============*/
const rw_lock_t* lock) /*!< in: rw-lock */
{
- int32_t lock_word;
-
ut_ad(lock);
- lock_word = lock->lock_word.load(std::memory_order_relaxed);
+ int32_t lock_word = lock->lock_word;
- ut_ad(lock->waiters.load(std::memory_order_relaxed) < 2);
+ ut_ad(lock->waiters < 2);
ut_ad(lock_word > -(2 * X_LOCK_DECR));
ut_ad(lock_word <= X_LOCK_DECR);
@@ -910,7 +915,7 @@ rw_lock_add_debug_info(
rw_lock_debug_mutex_exit();
if (pass == 0 && lock_type != RW_LOCK_X_WAIT) {
- auto lock_word = lock->lock_word.load(std::memory_order_relaxed);
+ int32_t lock_word = lock->lock_word;
/* Recursive x while holding SX
(lock_type == RW_LOCK_X && lock_word == -X_LOCK_HALF_DECR)
@@ -1096,11 +1101,11 @@ rw_lock_list_print_info(
count++;
- if (lock->lock_word.load(std::memory_order_relaxed) != X_LOCK_DECR) {
+ if (lock->lock_word != X_LOCK_DECR) {
fprintf(file, "RW-LOCK: %p ", (void*) lock);
- if (int32_t waiters= lock->waiters.load(std::memory_order_relaxed)) {
+ if (int32_t waiters= lock->waiters) {
fprintf(file, " (%d waiters)\n", waiters);
} else {
putc('\n', file);
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
index f0b4d6f91b5..6e730faf567 100644
--- a/storage/innobase/trx/trx0purge.cc
+++ b/storage/innobase/trx/trx0purge.cc
@@ -369,7 +369,7 @@ trx_purge_free_segment(trx_rseg_t* rseg, fil_addr_t hdr_addr)
while (!fseg_free_step_not_header(
TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER
- + block->frame, false, &mtr)) {
+ + block->frame, &mtr)) {
mutex_exit(&rseg->mutex);
mtr.commit();
@@ -405,7 +405,7 @@ trx_purge_free_segment(trx_rseg_t* rseg, fil_addr_t hdr_addr)
fsp0fsp.cc. */
} while (!fseg_free_step(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER
- + block->frame, false, &mtr));
+ + block->frame, &mtr));
byte* hist = TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rseg_hdr->frame;
ut_ad(mach_read_from_4(hist) >= seg_size);
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index aa8c644a896..aeefa2bf7ca 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -628,7 +628,7 @@ trx_undo_free_page(
fseg_free_page(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER
+ header_block->frame,
- rseg->space, page_no, false, mtr);
+ rseg->space, page_no, mtr);
const fil_addr_t last_addr = flst_get_last(
TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + header_block->frame);
@@ -813,7 +813,7 @@ static void trx_undo_seg_free(const trx_undo_t* undo, bool noredo)
fseg_header_t* file_seg = TRX_UNDO_SEG_HDR
+ TRX_UNDO_FSEG_HEADER + block->frame;
- finished = fseg_free_step(file_seg, false, &mtr);
+ finished = fseg_free_step(file_seg, &mtr);
if (finished) {
/* Update the rseg header */
diff --git a/storage/tokudb/mysql-test/tokudb_parts/r/partition_auto_increment_tokudb.result b/storage/tokudb/mysql-test/tokudb_parts/r/partition_auto_increment_tokudb.result
index b18f970d2ce..14b6052a7d3 100644
--- a/storage/tokudb/mysql-test/tokudb_parts/r/partition_auto_increment_tokudb.result
+++ b/storage/tokudb/mysql-test/tokudb_parts/r/partition_auto_increment_tokudb.result
@@ -1115,5 +1115,13 @@ SELECT * FROM t1;
a
0
DROP TABLE t1;
+#
+# MDEV-19622 Assertion failures in
+# ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table
+#
+CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a);
+INSERT INTO t1 VALUES (1,1),(2,2);
+UPDATE t1 SET pk = 0;
+DROP TABLE t1;
##############################################################################
SET GLOBAL tokudb_prelock_empty = @tokudb_prelock_empty_saved;