diff options
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; |