Merge 10.4 into 10.5

This commit is contained in:
Marko Mäkelä 2021-03-05 12:54:43 +02:00
commit 10d544aa7b
40 changed files with 771 additions and 275 deletions

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 1995, 2018, MariaDB Corporation.
Copyright (c) 1995, 2021, 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
@ -217,9 +217,7 @@ enum ha_extra_function {
/** Start writing rows during ALTER TABLE...ALGORITHM=COPY. */
HA_EXTRA_BEGIN_ALTER_COPY,
/** Finish writing rows during ALTER TABLE...ALGORITHM=COPY. */
HA_EXTRA_END_ALTER_COPY,
/** Fake the start of a statement after wsrep_load_data_splitting hack */
HA_EXTRA_FAKE_START_STMT
HA_EXTRA_END_ALTER_COPY
};
/* Compatible option, to be deleted in 6.0 */

View file

@ -74,7 +74,8 @@ my %debuggers = (
options => '-f -o {log} {exe} {args}',
},
rr => {
options => 'record -o {log} {exe} {args}',
options => '_RR_TRACE_DIR={log} rr record {exe} {args}',
run => 'env',
pre => sub {
::mtr_error('rr requires kernel.perf_event_paranoid <= 1')
if ::mtr_grab_file('/proc/sys/kernel/perf_event_paranoid') > 1;

View file

@ -20,3 +20,14 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
connection default;
disconnect con1;
unlock tables;
# Second test from MDEV-23843
CREATE TABLE t (a INT);
FLUSH TABLES WITH READ LOCK;
connect con1,localhost,root,,;
SET lock_wait_timeout= 1;
ANALYZE TABLE t;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
disconnect con1;
connection default;
UNLOCK TABLES;
DROP TABLE t;

View file

@ -27,3 +27,17 @@ FLUSH TABLES;
--connection default
--disconnect con1
unlock tables;
--echo # Second test from MDEV-23843
CREATE TABLE t (a INT);
FLUSH TABLES WITH READ LOCK;
--connect (con1,localhost,root,,)
SET lock_wait_timeout= 1;
--error ER_LOCK_WAIT_TIMEOUT
ANALYZE TABLE t;
# Cleanup
--disconnect con1
--connection default
UNLOCK TABLES;
DROP TABLE t;

View file

@ -2958,5 +2958,34 @@ f COUNT(*)
NULL 1
DROP TABLE t1;
#
# MDEV-24710 Uninitialized value upon CREATE .. SELECT ... VALUE
#
CREATE TABLE t1 (a VARCHAR(8) NOT NULL DEFAULT '');
INSERT INTO t1 (a) VALUES ('foo');
CREATE TABLE t2 AS SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL;
SELECT * from t2;
f1 f2
NULL NULL
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL;
f1 f2
NULL NULL
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE 1=0;
f1 f2
NULL NULL
drop table t1,t2;
# Extra test by to check the fix for MDEV-24710
create table t20 (pk int primary key, a int);
insert into t20 values (1,1);
create table t21 (pk int primary key, b int not null);
insert into t21 values (1,1);
create table t22 (a int);
insert into t22 values (1),(2);
select a, (select max(t21.b) from t20 left join t21 on t21.pk=t20.a+10
where t20.pk=1 and rand(123) < 0.5) as SUBQ from t22;
a SUBQ
1 NULL
2 NULL
drop table t20, t21, t22;
#
# End of 10.3 tests
#

View file

@ -2061,6 +2061,29 @@ INSERT INTO t1 VALUES ('2032-10-08');
SELECT d != '2023-03-04' AS f, COUNT(*) FROM t1 GROUP BY d WITH ROLLUP;
DROP TABLE t1;
--echo #
--echo # MDEV-24710 Uninitialized value upon CREATE .. SELECT ... VALUE
--echo #
CREATE TABLE t1 (a VARCHAR(8) NOT NULL DEFAULT '');
INSERT INTO t1 (a) VALUES ('foo');
CREATE TABLE t2 AS SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL;
SELECT * from t2;
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL;
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE 1=0;
drop table t1,t2;
--echo # Extra test by to check the fix for MDEV-24710
create table t20 (pk int primary key, a int);
insert into t20 values (1,1);create table t21 (pk int primary key, b int not null);
insert into t21 values (1,1);
create table t22 (a int);
insert into t22 values (1),(2);
select a, (select max(t21.b) from t20 left join t21 on t21.pk=t20.a+10
where t20.pk=1 and rand(123) < 0.5) as SUBQ from t22;
drop table t20, t21, t22;
--echo #
--echo # End of 10.3 tests
--echo #

View file

@ -847,6 +847,39 @@ t r
DROP TABLE t1;
DROP FUNCTION next_seq_value;
DROP TABLE series;
#
# MDEV-24958 Server crashes in my_strtod /
# Value_source::Converter_strntod::Converter_strntod with DEFAULT(blob)
#
# MDEV-24942 Server crashes in _ma_rec_pack / _ma_write_blob_record with
# DEFAULT() on BLOB
#
CREATE TABLE t1 (id INT, f MEDIUMTEXT NOT NULL DEFAULT 'A');
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
SELECT f FROM t1 GROUP BY id ORDER BY DEFAULT(f);
f
foo
bar
SELECT DEFAULT(f) AS h FROM t1 HAVING h > 5;
h
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'A'
SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 0;
h
A
A
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'A'
SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 'A';
h
A
A
alter table t1 add column b int default (rand()+1+3);
select default(b) AS h FROM t1 HAVING h > "2";
h
#
#
drop table t1;
# End of 10.3 tests
#
# MDEV-18681: AND formula in HAVING with several occurances

View file

@ -891,6 +891,27 @@ DROP TABLE t1;
DROP FUNCTION next_seq_value;
DROP TABLE series;
--echo #
--echo # MDEV-24958 Server crashes in my_strtod /
--echo # Value_source::Converter_strntod::Converter_strntod with DEFAULT(blob)
--echo #
--echo # MDEV-24942 Server crashes in _ma_rec_pack / _ma_write_blob_record with
--echo # DEFAULT() on BLOB
--echo #
CREATE TABLE t1 (id INT, f MEDIUMTEXT NOT NULL DEFAULT 'A');
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
SELECT f FROM t1 GROUP BY id ORDER BY DEFAULT(f);
SELECT DEFAULT(f) AS h FROM t1 HAVING h > 5;
SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 0;
SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 'A';
alter table t1 add column b int default (rand()+1+3);
--replace_column 1 #
select default(b) AS h FROM t1 HAVING h > "2";
drop table t1;
--echo # End of 10.3 tests
--echo #

View file

@ -5497,6 +5497,23 @@ EXISTS(SELECT 1 FROM t1 GROUP BY a IN (select a from t1))
0
DROP TABLE t1;
#
# MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement
#
CREATE TABLE t1(c1 CHAR(255) PRIMARY KEY);
PREPARE stmt FROM 'EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b';
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE a system NULL NULL NULL NULL 0 Const row not found
1 SIMPLE b system NULL NULL NULL NULL 0 Const row not found
DROP TABLE t1;
CREATE TABLE t1(a INT);
PREPARE stmt FROM 'EXPLAIN DELETE FROM t1.* USING t1';
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 0 Const row not found
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
#
# End of 10.2 tests
#
#

View file

@ -4941,6 +4941,20 @@ EXECUTE stmt;
EXECUTE stmt;
DROP TABLE t1;
--echo #
--echo # MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement
--echo #
CREATE TABLE t1(c1 CHAR(255) PRIMARY KEY);
PREPARE stmt FROM 'EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b';
EXECUTE stmt;
DROP TABLE t1;
CREATE TABLE t1(a INT);
PREPARE stmt FROM 'EXPLAIN DELETE FROM t1.* USING t1';
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
--echo #
--echo # End of 10.2 tests
--echo #

View file

@ -1217,6 +1217,31 @@ set @rnd=1;
select @rnd;
@rnd
0
#
# MDEV-24860: Incorrect behaviour of SET STATEMENT in case
# it is executed as a prepared statement
#
PREPARE stmt FROM "SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1";
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
# Show definition of the table t1 created using Prepared Statement
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(3) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
# Create the table t1 with the same definition as it used before
# using regular statement execution mode.
SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1;
# Show that the table has the same definition as it is in case the table
# created in prepared statement mode.
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(3) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
create table t (a int);
SET sql_mode=ORACLE;
SET STATEMENT myisam_sort_buffer_size=800000 FOR OPTIMIZE TABLE t;
@ -1234,3 +1259,4 @@ SET sql_mode=ORACLE;
SET STATEMENT max_statement_time=30 FOR DELETE FROM mysql.user where user = 'unknown';
SET sql_mode=default;
SET STATEMENT max_statement_time=30 FOR DELETE FROM mysql.user where user = 'unknown';
# End of 10.4 tests

View file

@ -1137,6 +1137,30 @@ while ($1)
--echo # @rnd should be 0
select @rnd;
--echo #
--echo # MDEV-24860: Incorrect behaviour of SET STATEMENT in case
--echo # it is executed as a prepared statement
--echo #
PREPARE stmt FROM "SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1";
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
--echo # Show definition of the table t1 created using Prepared Statement
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo # Create the table t1 with the same definition as it used before
--echo # using regular statement execution mode.
SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1;
--echo # Show that the table has the same definition as it is in case the table
--echo # created in prepared statement mode.
SHOW CREATE TABLE t1;
DROP TABLE t1;
create table t (a int);
SET sql_mode=ORACLE;
SET STATEMENT myisam_sort_buffer_size=800000 FOR OPTIMIZE TABLE t;
@ -1152,3 +1176,5 @@ SET sql_mode=ORACLE;
SET STATEMENT max_statement_time=30 FOR DELETE FROM mysql.user where user = 'unknown';
SET sql_mode=default;
SET STATEMENT max_statement_time=30 FOR DELETE FROM mysql.user where user = 'unknown';
--echo # End of 10.4 tests

View file

@ -2880,8 +2880,12 @@ deallocate prepare stmt;
drop view v1;
drop table t1,t2,t3;
#
# End of 10.3 tests
# MDEV-24919: subselect formed by TVC and used in set function
#
select sum((values(1)));
sum((values(1)))
1
End of 10.3 tests
#
# MDEV-22610 Crash in INSERT INTO t1 (VALUES (DEFAULT) UNION VALUES (DEFAULT))
#

View file

@ -1517,9 +1517,13 @@ drop view v1;
drop table t1,t2,t3;
--echo #
--echo # End of 10.3 tests
--echo # MDEV-24919: subselect formed by TVC and used in set function
--echo #
select sum((values(1)));
--echo End of 10.3 tests
--echo #
--echo # MDEV-22610 Crash in INSERT INTO t1 (VALUES (DEFAULT) UNION VALUES (DEFAULT))
--echo #

View file

@ -5000,7 +5000,7 @@ sub mysqld_start ($$) {
$ENV{'MYSQLD_LAST_CMD'}= "$exe @$args";
My::Debugger::setup_args(\$args, \$exe, $mysqld->name());
$ENV{'VALGRIND_TEST'}= $opt_valgrind = int($exe && $exe eq 'valgrind');
$ENV{'VALGRIND_TEST'}= $opt_valgrind = int(($exe || '') eq 'valgrind');
# Remove the old pidfile if any
unlink($mysqld->value('pid-file'));

View file

@ -57,3 +57,14 @@ disconnect dml;
connection default;
SET DEBUG_SYNC = RESET;
DROP TABLE child, parent;
#
# MDEV-24532 Table corruption ER_NO_SUCH_TABLE_IN_ENGINE or
# ER_CRASHED_ON_USAGE after ALTER on table with foreign key
#
CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)) ENGINE=InnoDB;
ALTER TABLE t1 ADD FOREIGN KEY (b) REFERENCES t1 (a) ON UPDATE CASCADE;
LOCK TABLE t1 WRITE;
TRUNCATE TABLE t1;
ALTER TABLE t1 ADD c INT;
UNLOCK TABLES;
DROP TABLE t1;

View file

@ -67,3 +67,16 @@ connection default;
SET DEBUG_SYNC = RESET;
DROP TABLE child, parent;
--echo #
--echo # MDEV-24532 Table corruption ER_NO_SUCH_TABLE_IN_ENGINE or
--echo # ER_CRASHED_ON_USAGE after ALTER on table with foreign key
--echo #
CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)) ENGINE=InnoDB;
ALTER TABLE t1 ADD FOREIGN KEY (b) REFERENCES t1 (a) ON UPDATE CASCADE;
LOCK TABLE t1 WRITE;
TRUNCATE TABLE t1;
ALTER TABLE t1 ADD c INT;
UNLOCK TABLES;
DROP TABLE t1;

View file

@ -118,6 +118,7 @@ CREATE USER u1 IDENTIFIED BY 'pwd-123';
GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321";
SET PASSWORD FOR u1 = PASSWORD('pwd 098');
CREATE USER u3 IDENTIFIED BY '';
ALTER USER u3 IDENTIFIED BY 'pwd-456';
drop user u1, u2, u3;
set global server_audit_events='query_ddl';
create table t1(id int);
@ -393,6 +394,8 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,global_priv,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u3 IDENTIFIED BY *****',0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,global_priv,
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'ALTER USER u3 IDENTIFIED BY *****',0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv,

View file

@ -95,6 +95,7 @@ CREATE USER u1 IDENTIFIED BY 'pwd-123';
GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321";
SET PASSWORD FOR u1 = PASSWORD('pwd 098');
CREATE USER u3 IDENTIFIED BY '';
ALTER USER u3 IDENTIFIED BY 'pwd-456';
drop user u1, u2, u3;
set global server_audit_events='query_ddl';

View file

@ -20,7 +20,6 @@ sub start_test {
($path, $args) = ($cmd, , [ ])
}
my $oldpwd=getcwd();
chdir $::opt_vardir;
my $proc=My::SafeProcess->new
@ -49,12 +48,12 @@ sub start_test {
my ($command, %tests, $prefix);
for (@ctest_list) {
chomp;
if (/^\d+: Test command: +/) {
$command= $';
if (/^\d+: Test command: +([^ \t]+)/) {
$command= $1;
$prefix= /libmariadb/ ? 'conc_' : '';
} elsif (/^ +Test +#\d+: +/) {
if ($command ne "NOT_AVAILABLE") {
$tests{$prefix.$'}=$command;
} elsif (/^ +Test +#\d+: ([^ \t]+)/) {
if ($command ne "NOT_AVAILABLE" && $command ne "/bin/sh") {
$tests{$prefix.$1}=$command;
}
}
}

View file

@ -151,23 +151,34 @@ exit:
}
/*
Return 1 if we should rotate the log
*/
my_bool logger_time_to_rotate(LOGGER_HANDLE *log)
{
my_off_t filesize;
if (log->rotations > 0 &&
(filesize= my_tell(log->file, MYF(0))) != (my_off_t) -1 &&
((ulonglong) filesize >= log->size_limit))
return 1;
return 0;
}
int logger_vprintf(LOGGER_HANDLE *log, const char* fmt, va_list ap)
{
int result;
my_off_t filesize;
char cvtbuf[1024];
size_t n_bytes;
flogger_mutex_lock(&log->lock);
if (log->rotations > 0)
if ((filesize= my_tell(log->file, MYF(0))) == (my_off_t) -1 ||
((unsigned long long)filesize >= log->size_limit &&
do_rotate(log)))
{
result= -1;
errno= my_errno;
goto exit; /* Log rotation needed but failed */
}
if (logger_time_to_rotate(log) && do_rotate(log))
{
result= -1;
errno= my_errno;
goto exit; /* Log rotation needed but failed */
}
n_bytes= my_vsnprintf(cvtbuf, sizeof(cvtbuf), fmt, ap);
if (n_bytes >= sizeof(cvtbuf))
@ -181,21 +192,18 @@ exit:
}
int logger_write(LOGGER_HANDLE *log, const char *buffer, size_t size)
static int logger_write_r(LOGGER_HANDLE *log, my_bool allow_rotations,
const char *buffer, size_t size)
{
int result;
my_off_t filesize;
flogger_mutex_lock(&log->lock);
if (log->rotations > 0)
if ((filesize= my_tell(log->file, MYF(0))) == (my_off_t) -1 ||
((unsigned long long)filesize >= log->size_limit &&
do_rotate(log)))
{
result= -1;
errno= my_errno;
goto exit; /* Log rotation needed but failed */
}
if (allow_rotations && logger_time_to_rotate(log) && do_rotate(log))
{
result= -1;
errno= my_errno;
goto exit; /* Log rotation needed but failed */
}
result= (int)my_write(log->file, (uchar *) buffer, size, MYF(0));
@ -205,6 +213,11 @@ exit:
}
int logger_write(LOGGER_HANDLE *log, const char *buffer, size_t size)
{
return logger_write_r(log, TRUE, buffer, size);
}
int logger_rotate(LOGGER_HANDLE *log)
{
int result;

View file

@ -16,7 +16,7 @@
#define PLUGIN_VERSION 0x104
#define PLUGIN_STR_VERSION "1.4.10"
#define PLUGIN_STR_VERSION "1.4.11"
#define _my_thread_var loc_thread_var
@ -140,6 +140,7 @@ static int loc_file_errno;
#define logger_write loc_logger_write
#define logger_rotate loc_logger_rotate
#define logger_init_mutexts loc_logger_init_mutexts
#define logger_time_to_rotate loc_logger_time_to_rotate
static size_t loc_write(File Filedes, const uchar *Buffer, size_t Count)
@ -554,22 +555,22 @@ static struct st_mysql_show_var audit_status[]=
{0,0,0}
};
#if defined(HAVE_PSI_INTERFACE) && !defined(FLOGGER_NO_PSI)
/* These belong to the service initialization */
#ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_LOCK_operations;
static PSI_mutex_key key_LOCK_atomic;
static PSI_mutex_key key_LOCK_bigbuffer;
static PSI_mutex_info mutex_key_list[]=
{
{ &key_LOCK_operations, "SERVER_AUDIT_plugin::lock_operations",
PSI_FLAG_GLOBAL},
PSI_FLAG_GLOBAL}
#ifndef FLOGGER_NO_PSI
,
{ &key_LOCK_atomic, "SERVER_AUDIT_plugin::lock_atomic",
PSI_FLAG_GLOBAL},
{ &key_LOCK_bigbuffer, "SERVER_AUDIT_plugin::lock_bigbuffer",
PSI_FLAG_GLOBAL}
#endif /*FLOGGER_NO_PSI*/
};
#endif
static mysql_mutex_t lock_operations;
#endif /*HAVE_PSI_INTERFACE*/
static mysql_prlock_t lock_operations;
static mysql_mutex_t lock_atomic;
static mysql_mutex_t lock_bigbuffer;
@ -819,6 +820,7 @@ enum sa_keywords
SQLCOM_DML,
SQLCOM_GRANT,
SQLCOM_CREATE_USER,
SQLCOM_ALTER_USER,
SQLCOM_CHANGE_MASTER,
SQLCOM_CREATE_SERVER,
SQLCOM_SET_OPTION,
@ -926,6 +928,7 @@ struct sa_keyword passwd_keywords[]=
{
{3, "SET", &password_word, SQLCOM_SET_OPTION},
{5, "ALTER", &server_word, SQLCOM_ALTER_SERVER},
{5, "ALTER", &user_word, SQLCOM_ALTER_USER},
{5, "GRANT", 0, SQLCOM_GRANT},
{6, "CREATE", &user_word, SQLCOM_CREATE_USER},
{6, "CREATE", &server_word, SQLCOM_CREATE_SERVER},
@ -1320,19 +1323,41 @@ static void change_connection(struct connection_info *cn,
event->ip, event->ip_length);
}
/*
Write to the log
@param take_lock If set, take a read lock (or write lock on rotate).
If not set, the caller has a already taken a write lock
*/
static int write_log(const char *message, size_t len, int take_lock)
{
int result= 0;
if (take_lock)
flogger_mutex_lock(&lock_operations);
{
/* Start by taking a read lock */
mysql_prlock_rdlock(&lock_operations);
}
if (output_type == OUTPUT_FILE)
{
if (logfile &&
(is_active= (logger_write(logfile, message, len) == (int) len)))
goto exit;
++log_write_failures;
result= 1;
if (logfile)
{
my_bool allow_rotate= !take_lock; /* Allow rotate if caller write lock */
if (take_lock && logger_time_to_rotate(logfile))
{
/* We have to rotate the log, change above read lock to write lock */
mysql_prlock_unlock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
allow_rotate= 1;
}
if (!(is_active= (logger_write_r(logfile, allow_rotate, message, len) ==
(int) len)))
{
++log_write_failures;
result= 1;
}
}
}
else if (output_type == OUTPUT_SYSLOG)
{
@ -1340,9 +1365,8 @@ static int write_log(const char *message, size_t len, int take_lock)
syslog_priority_codes[syslog_priority],
"%s %.*s", syslog_info, (int) len, message);
}
exit:
if (take_lock)
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
return result;
}
@ -1590,7 +1614,7 @@ static int do_log_user(const char *name, int len,
return 0;
if (take_lock)
flogger_mutex_lock(&lock_operations);
mysql_prlock_rdlock(&lock_operations);
if (incl_user_coll.n_users)
{
@ -1606,7 +1630,7 @@ static int do_log_user(const char *name, int len,
result= 1;
if (take_lock)
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
return result;
}
@ -1824,6 +1848,7 @@ do_log_query:
{
case SQLCOM_GRANT:
case SQLCOM_CREATE_USER:
case SQLCOM_ALTER_USER:
csize+= escape_string_hide_passwords(query, query_len,
uh_buffer, uh_buffer_size,
"IDENTIFIED", 10, "BY", 2, 0);
@ -2502,11 +2527,11 @@ static int server_audit_init(void *p __attribute__((unused)))
servhost_len= (uint)strlen(servhost);
logger_init_mutexes();
#if defined(HAVE_PSI_INTERFACE) && !defined(FLOGGER_NO_PSI)
#ifdef HAVE_PSI_INTERFACE
if (PSI_server)
PSI_server->register_mutex("server_audit", mutex_key_list, 1);
#endif
flogger_mutex_init(key_LOCK_operations, &lock_operations, MY_MUTEX_INIT_FAST);
mysql_prlock_init(key_LOCK_operations, &lock_operations);
flogger_mutex_init(key_LOCK_operations, &lock_atomic, MY_MUTEX_INIT_FAST);
flogger_mutex_init(key_LOCK_operations, &lock_bigbuffer, MY_MUTEX_INIT_FAST);
@ -2594,7 +2619,7 @@ static int server_audit_deinit(void *p __attribute__((unused)))
closelog();
(void) free(big_buffer);
flogger_mutex_destroy(&lock_operations);
mysql_prlock_destroy(&lock_operations);
flogger_mutex_destroy(&lock_atomic);
flogger_mutex_destroy(&lock_bigbuffer);
@ -2705,7 +2730,7 @@ static void update_file_path(MYSQL_THD thd,
fprintf(stderr, "Log file name was changed to '%s'.\n", new_name);
if (!maria_55_started || !debug_server_started)
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
if (logging)
log_current_query(thd);
@ -2737,7 +2762,7 @@ static void update_file_path(MYSQL_THD thd,
file_path= path_buffer;
exit_func:
if (!maria_55_started || !debug_server_started)
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
ADD_ATOMIC(internal_stop_logging, -1);
}
@ -2753,9 +2778,9 @@ static void update_file_rotations(MYSQL_THD thd __attribute__((unused)),
if (!logging || output_type != OUTPUT_FILE)
return;
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
logfile->rotations= rotations;
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
}
@ -2771,9 +2796,9 @@ static void update_file_rotate_size(MYSQL_THD thd __attribute__((unused)),
if (!logging || output_type != OUTPUT_FILE)
return;
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
logfile->size_limit= file_rotate_size;
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
}
@ -2818,7 +2843,7 @@ static void update_incl_users(MYSQL_THD thd,
char *new_users= (*(char **) save) ? *(char **) save : empty_str;
size_t new_len= strlen(new_users) + 1;
if (!maria_55_started || !debug_server_started)
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
mark_always_logged(thd);
if (new_len > sizeof(incl_user_buffer))
@ -2832,7 +2857,7 @@ static void update_incl_users(MYSQL_THD thd,
error_header();
fprintf(stderr, "server_audit_incl_users set to '%s'.\n", incl_users);
if (!maria_55_started || !debug_server_started)
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
}
@ -2843,7 +2868,7 @@ static void update_excl_users(MYSQL_THD thd __attribute__((unused)),
char *new_users= (*(char **) save) ? *(char **) save : empty_str;
size_t new_len= strlen(new_users) + 1;
if (!maria_55_started || !debug_server_started)
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
mark_always_logged(thd);
if (new_len > sizeof(excl_user_buffer))
@ -2857,7 +2882,7 @@ static void update_excl_users(MYSQL_THD thd __attribute__((unused)),
error_header();
fprintf(stderr, "server_audit_excl_users set to '%s'.\n", excl_users);
if (!maria_55_started || !debug_server_started)
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
}
@ -2870,7 +2895,7 @@ static void update_output_type(MYSQL_THD thd,
return;
ADD_ATOMIC(internal_stop_logging, 1);
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
if (logging)
{
log_current_query(thd);
@ -2884,7 +2909,7 @@ static void update_output_type(MYSQL_THD thd,
if (logging)
start_logging();
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
ADD_ATOMIC(internal_stop_logging, -1);
}
@ -2914,9 +2939,9 @@ static void update_syslog_priority(MYSQL_THD thd __attribute__((unused)),
if (syslog_priority == new_priority)
return;
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
mark_always_logged(thd);
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
error_header();
fprintf(stderr, "SysLog priority was changed from '%s' to '%s'.\n",
syslog_priority_names[syslog_priority],
@ -2935,7 +2960,7 @@ static void update_logging(MYSQL_THD thd,
ADD_ATOMIC(internal_stop_logging, 1);
if (!maria_55_started || !debug_server_started)
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
if ((logging= new_logging))
{
start_logging();
@ -2952,7 +2977,7 @@ static void update_logging(MYSQL_THD thd,
}
if (!maria_55_started || !debug_server_started)
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
ADD_ATOMIC(internal_stop_logging, -1);
}
@ -2967,13 +2992,13 @@ static void update_mode(MYSQL_THD thd __attribute__((unused)),
ADD_ATOMIC(internal_stop_logging, 1);
if (!maria_55_started || !debug_server_started)
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
mark_always_logged(thd);
error_header();
fprintf(stderr, "Logging mode was changed from %d to %d.\n", mode, new_mode);
mode= new_mode;
if (!maria_55_started || !debug_server_started)
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
ADD_ATOMIC(internal_stop_logging, -1);
}
@ -2988,14 +3013,14 @@ static void update_syslog_ident(MYSQL_THD thd __attribute__((unused)),
syslog_ident= syslog_ident_buffer;
error_header();
fprintf(stderr, "SYSYLOG ident was changed to '%s'\n", syslog_ident);
flogger_mutex_lock(&lock_operations);
mysql_prlock_wrlock(&lock_operations);
mark_always_logged(thd);
if (logging && output_type == OUTPUT_SYSLOG)
{
stop_logging();
start_logging();
}
flogger_mutex_unlock(&lock_operations);
mysql_prlock_unlock(&lock_operations);
}

View file

@ -9182,7 +9182,6 @@ int ha_partition::extra(enum ha_extra_function operation)
case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN:
case HA_EXTRA_BEGIN_ALTER_COPY:
case HA_EXTRA_END_ALTER_COPY:
case HA_EXTRA_FAKE_START_STMT:
DBUG_RETURN(loop_partitions(extra_cb, &operation));
default:
{

View file

@ -1799,6 +1799,12 @@ handlerton *ha_default_tmp_handlerton(THD *thd);
*/
#define HTON_TRANSACTIONAL_AND_NON_TRANSACTIONAL (1 << 17)
/*
Table requires and close and reopen after truncate
If the handler has HTON_CAN_RECREATE, this flag is not used
*/
#define HTON_REQUIRES_CLOSE_AFTER_TRUNCATE (1 << 18)
class Ha_trx_info;
struct THD_TRANS

View file

@ -9372,7 +9372,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
def_field->reset_fields();
// If non-constant default value expression or a blob
if (def_field->default_value &&
(def_field->default_value->flags || def_field->flags & BLOB_FLAG))
(def_field->default_value->flags || (def_field->flags & BLOB_FLAG)))
{
uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length());
if (!newptr)
@ -9476,11 +9476,60 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
return Item_field::save_in_field(field_arg, no_conversions);
}
double Item_default_value::val_result()
{
calculate();
return Item_field::val_result();
}
longlong Item_default_value::val_int_result()
{
calculate();
return Item_field::val_int_result();
}
String *Item_default_value::str_result(String* tmp)
{
calculate();
return Item_field::str_result(tmp);
}
bool Item_default_value::val_bool_result()
{
calculate();
return Item_field::val_bool_result();
}
bool Item_default_value::is_null_result()
{
calculate();
return Item_field::is_null_result();
}
my_decimal *Item_default_value::val_decimal_result(my_decimal *decimal_value)
{
calculate();
return Item_field::val_decimal_result(decimal_value);
}
bool Item_default_value::get_date_result(THD *thd, MYSQL_TIME *ltime,
date_mode_t fuzzydate)
{
calculate();
return Item_field::get_date_result(thd, ltime, fuzzydate);
}
bool Item_default_value::val_native_result(THD *thd, Native *to)
{
calculate();
return Item_field::val_native_result(thd, to);
}
table_map Item_default_value::used_tables() const
{
if (!field || !field->default_value)
return static_cast<table_map>(0);
if (!field->default_value->expr) // not fully parsed field
if (!field->default_value->expr) // not fully parsed field
return static_cast<table_map>(RAND_TABLE_BIT);
return field->default_value->expr->used_tables();
}

View file

@ -2,7 +2,7 @@
#define SQL_ITEM_INCLUDED
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
Copyright (c) 2009, 2020, MariaDB Corporation.
Copyright (c) 2009, 2021, 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
@ -6428,6 +6428,17 @@ public:
my_decimal *val_decimal(my_decimal *decimal_value);
bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate);
bool val_native(THD *thd, Native *to);
bool val_native_result(THD *thd, Native *to);
/* Result variants */
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
my_decimal *val_decimal_result(my_decimal *val);
bool val_bool_result();
bool is_null_result();
bool get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool send(Protocol *protocol, st_value *buffer);
int save_in_field(Field *field_arg, bool no_conversions);
bool save_in_param(THD *thd, Item_param *param)
@ -6456,6 +6467,8 @@ public:
}
Item *transform(THD *thd, Item_transformer transformer, uchar *args);
Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
};

View file

@ -1395,7 +1395,9 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
/*
Presumably, ANALYZE and binlog writing doesn't require synchronization
*/
thd->get_stmt_da()->set_overwrite_status(true);
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
thd->get_stmt_da()->set_overwrite_status(false);
}
m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table;

View file

@ -3345,6 +3345,146 @@ bool Sql_cmd_call::execute(THD *thd)
}
/**
Check whether the SQL statement being processed is prepended by
SET STATEMENT clause and handle variables assignment if it is.
@param thd thread handle
@param lex current lex
@return false in case of success, true in case of error.
*/
bool run_set_statement_if_requested(THD *thd, LEX *lex)
{
if (!lex->stmt_var_list.is_empty() && !thd->slave_thread)
{
Query_arena backup;
DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements));
lex->old_var_list.empty();
List_iterator_fast<set_var_base> it(lex->stmt_var_list);
set_var_base *var;
if (lex->set_arena_for_set_stmt(&backup))
return true;
MEM_ROOT *mem_root= thd->mem_root;
while ((var= it++))
{
DBUG_ASSERT(var->is_system());
set_var *o= NULL, *v= (set_var*)var;
if (!v->var->is_set_stmt_ok())
{
my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str);
lex->reset_arena_for_set_stmt(&backup);
lex->old_var_list.empty();
lex->free_arena_for_set_stmt();
return true;
}
if (v->var->session_is_default(thd))
o= new set_var(thd,v->type, v->var, &v->base, NULL);
else
{
switch (v->var->option.var_type & GET_TYPE_MASK)
{
case GET_BOOL:
case GET_INT:
case GET_LONG:
case GET_LL:
{
bool null_value;
longlong val= v->var->val_int(&null_value, thd, v->type, &v->base);
o= new set_var(thd, v->type, v->var, &v->base,
(null_value ?
(Item *) new (mem_root) Item_null(thd) :
(Item *) new (mem_root) Item_int(thd, val)));
}
break;
case GET_UINT:
case GET_ULONG:
case GET_ULL:
{
bool null_value;
ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base);
o= new set_var(thd, v->type, v->var, &v->base,
(null_value ?
(Item *) new (mem_root) Item_null(thd) :
(Item *) new (mem_root) Item_uint(thd, val)));
}
break;
case GET_DOUBLE:
{
bool null_value;
double val= v->var->val_real(&null_value, thd, v->type, &v->base);
o= new set_var(thd, v->type, v->var, &v->base,
(null_value ?
(Item *) new (mem_root) Item_null(thd) :
(Item *) new (mem_root) Item_float(thd, val, 1)));
}
break;
default:
case GET_NO_ARG:
case GET_DISABLED:
DBUG_ASSERT(0);
/* fall through */
case 0:
case GET_FLAGSET:
case GET_ENUM:
case GET_SET:
case GET_STR:
case GET_STR_ALLOC:
{
char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff, sizeof(buff), v->var->charset(thd)),*val;
val= v->var->val_str(&tmp, thd, v->type, &v->base);
if (val)
{
Item_string *str=
new (mem_root) Item_string(thd, v->var->charset(thd),
val->ptr(), val->length());
o= new set_var(thd, v->type, v->var, &v->base, str);
}
else
o= new set_var(thd, v->type, v->var, &v->base,
new (mem_root) Item_null(thd));
}
break;
}
}
DBUG_ASSERT(o);
lex->old_var_list.push_back(o, thd->mem_root);
}
lex->reset_arena_for_set_stmt(&backup);
if (lex->old_var_list.is_empty())
lex->free_arena_for_set_stmt();
if (thd->is_error() ||
sql_set_variables(thd, &lex->stmt_var_list, false))
{
if (!thd->is_error())
my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET");
lex->restore_set_statement_var();
return true;
}
/*
The value of last_insert_id is remembered in THD to be written to binlog
when it's used *the first time* in the statement. But SET STATEMENT
must read the old value of last_insert_id to be able to restore it at
the end. This should not count at "reading of last_insert_id" and
should not remember last_insert_id for binlog. That is, it should clear
stmt_depends_on_first_successful_insert_id_in_prev_stmt flag.
*/
if (!thd->in_sub_stmt)
{
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
}
}
return false;
}
/**
Execute command saved in thd and lex->sql_command.
@ -3631,127 +3771,13 @@ mysql_execute_command(THD *thd)
thd->get_binlog_format(&orig_binlog_format,
&orig_current_stmt_binlog_format);
if (!lex->stmt_var_list.is_empty() && !thd->slave_thread)
{
Query_arena backup;
DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements));
lex->old_var_list.empty();
List_iterator_fast<set_var_base> it(lex->stmt_var_list);
set_var_base *var;
if (lex->set_arena_for_set_stmt(&backup))
goto error;
MEM_ROOT *mem_root= thd->mem_root;
while ((var= it++))
{
DBUG_ASSERT(var->is_system());
set_var *o= NULL, *v= (set_var*)var;
if (!v->var->is_set_stmt_ok())
{
my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str);
lex->reset_arena_for_set_stmt(&backup);
lex->old_var_list.empty();
lex->free_arena_for_set_stmt();
goto error;
}
if (v->var->session_is_default(thd))
o= new set_var(thd,v->type, v->var, &v->base, NULL);
else
{
switch (v->var->option.var_type & GET_TYPE_MASK)
{
case GET_BOOL:
case GET_INT:
case GET_LONG:
case GET_LL:
{
bool null_value;
longlong val= v->var->val_int(&null_value, thd, v->type, &v->base);
o= new set_var(thd, v->type, v->var, &v->base,
(null_value ?
(Item *) new (mem_root) Item_null(thd) :
(Item *) new (mem_root) Item_int(thd, val)));
}
break;
case GET_UINT:
case GET_ULONG:
case GET_ULL:
{
bool null_value;
ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base);
o= new set_var(thd, v->type, v->var, &v->base,
(null_value ?
(Item *) new (mem_root) Item_null(thd) :
(Item *) new (mem_root) Item_uint(thd, val)));
}
break;
case GET_DOUBLE:
{
bool null_value;
double val= v->var->val_real(&null_value, thd, v->type, &v->base);
o= new set_var(thd, v->type, v->var, &v->base,
(null_value ?
(Item *) new (mem_root) Item_null(thd) :
(Item *) new (mem_root) Item_float(thd, val, 1)));
}
break;
default:
case GET_NO_ARG:
case GET_DISABLED:
DBUG_ASSERT(0);
/* fall through */
case 0:
case GET_FLAGSET:
case GET_ENUM:
case GET_SET:
case GET_STR:
case GET_STR_ALLOC:
{
char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff, sizeof(buff), v->var->charset(thd)),*val;
val= v->var->val_str(&tmp, thd, v->type, &v->base);
if (val)
{
Item_string *str= new (mem_root) Item_string(thd, v->var->charset(thd),
val->ptr(), val->length());
o= new set_var(thd, v->type, v->var, &v->base, str);
}
else
o= new set_var(thd, v->type, v->var, &v->base,
new (mem_root) Item_null(thd));
}
break;
}
}
DBUG_ASSERT(o);
lex->old_var_list.push_back(o, thd->mem_root);
}
lex->reset_arena_for_set_stmt(&backup);
if (lex->old_var_list.is_empty())
lex->free_arena_for_set_stmt();
if (thd->is_error() ||
(res= sql_set_variables(thd, &lex->stmt_var_list, false)))
{
if (!thd->is_error())
my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET");
lex->restore_set_statement_var();
goto error;
}
/*
The value of last_insert_id is remembered in THD to be written to binlog
when it's used *the first time* in the statement. But SET STATEMENT
must read the old value of last_insert_id to be able to restore it at
the end. This should not count at "reading of last_insert_id" and
should not remember last_insert_id for binlog. That is, it should clear
stmt_depends_on_first_successful_insert_id_in_prev_stmt flag.
*/
if (!thd->in_sub_stmt)
{
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
}
}
/*
Assign system variables with values specified by the clause
SET STATEMENT var1=value1 [, var2=value2, ...] FOR <statement>
if they are any.
*/
if (run_set_statement_if_requested(thd, lex))
goto error;
if (thd->lex->mi.connection_name.str == NULL)
thd->lex->mi.connection_name= thd->variables.default_master_connection;

View file

@ -100,6 +100,7 @@ void mysql_init_multi_delete(LEX *lex);
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
void create_table_set_open_action_and_adjust_tables(LEX *lex);
int bootstrap(MYSQL_FILE *file);
bool run_set_statement_if_requested(THD *thd, LEX *lex);
int mysql_execute_command(THD *thd);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,

View file

@ -4260,6 +4260,16 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
*/
MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
/*
Set variables specified by
SET STATEMENT var1=value1 [, var2=value2, ...] FOR <statement>
clause for duration of prepare phase. Original values of variable
listed in the SET STATEMENT clause is restored right after return
from the function check_prepared_statement()
*/
if (likely(error == 0))
error= run_set_statement_if_requested(thd, lex);
/*
The only case where we should have items in the thd->free_list is
after stmt->set_params_from_vars(), which may in some cases create
@ -4278,6 +4288,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE;
}
/*
Restore original values of variables modified on handling
SET STATEMENT clause.
*/
thd->lex->restore_set_statement_var();
/* The order is important */
lex->unit.cleanup();

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
Copyright (c) 2009, 2020, MariaDB Corporation.
Copyright (c) 2009, 2021, 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
@ -4682,6 +4682,9 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
}
else
{
if (thd->lex->describe)
select_options|= SELECT_DESCRIBE;
/*
When in EXPLAIN, delay deleting the joins so that they are still
available when we're producing EXPLAIN EXTENDED warning text.
@ -14499,22 +14502,71 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
DBUG_RETURN(0);
}
/*
used only in JOIN::clear
/**
used only in JOIN::clear (always) and in do_select()
(if there where no matching rows)
@param join JOIN
@param cleared_tables If not null, clear also const tables and mark all
cleared tables in the map. cleared_tables is only
set when called from do_select() when there is a
group function and there where no matching rows.
*/
static void clear_tables(JOIN *join)
static void clear_tables(JOIN *join, table_map *cleared_tables)
{
/*
must clear only the non-const tables, as const tables
are not re-calculated.
must clear only the non-const tables as const tables are not re-calculated.
*/
for (uint i= 0 ; i < join->table_count ; i++)
{
if (!(join->table[i]->map & join->const_table_map))
mark_as_null_row(join->table[i]); // All fields are NULL
TABLE *table= join->table[i];
if (table->null_row)
continue; // Nothing more to do
if (!(table->map & join->const_table_map) || cleared_tables)
{
if (cleared_tables)
{
(*cleared_tables)|= (((table_map) 1) << i);
if (table->s->null_bytes)
{
/*
Remember null bits for the record so that we can restore the
original const record in unclear_tables()
*/
memcpy(table->record[1], table->null_flags, table->s->null_bytes);
}
}
mark_as_null_row(table); // All fields are NULL
}
}
}
/**
Reverse null marking for tables and restore null bits.
We have to do this because the tables may be re-used in a sub query
and the subquery will assume that the const tables contains the original
data before clear_tables().
*/
static void unclear_tables(JOIN *join, table_map *cleared_tables)
{
for (uint i= 0 ; i < join->table_count ; i++)
{
if ((*cleared_tables) & (((table_map) 1) << i))
{
TABLE *table= join->table[i];
if (table->s->null_bytes)
memcpy(table->null_flags, table->record[1], table->s->null_bytes);
unmark_as_null_row(table);
}
}
}
/*****************************************************************************
Make som simple condition optimization:
If there is a test 'field = const' change all refs to 'field' to 'const'
@ -17985,17 +18037,34 @@ Field *Item_field::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
src->set_field(field);
if (!(result= create_tmp_field_from_item_field(root, table, NULL, param)))
return NULL;
/*
Fields that are used as arguments to the DEFAULT() function already have
their data pointers set to the default value during name resolution. See
Item_default_value::fix_fields.
*/
if (type() != Item::DEFAULT_VALUE_ITEM && field->eq_def(result))
if (field->eq_def(result))
src->set_default_field(field);
return result;
}
Field *Item_default_value::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
if (field->default_value && (field->flags & BLOB_FLAG))
{
/*
We have to use a copy function when using a blob with default value
as the we have to calculate the default value before we can use it.
*/
get_tmp_field_src(src, param);
return tmp_table_field_from_field_type(root, table);
}
/*
Same code as in Item_field::create_tmp_field_ex, except no default field
handling
*/
src->set_field(field);
return create_tmp_field_from_item_field(root, table, nullptr, param);
}
Field *Item_ref::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
@ -18097,7 +18166,13 @@ Field *Item_func_sp::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
the record in the original table.
If modify_item is 0 then fill_record() will update
the temporary table
@param table_cant_handle_bit_fields
Set to 1 if the temporary table cannot handle bit
fields. Only set for heap tables when the bit field
is part of an index.
@param make_copy_field
Set when using with rollup when we want to have
an exact copy of the field.
@retval
0 on error
@retval
@ -20162,6 +20237,7 @@ do_select(JOIN *join, Procedure *procedure)
if (join->only_const_tables() && !join->need_tmp)
{
Next_select_func end_select= setup_end_select_func(join, NULL);
/*
HAVING will be checked after processing aggregate functions,
But WHERE should checked here (we alredy have read tables).
@ -20188,6 +20264,17 @@ do_select(JOIN *join, Procedure *procedure)
}
else if (join->send_row_on_empty_set())
{
table_map cleared_tables= (table_map) 0;
if (end_select == end_send_group)
{
/*
Was a grouping query but we did not find any rows. In this case
we clear all tables to get null in any referenced fields,
like in case of:
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL
*/
clear_tables(join, &cleared_tables);
}
if (!join->having || join->having->val_int())
{
List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
@ -20195,6 +20282,12 @@ do_select(JOIN *join, Procedure *procedure)
rc= join->result->send_data_with_check(*columns_list,
join->unit, 0) > 0;
}
/*
We have to remove the null markings from the tables as this table
may be part of a sub query that is re-evaluated
*/
if (cleared_tables)
unclear_tables(join, &cleared_tables);
}
/*
An error can happen when evaluating the conds
@ -21175,8 +21268,8 @@ join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos)
if ((table->null_row= MY_TEST((*tab->on_expr_ref)->val_int() == 0)))
mark_as_null_row(table);
}
if (!table->null_row)
table->maybe_null=0;
if (!table->null_row && ! tab->join->mixed_implicit_grouping)
table->maybe_null= 0;
{
JOIN *join= tab->join;
@ -26334,7 +26427,7 @@ int JOIN::rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param_arg, TABL
void JOIN::clear()
{
clear_tables(this);
clear_tables(this, 0);
copy_fields(&tmp_table_param);
if (sum_funcs)

View file

@ -477,6 +477,15 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
*/
error= handler_truncate(thd, table_ref, FALSE);
if (error == TRUNCATE_OK && thd->locked_tables_mode &&
(table_ref->table->file->ht->flags &
HTON_REQUIRES_CLOSE_AFTER_TRUNCATE))
{
thd->locked_tables_list.mark_table_for_reopen(thd, table_ref->table);
if (unlikely(thd->locked_tables_list.reopen_tables(thd, true)))
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
}
/*
All effects of a TRUNCATE TABLE operation are committed even if
truncation fails in the case of non transactional tables. Thus, the

View file

@ -679,7 +679,7 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl,
st_select_lex *parent_select)
{
LEX *lex= thd->lex;
select_result *save_result= thd->lex->result;
select_result *save_result= lex->result;
uint8 save_derived_tables= lex->derived_tables;
thd->lex->result= NULL;
@ -760,13 +760,13 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl,
if (arena)
thd->restore_active_arena(arena, &backup);
thd->lex->result= save_result;
lex->result= save_result;
return wrapper_sl;
err:
if (arena)
thd->restore_active_arena(arena, &backup);
thd->lex->result= save_result;
lex->result= save_result;
lex->derived_tables= save_derived_tables;
return 0;
}
@ -851,14 +851,9 @@ Item_subselect::wrap_tvc_into_select(THD *thd, st_select_lex *tvc_sl)
{
if (engine->engine_type() == subselect_engine::SINGLE_SELECT_ENGINE)
((subselect_single_select_engine *) engine)->change_select(wrapper_sl);
lex->current_select= wrapper_sl;
return wrapper_sl;
}
else
{
lex->current_select= parent_select;
return 0;
}
lex->current_select= parent_select;
return wrapper_sl;
}

View file

@ -3202,6 +3202,12 @@ inline void mark_as_null_row(TABLE *table)
bfill(table->null_flags,table->s->null_bytes,255);
}
inline void unmark_as_null_row(TABLE *table)
{
table->null_row=0;
table->status= STATUS_NO_RECORD;
}
bool is_simple_order(ORDER *order);
class Open_tables_backup;

View file

@ -3834,8 +3834,10 @@ static int innodb_init(void* p)
innobase_hton->show_status = innobase_show_status;
innobase_hton->notify_tabledef_changed= innodb_notify_tabledef_changed;
innobase_hton->flags =
HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS
| HTON_NATIVE_SYS_VERSIONING | HTON_WSREP_REPLICATION;
HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS |
HTON_NATIVE_SYS_VERSIONING |
HTON_WSREP_REPLICATION |
HTON_REQUIRES_CLOSE_AFTER_TRUNCATE;
#ifdef WITH_WSREP
innobase_hton->abort_transaction=wsrep_abort_transaction;
@ -15375,10 +15377,6 @@ ha_innobase::extra(
case HA_EXTRA_END_ALTER_COPY:
m_prebuilt->table->skip_alter_undo = 0;
break;
case HA_EXTRA_FAKE_START_STMT:
trx_register_for_2pc(m_prebuilt->trx);
m_prebuilt->sql_stat_start = true;
break;
default:/* Do nothing */
;
}

View file

@ -4158,6 +4158,18 @@ lock_check_dict_lock(
and release possible other transactions waiting because of these locks. */
void lock_release(trx_t* trx)
{
#ifdef UNIV_DEBUG
std::set<table_id_t> to_evict;
if (innodb_evict_tables_on_commit_debug && !trx->is_recovered)
# if 1 /* if dict_stats_exec_sql() were not playing dirty tricks */
if (!mutex_own(&dict_sys.mutex))
# else /* this would be more proper way to do it */
if (!trx->dict_operation_lock_mode && !trx->dict_operation)
# endif
for (const auto& p : trx->mod_tables)
if (!p.first->is_temporary())
to_evict.emplace(p.first->id);
#endif
ulint count = 0;
trx_id_t max_trx_id = trx_sys.get_max_trx_id();
@ -4206,6 +4218,25 @@ void lock_release(trx_t* trx)
}
lock_mutex_exit();
#ifdef UNIV_DEBUG
if (to_evict.empty()) {
return;
}
mutex_enter(&dict_sys.mutex);
lock_mutex_enter();
for (table_id_t id : to_evict) {
if (dict_table_t *table = dict_table_open_on_id(
id, TRUE, DICT_TABLE_OP_OPEN_ONLY_IF_CACHED)) {
if (!table->get_ref_count()
&& !UT_LIST_GET_LEN(table->locks)) {
dict_sys.remove(table, true);
}
}
}
lock_mutex_exit();
mutex_exit(&dict_sys.mutex);
#endif
}
/* True if a lock mode is S or X */

View file

@ -1245,16 +1245,6 @@ trx_update_mod_tables_timestamp(
const time_t now = time(NULL);
trx_mod_tables_t::const_iterator end = trx->mod_tables.end();
#ifdef UNIV_DEBUG
const bool preserve_tables = !innodb_evict_tables_on_commit_debug
|| trx->is_recovered /* avoid trouble with XA recovery */
# if 1 /* if dict_stats_exec_sql() were not playing dirty tricks */
|| mutex_own(&dict_sys.mutex)
# else /* this would be more proper way to do it */
|| trx->dict_operation_lock_mode || trx->dict_operation
# endif
;
#endif
for (trx_mod_tables_t::const_iterator it = trx->mod_tables.begin();
it != end;
@ -1270,26 +1260,6 @@ trx_update_mod_tables_timestamp(
intrusive. */
dict_table_t* table = it->first;
table->update_time = now;
#ifdef UNIV_DEBUG
if (preserve_tables || table->get_ref_count()
|| UT_LIST_GET_LEN(table->locks)) {
/* do not evict when committing DDL operations
or if some other transaction is holding the
table handle */
continue;
}
/* recheck while holding the mutex that blocks
table->acquire() */
mutex_enter(&dict_sys.mutex);
mutex_enter(&lock_sys.mutex);
const bool do_evict = !table->get_ref_count()
&& !UT_LIST_GET_LEN(table->locks);
mutex_exit(&lock_sys.mutex);
if (do_evict) {
dict_sys.remove(table, true);
}
mutex_exit(&dict_sys.mutex);
#endif
}
trx->mod_tables.clear();
@ -1375,16 +1345,9 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr)
so that there will be no race condition in lock_release(). */
while (UNIV_UNLIKELY(is_referenced()))
ut_delay(srv_spin_wait_delay);
release_locks();
id= 0;
}
else
{
ut_ad(read_only || !rsegs.m_redo.rseg);
release_locks();
}
DEBUG_SYNC_C("after_trx_committed_in_memory");
if (read_only || !rsegs.m_redo.rseg)
{
@ -1397,6 +1360,10 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr)
is_recovered= false;
}
release_locks();
id= 0;
DEBUG_SYNC_C("after_trx_committed_in_memory");
while (dict_table_t *table= UT_LIST_GET_FIRST(lock.evicted_tables))
{
UT_LIST_REMOVE(lock.evicted_tables, table);

View file

@ -1464,6 +1464,7 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
}
if (maria_is_crashed(info))
{
tprint(tracef, "\n");
eprint(tracef, "Table '%s' is crashed, skipping it. Please repair it with"
" aria_chk -r", share->open_file_name.str);
recovery_found_crashed_tables++;

View file

@ -98,6 +98,7 @@ void eprint(FILE *trace_file __attribute__ ((unused)),
fputc('\n', trace_file);
if (trace_file != stderr)
{
va_start(args, format);
my_printv_error(HA_ERR_INITIALIZATION, format, MYF(0), args);
}
va_end(args);

View file

@ -550,9 +550,6 @@ static const char *mrn_inspect_extra_function(enum ha_extra_function operation)
case HA_EXTRA_END_ALTER_COPY:
inspected = "HA_EXTRA_END_ALTER_COPY";
break;
case HA_EXTRA_FAKE_START_STMT:
inspected = "HA_EXTRA_FAKE_START_STMT";
break;
#ifdef MRN_HAVE_HA_EXTRA_EXPORT
case HA_EXTRA_EXPORT:
inspected = "HA_EXTRA_EXPORT";