Merge 10.4 into 10.5

This commit is contained in:
Marko Mäkelä 2020-05-18 17:30:02 +03:00
commit 23047d3ed4
89 changed files with 1905 additions and 872 deletions
client
include
libmariadb
mysql-test
mysys
sql
storage

View file

@ -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);

View file

@ -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);

View file

@ -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 */

View file

@ -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)

View file

@ -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:

@ -1 +1 @@
Subproject commit 2759b87d72926b7c9b5426437a7c8dd15ff57945
Subproject commit cdfecebc9932a0dd5516c10505bfe78d79132e7d

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -2078,6 +2078,30 @@ select (select c1 from t1 group by c1,c2 order by c1 limit 1) as x;
(select c1 from t1 group by c1,c2 order by c1 limit 1);
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 #
@ -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

View file

@ -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

View file

@ -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 ;$$

View file

@ -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");

View file

@ -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();

View file

@ -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;

View file

@ -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;

View file

@ -0,0 +1 @@
--encrypt-tmp_files=ON

View file

@ -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;

View file

@ -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()

View file

@ -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");

View file

@ -1,7 +1,7 @@
!include ../galera_2nodes.cnf
[mysqld.1]
wsrep-debug=ON
wsrep-debug=SERVER
[mysqld.2]
wsrep-debug=ON
wsrep-debug=SERVER

View file

@ -1,7 +1,7 @@
!include ../galera_2nodes.cnf
[mysqld.1]
wsrep-debug=ON
wsrep-debug=SERVER
[mysqld.2]
wsrep-debug=ON
wsrep-debug=SERVER

View file

@ -0,0 +1,7 @@
!include ../galera_2nodes.cnf
[mysqld.1]
wsrep-debug=SERVER
[mysqld.2]
wsrep-debug=SERVER

View file

@ -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

View file

@ -0,0 +1,7 @@
!include ../galera_2nodes.cnf
[mysqld.1]
wsrep-debug=SERVER
[mysqld.2]
wsrep-debug=SERVER

View file

@ -0,0 +1,7 @@
!include ../galera_2nodes.cnf
[mysqld.1]
wsrep-debug=SERVER
[mysqld.2]
wsrep-debug=SERVER

View file

@ -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;

View file

@ -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;

View file

@ -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 #

View file

@ -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 ##############################################################################
}

View file

@ -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;
##############################################################################

View file

@ -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;
##############################################################################

View file

@ -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;
##############################################################################

View file

@ -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;
##############################################################################

View file

@ -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

View file

@ -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;

View file

@ -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
#

View file

@ -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 #
@ -442,6 +472,37 @@ REPLACE INTO t1 (pk,i) VALUES (1,2);
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 #

View file

@ -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

View file

@ -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))

View file

@ -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
{

View file

@ -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;

View file

@ -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();

View file

@ -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);

View file

@ -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)
{

View file

@ -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;

View file

@ -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++;

View file

@ -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));

View file

@ -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)

View file

@ -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'";

View file

@ -1671,6 +1671,7 @@ public:
*/
virtual bool add()
{
table_field->mark_unused_memory_as_defined();
return tree->unique_add(table_field->ptr);
}

View file

@ -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);
}
}

View file

@ -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)
{
/*

View file

@ -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) {

View file

@ -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;

View file

@ -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;
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;
}
ut_ad(mutex_own(&dict_sys.mutex));
/** 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);
for (index = dict_table_get_first_index(table);
index != NULL;
index = dict_table_get_next_index(index)) {
index->search_info->ref_count = 0;
}
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);

View file

@ -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"

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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);

View file

@ -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"

View file

@ -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.

View file

@ -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--; ) {

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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. */

View file

@ -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.

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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 */

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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,

View file

@ -2173,7 +2173,6 @@ void release_thd(THD *thd, void *ctx)
}
/*
Called by timer when purge coordinator decides
to delay processing of purge records.

View file

@ -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));

View file

@ -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);

View file

@ -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);

View file

@ -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 */

View file

@ -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;