Merge 10.4 into 10.5
This commit is contained in:
commit
6a1e655cb0
@ -863,21 +863,14 @@ datafile_rsync_backup(const char *filepath, bool save_to_list, FILE *f)
|
|||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool backup_file_print_buf(const char *filename, const char *buf, int buf_len)
|
||||||
static
|
|
||||||
bool
|
|
||||||
backup_file_vprintf(const char *filename, const char *fmt, va_list ap)
|
|
||||||
{
|
{
|
||||||
ds_file_t *dstfile = NULL;
|
ds_file_t *dstfile = NULL;
|
||||||
MY_STAT stat; /* unused for now */
|
MY_STAT stat; /* unused for now */
|
||||||
char *buf = 0;
|
|
||||||
int buf_len;
|
|
||||||
const char *action;
|
const char *action;
|
||||||
|
|
||||||
memset(&stat, 0, sizeof(stat));
|
memset(&stat, 0, sizeof(stat));
|
||||||
|
|
||||||
buf_len = vasprintf(&buf, fmt, ap);
|
|
||||||
|
|
||||||
stat.st_size = buf_len;
|
stat.st_size = buf_len;
|
||||||
stat.st_mtime = my_time(0);
|
stat.st_mtime = my_time(0);
|
||||||
|
|
||||||
@ -901,7 +894,6 @@ backup_file_vprintf(const char *filename, const char *fmt, va_list ap)
|
|||||||
|
|
||||||
/* close */
|
/* close */
|
||||||
msg(" ...done");
|
msg(" ...done");
|
||||||
free(buf);
|
|
||||||
|
|
||||||
if (ds_close(dstfile)) {
|
if (ds_close(dstfile)) {
|
||||||
goto error_close;
|
goto error_close;
|
||||||
@ -910,7 +902,6 @@ backup_file_vprintf(const char *filename, const char *fmt, va_list ap)
|
|||||||
return(true);
|
return(true);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
free(buf);
|
|
||||||
if (dstfile != NULL) {
|
if (dstfile != NULL) {
|
||||||
ds_close(dstfile);
|
ds_close(dstfile);
|
||||||
}
|
}
|
||||||
@ -918,8 +909,21 @@ error:
|
|||||||
error_close:
|
error_close:
|
||||||
msg("Error: backup file failed.");
|
msg("Error: backup file failed.");
|
||||||
return(false); /*ERROR*/
|
return(false); /*ERROR*/
|
||||||
}
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
backup_file_vprintf(const char *filename, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
char *buf = 0;
|
||||||
|
int buf_len;
|
||||||
|
buf_len = vasprintf(&buf, fmt, ap);
|
||||||
|
bool result = backup_file_print_buf(filename, buf, buf_len);
|
||||||
|
free(buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
backup_file_printf(const char *filename, const char *fmt, ...)
|
backup_file_printf(const char *filename, const char *fmt, ...)
|
||||||
@ -1441,7 +1445,7 @@ out:
|
|||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void backup_fix_ddl(void);
|
void backup_fix_ddl(CorruptedPages &);
|
||||||
|
|
||||||
lsn_t get_current_lsn(MYSQL *connection)
|
lsn_t get_current_lsn(MYSQL *connection)
|
||||||
{
|
{
|
||||||
@ -1466,7 +1470,7 @@ lsn_t get_current_lsn(MYSQL *connection)
|
|||||||
lsn_t server_lsn_after_lock;
|
lsn_t server_lsn_after_lock;
|
||||||
extern void backup_wait_for_lsn(lsn_t lsn);
|
extern void backup_wait_for_lsn(lsn_t lsn);
|
||||||
/** Start --backup */
|
/** Start --backup */
|
||||||
bool backup_start()
|
bool backup_start(CorruptedPages &corrupted_pages)
|
||||||
{
|
{
|
||||||
if (!opt_no_lock) {
|
if (!opt_no_lock) {
|
||||||
if (opt_safe_slave_backup) {
|
if (opt_safe_slave_backup) {
|
||||||
@ -1501,7 +1505,7 @@ bool backup_start()
|
|||||||
|
|
||||||
msg("Waiting for log copy thread to read lsn %llu", (ulonglong)server_lsn_after_lock);
|
msg("Waiting for log copy thread to read lsn %llu", (ulonglong)server_lsn_after_lock);
|
||||||
backup_wait_for_lsn(server_lsn_after_lock);
|
backup_wait_for_lsn(server_lsn_after_lock);
|
||||||
backup_fix_ddl();
|
backup_fix_ddl(corrupted_pages);
|
||||||
|
|
||||||
// There is no need to stop slave thread before coping non-Innodb data when
|
// There is no need to stop slave thread before coping non-Innodb data when
|
||||||
// --no-lock option is used because --no-lock option requires that no DDL or
|
// --no-lock option is used because --no-lock option requires that no DDL or
|
||||||
|
@ -33,7 +33,7 @@ copy_file(ds_ctxt_t *datasink,
|
|||||||
uint thread_n);
|
uint thread_n);
|
||||||
|
|
||||||
/** Start --backup */
|
/** Start --backup */
|
||||||
bool backup_start();
|
bool backup_start(CorruptedPages &corrupted_pages);
|
||||||
/** Release resources after backup_start() */
|
/** Release resources after backup_start() */
|
||||||
void backup_release();
|
void backup_release();
|
||||||
/** Finish after backup_start() and backup_release() */
|
/** Finish after backup_start() and backup_release() */
|
||||||
@ -51,5 +51,6 @@ directory_exists(const char *dir, bool create);
|
|||||||
|
|
||||||
lsn_t
|
lsn_t
|
||||||
get_current_lsn(MYSQL *connection);
|
get_current_lsn(MYSQL *connection);
|
||||||
|
bool backup_file_print_buf(const char *filename, const char *buf, int buf_len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
32
extra/mariabackup/backup_debug.h
Normal file
32
extra/mariabackup/backup_debug.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "my_dbug.h"
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
extern char *dbug_mariabackup_get_val(const char *event, const char *key);
|
||||||
|
/*
|
||||||
|
In debug mode, execute SQL statement that was passed via environment.
|
||||||
|
To use this facility, you need to
|
||||||
|
|
||||||
|
1. Add code DBUG_EXECUTE_MARIABACKUP_EVENT("my_event_name", key););
|
||||||
|
to the code. key is usually a table name
|
||||||
|
2. Set environment variable my_event_name_$key SQL statement you want to execute
|
||||||
|
when event occurs, in DBUG_EXECUTE_IF from above.
|
||||||
|
In mtr , you can set environment via 'let' statement (do not use $ as the first char
|
||||||
|
for the variable)
|
||||||
|
3. start mariabackup with --dbug=+d,debug_mariabackup_events
|
||||||
|
*/
|
||||||
|
extern void dbug_mariabackup_event(
|
||||||
|
const char *event,const char *key);
|
||||||
|
#define DBUG_MARIABACKUP_EVENT(A, B) \
|
||||||
|
DBUG_EXECUTE_IF("mariabackup_events", \
|
||||||
|
dbug_mariabackup_event(A,B););
|
||||||
|
#define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE) \
|
||||||
|
DBUG_EXECUTE_IF("mariabackup_inject_code", {\
|
||||||
|
char *dbug_val = dbug_mariabackup_get_val(EVENT, KEY); \
|
||||||
|
if (dbug_val && *dbug_val) CODE \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
#define DBUG_MARIABACKUP_EVENT(A,B)
|
||||||
|
#define DBUG_MARIABACKUP_EVENT_LOCK(A,B)
|
||||||
|
#define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE)
|
||||||
|
#endif
|
||||||
|
|
@ -18,7 +18,6 @@
|
|||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
#include <xtrabackup.h>
|
#include <xtrabackup.h>
|
||||||
#include <encryption_plugin.h>
|
#include <encryption_plugin.h>
|
||||||
#include <backup_copy.h>
|
|
||||||
#include <sql_plugin.h>
|
#include <sql_plugin.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "read_filt.h"
|
#include "read_filt.h"
|
||||||
#include "xtrabackup.h"
|
#include "xtrabackup.h"
|
||||||
|
#include "backup_debug.h"
|
||||||
|
|
||||||
/* Size of read buffer in pages (640 pages = 10M for 16K sized pages) */
|
/* Size of read buffer in pages (640 pages = 10M for 16K sized pages) */
|
||||||
#define XB_FIL_CUR_PAGES 640
|
#define XB_FIL_CUR_PAGES 640
|
||||||
@ -351,19 +352,18 @@ static bool page_is_corrupted(const byte *page, ulint page_no,
|
|||||||
return buf_page_is_corrupted(true, page, space->flags);
|
return buf_page_is_corrupted(true, page, space->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/** Reads and verifies the next block of pages from the source
|
||||||
Reads and verifies the next block of pages from the source
|
|
||||||
file. Positions the cursor after the last read non-corrupted page.
|
file. Positions the cursor after the last read non-corrupted page.
|
||||||
|
@param[in,out] cursor source file cursor
|
||||||
|
@param[out] corrupted_pages adds corrupted pages if
|
||||||
|
opt_log_innodb_page_corruption is set
|
||||||
@return XB_FIL_CUR_SUCCESS if some have been read successfully, XB_FIL_CUR_EOF
|
@return XB_FIL_CUR_SUCCESS if some have been read successfully, XB_FIL_CUR_EOF
|
||||||
if there are no more pages to read and XB_FIL_CUR_ERROR on error. */
|
if there are no more pages to read and XB_FIL_CUR_ERROR on error. */
|
||||||
xb_fil_cur_result_t
|
xb_fil_cur_result_t xb_fil_cur_read(xb_fil_cur_t* cursor,
|
||||||
xb_fil_cur_read(
|
CorruptedPages &corrupted_pages)
|
||||||
/*============*/
|
|
||||||
xb_fil_cur_t* cursor) /*!< in/out: source file cursor */
|
|
||||||
{
|
{
|
||||||
byte* page;
|
byte* page;
|
||||||
ulint i;
|
unsigned i;
|
||||||
ulint npages;
|
ulint npages;
|
||||||
ulint retry_count;
|
ulint retry_count;
|
||||||
xb_fil_cur_result_t ret;
|
xb_fil_cur_result_t ret;
|
||||||
@ -417,7 +417,7 @@ read_retry:
|
|||||||
cursor->buf_read = 0;
|
cursor->buf_read = 0;
|
||||||
cursor->buf_npages = 0;
|
cursor->buf_npages = 0;
|
||||||
cursor->buf_offset = offset;
|
cursor->buf_offset = offset;
|
||||||
cursor->buf_page_no = (ulint)(offset / page_size);
|
cursor->buf_page_no = static_cast<unsigned>(offset / page_size);
|
||||||
|
|
||||||
if (os_file_read(IORequestRead, cursor->file, cursor->buf, offset,
|
if (os_file_read(IORequestRead, cursor->file, cursor->buf, offset,
|
||||||
(ulint) to_read) != DB_SUCCESS) {
|
(ulint) to_read) != DB_SUCCESS) {
|
||||||
@ -428,26 +428,47 @@ read_retry:
|
|||||||
partially written pages */
|
partially written pages */
|
||||||
for (page = cursor->buf, i = 0; i < npages;
|
for (page = cursor->buf, i = 0; i < npages;
|
||||||
page += page_size, i++) {
|
page += page_size, i++) {
|
||||||
ulint page_no = cursor->buf_page_no + i;
|
unsigned page_no = cursor->buf_page_no + i;
|
||||||
|
|
||||||
if (page_is_corrupted(page, page_no, cursor, space)){
|
if (page_is_corrupted(page, page_no, cursor, space)){
|
||||||
retry_count--;
|
retry_count--;
|
||||||
|
|
||||||
if (retry_count == 0) {
|
if (retry_count == 0) {
|
||||||
|
const char *ignore_corruption_warn = opt_log_innodb_page_corruption ?
|
||||||
|
" WARNING!!! The corruption is ignored due to"
|
||||||
|
" log-innodb-page-corruption option, the backup can contain"
|
||||||
|
" corrupted data." : "";
|
||||||
msg(cursor->thread_n,
|
msg(cursor->thread_n,
|
||||||
"Error: failed to read page after "
|
"Error: failed to read page after "
|
||||||
"10 retries. File %s seems to be "
|
"10 retries. File %s seems to be "
|
||||||
"corrupted.", cursor->abs_path);
|
"corrupted.%s", cursor->abs_path, ignore_corruption_warn);
|
||||||
ret = XB_FIL_CUR_ERROR;
|
|
||||||
ut_print_buf(stderr, page, page_size);
|
ut_print_buf(stderr, page, page_size);
|
||||||
break;
|
if (opt_log_innodb_page_corruption) {
|
||||||
|
corrupted_pages.add_page(cursor->node->name, cursor->node->space->id,
|
||||||
|
page_no);
|
||||||
|
retry_count = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = XB_FIL_CUR_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msg(cursor->thread_n, "Database page corruption detected at page "
|
||||||
|
UINT32PF ", retrying...",
|
||||||
|
page_no);
|
||||||
|
os_thread_sleep(100000);
|
||||||
|
goto read_retry;
|
||||||
}
|
}
|
||||||
msg(cursor->thread_n, "Database page corruption detected at page "
|
|
||||||
ULINTPF ", retrying...",
|
|
||||||
page_no);
|
|
||||||
os_thread_sleep(100000);
|
|
||||||
goto read_retry;
|
|
||||||
}
|
}
|
||||||
|
DBUG_EXECUTE_FOR_KEY("add_corrupted_page_for", cursor->node->space->name,
|
||||||
|
{
|
||||||
|
unsigned corrupted_page_no =
|
||||||
|
static_cast<unsigned>(strtoul(dbug_val, NULL, 10));
|
||||||
|
if (page_no == corrupted_page_no)
|
||||||
|
corrupted_pages.add_page(cursor->node->name, cursor->node->space->id,
|
||||||
|
corrupted_page_no);
|
||||||
|
});
|
||||||
cursor->buf_read += page_size;
|
cursor->buf_read += page_size;
|
||||||
cursor->buf_npages++;
|
cursor->buf_npages++;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
|||||||
#include "read_filt.h"
|
#include "read_filt.h"
|
||||||
#include "srv0start.h"
|
#include "srv0start.h"
|
||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
|
#include "xtrabackup.h"
|
||||||
|
|
||||||
struct xb_fil_cur_t {
|
struct xb_fil_cur_t {
|
||||||
pfs_os_file_t file; /*!< source file handle */
|
pfs_os_file_t file; /*!< source file handle */
|
||||||
@ -52,7 +53,7 @@ struct xb_fil_cur_t {
|
|||||||
last cursor read */
|
last cursor read */
|
||||||
ib_int64_t buf_offset; /*!< file offset of the first page in
|
ib_int64_t buf_offset; /*!< file offset of the first page in
|
||||||
buffer */
|
buffer */
|
||||||
ulint buf_page_no; /*!< number of the first page in
|
unsigned buf_page_no; /*!< number of the first page in
|
||||||
buffer */
|
buffer */
|
||||||
uint thread_n; /*!< thread number for diagnostics */
|
uint thread_n; /*!< thread number for diagnostics */
|
||||||
ulint space_id; /*!< ID of tablespace */
|
ulint space_id; /*!< ID of tablespace */
|
||||||
@ -88,17 +89,15 @@ xb_fil_cur_open(
|
|||||||
uint thread_n, /*!< thread number for diagnostics */
|
uint thread_n, /*!< thread number for diagnostics */
|
||||||
ulonglong max_file_size = ULLONG_MAX);
|
ulonglong max_file_size = ULLONG_MAX);
|
||||||
|
|
||||||
/************************************************************************
|
/** Reads and verifies the next block of pages from the source
|
||||||
Reads and verifies the next block of pages from the source
|
|
||||||
file. Positions the cursor after the last read non-corrupted page.
|
file. Positions the cursor after the last read non-corrupted page.
|
||||||
|
@param[in,out] cursor source file cursor
|
||||||
|
@param[out] corrupted_pages adds corrupted pages if
|
||||||
|
opt_log_innodb_page_corruption is set
|
||||||
@return XB_FIL_CUR_SUCCESS if some have been read successfully, XB_FIL_CUR_EOF
|
@return XB_FIL_CUR_SUCCESS if some have been read successfully, XB_FIL_CUR_EOF
|
||||||
if there are no more pages to read and XB_FIL_CUR_ERROR on error. */
|
if there are no more pages to read and XB_FIL_CUR_ERROR on error. */
|
||||||
xb_fil_cur_result_t
|
xb_fil_cur_result_t xb_fil_cur_read(xb_fil_cur_t *cursor,
|
||||||
xb_fil_cur_read(
|
CorruptedPages &corrupted_pages);
|
||||||
/*============*/
|
|
||||||
xb_fil_cur_t* cursor); /*!< in/out: source file cursor */
|
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
Close the source file cursor opened with xb_fil_cur_open() and its
|
Close the source file cursor opened with xb_fil_cur_open() and its
|
||||||
associated read filter. */
|
associated read filter. */
|
||||||
|
@ -32,7 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
|||||||
/************************************************************************
|
/************************************************************************
|
||||||
Write-through page write filter. */
|
Write-through page write filter. */
|
||||||
static my_bool wf_wt_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
static my_bool wf_wt_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
||||||
xb_fil_cur_t *cursor);
|
xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages);
|
||||||
static my_bool wf_wt_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile);
|
static my_bool wf_wt_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile);
|
||||||
|
|
||||||
xb_write_filt_t wf_write_through = {
|
xb_write_filt_t wf_write_through = {
|
||||||
@ -45,7 +45,7 @@ xb_write_filt_t wf_write_through = {
|
|||||||
/************************************************************************
|
/************************************************************************
|
||||||
Incremental page write filter. */
|
Incremental page write filter. */
|
||||||
static my_bool wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
static my_bool wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
||||||
xb_fil_cur_t *cursor);
|
xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages);
|
||||||
static my_bool wf_incremental_process(xb_write_filt_ctxt_t *ctxt,
|
static my_bool wf_incremental_process(xb_write_filt_ctxt_t *ctxt,
|
||||||
ds_file_t *dstfile);
|
ds_file_t *dstfile);
|
||||||
static my_bool wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt,
|
static my_bool wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt,
|
||||||
@ -65,11 +65,11 @@ Initialize incremental page write filter.
|
|||||||
@return TRUE on success, FALSE on error. */
|
@return TRUE on success, FALSE on error. */
|
||||||
static my_bool
|
static my_bool
|
||||||
wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
||||||
xb_fil_cur_t *cursor)
|
xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages)
|
||||||
{
|
{
|
||||||
char meta_name[FN_REFLEN];
|
char meta_name[FN_REFLEN];
|
||||||
xb_wf_incremental_ctxt_t *cp =
|
xb_wf_incremental_ctxt_t *cp =
|
||||||
&(ctxt->u.wf_incremental_ctxt);
|
&(ctxt->wf_incremental_ctxt);
|
||||||
|
|
||||||
ctxt->cursor = cursor;
|
ctxt->cursor = cursor;
|
||||||
|
|
||||||
@ -100,7 +100,9 @@ wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
|||||||
strcat(dst_name, ".delta");
|
strcat(dst_name, ".delta");
|
||||||
|
|
||||||
mach_write_to_4(cp->delta_buf, 0x78747261UL); /*"xtra"*/
|
mach_write_to_4(cp->delta_buf, 0x78747261UL); /*"xtra"*/
|
||||||
|
|
||||||
cp->npages = 1;
|
cp->npages = 1;
|
||||||
|
cp->corrupted_pages = corrupted_pages;
|
||||||
|
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
}
|
}
|
||||||
@ -112,19 +114,20 @@ Run the next batch of pages through incremental page write filter.
|
|||||||
static my_bool
|
static my_bool
|
||||||
wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
|
wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
|
||||||
{
|
{
|
||||||
ulint i;
|
unsigned i;
|
||||||
xb_fil_cur_t *cursor = ctxt->cursor;
|
xb_fil_cur_t *cursor = ctxt->cursor;
|
||||||
byte *page;
|
byte *page;
|
||||||
const ulint page_size = cursor->page_size;
|
const ulint page_size = cursor->page_size;
|
||||||
xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt);
|
xb_wf_incremental_ctxt_t *cp = &(ctxt->wf_incremental_ctxt);
|
||||||
|
|
||||||
for (i = 0, page = cursor->buf; i < cursor->buf_npages;
|
for (i = 0, page = cursor->buf; i < cursor->buf_npages;
|
||||||
i++, page += page_size) {
|
i++, page += page_size) {
|
||||||
|
|
||||||
if (incremental_lsn >= mach_read_from_8(page + FIL_PAGE_LSN)) {
|
if ((!cp->corrupted_pages ||
|
||||||
|
!cp->corrupted_pages->contains(cursor->node->space->id,
|
||||||
|
cursor->buf_page_no + i)) &&
|
||||||
|
incremental_lsn >= mach_read_from_8(page + FIL_PAGE_LSN))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
/* updated page */
|
/* updated page */
|
||||||
if (cp->npages == page_size / 4) {
|
if (cp->npages == page_size / 4) {
|
||||||
@ -161,7 +164,7 @@ wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
|
|||||||
{
|
{
|
||||||
xb_fil_cur_t *cursor = ctxt->cursor;
|
xb_fil_cur_t *cursor = ctxt->cursor;
|
||||||
const ulint page_size = cursor->page_size;
|
const ulint page_size = cursor->page_size;
|
||||||
xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt);
|
xb_wf_incremental_ctxt_t *cp = &(ctxt->wf_incremental_ctxt);
|
||||||
|
|
||||||
if (cp->npages != page_size / 4) {
|
if (cp->npages != page_size / 4) {
|
||||||
mach_write_to_4(cp->delta_buf + cp->npages * 4, 0xFFFFFFFFUL);
|
mach_write_to_4(cp->delta_buf + cp->npages * 4, 0xFFFFFFFFUL);
|
||||||
@ -183,7 +186,7 @@ Free the incremental page write filter's buffer. */
|
|||||||
static void
|
static void
|
||||||
wf_incremental_deinit(xb_write_filt_ctxt_t *ctxt)
|
wf_incremental_deinit(xb_write_filt_ctxt_t *ctxt)
|
||||||
{
|
{
|
||||||
xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt);
|
xb_wf_incremental_ctxt_t *cp = &(ctxt->wf_incremental_ctxt);
|
||||||
my_large_free(cp->delta_buf, cp->delta_buf_size);
|
my_large_free(cp->delta_buf, cp->delta_buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +196,7 @@ Initialize the write-through page write filter.
|
|||||||
@return TRUE on success, FALSE on error. */
|
@return TRUE on success, FALSE on error. */
|
||||||
static my_bool
|
static my_bool
|
||||||
wf_wt_init(xb_write_filt_ctxt_t *ctxt, char *dst_name __attribute__((unused)),
|
wf_wt_init(xb_write_filt_ctxt_t *ctxt, char *dst_name __attribute__((unused)),
|
||||||
xb_fil_cur_t *cursor)
|
xb_fil_cur_t *cursor, CorruptedPages *)
|
||||||
{
|
{
|
||||||
ctxt->cursor = cursor;
|
ctxt->cursor = cursor;
|
||||||
|
|
||||||
|
@ -27,26 +27,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
|||||||
|
|
||||||
#include "fil_cur.h"
|
#include "fil_cur.h"
|
||||||
#include "datasink.h"
|
#include "datasink.h"
|
||||||
|
#include "xtrabackup.h"
|
||||||
|
|
||||||
/* Incremental page filter context */
|
/* Incremental page filter context */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ulint delta_buf_size;
|
ulint delta_buf_size;
|
||||||
byte *delta_buf;
|
byte *delta_buf;
|
||||||
ulint npages;
|
ulint npages;
|
||||||
|
CorruptedPages *corrupted_pages;
|
||||||
} xb_wf_incremental_ctxt_t;
|
} xb_wf_incremental_ctxt_t;
|
||||||
|
|
||||||
/* Page filter context used as an opaque structure by callers */
|
/* Page filter context used as an opaque structure by callers */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
xb_fil_cur_t *cursor;
|
xb_fil_cur_t *cursor;
|
||||||
union {
|
xb_wf_incremental_ctxt_t wf_incremental_ctxt;
|
||||||
xb_wf_incremental_ctxt_t wf_incremental_ctxt;
|
|
||||||
} u;
|
|
||||||
} xb_write_filt_ctxt_t;
|
} xb_write_filt_ctxt_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
my_bool (*init)(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
my_bool (*init)(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
||||||
xb_fil_cur_t *cursor);
|
xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages);
|
||||||
my_bool (*process)(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile);
|
my_bool (*process)(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile);
|
||||||
my_bool (*finalize)(xb_write_filt_ctxt_t *, ds_file_t *dstfile);
|
my_bool (*finalize)(xb_write_filt_ctxt_t *, ds_file_t *dstfile);
|
||||||
void (*deinit)(xb_write_filt_ctxt_t *);
|
void (*deinit)(xb_write_filt_ctxt_t *);
|
||||||
|
@ -77,6 +77,7 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <fstream>
|
||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
|
|
||||||
#define G_PTR uchar*
|
#define G_PTR uchar*
|
||||||
@ -104,6 +105,9 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA
|
|||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <derror.h>
|
#include <derror.h>
|
||||||
#include <thr_timer.h>
|
#include <thr_timer.h>
|
||||||
|
#include "backup_debug.h"
|
||||||
|
|
||||||
|
#define MB_CORRUPTED_PAGES_FILE "innodb_corrupted_pages"
|
||||||
|
|
||||||
int sys_var_init();
|
int sys_var_init();
|
||||||
|
|
||||||
@ -287,6 +291,7 @@ my_bool opt_noversioncheck = FALSE;
|
|||||||
my_bool opt_no_backup_locks = FALSE;
|
my_bool opt_no_backup_locks = FALSE;
|
||||||
my_bool opt_decompress = FALSE;
|
my_bool opt_decompress = FALSE;
|
||||||
my_bool opt_remove_original;
|
my_bool opt_remove_original;
|
||||||
|
my_bool opt_log_innodb_page_corruption;
|
||||||
|
|
||||||
my_bool opt_lock_ddl_per_table = FALSE;
|
my_bool opt_lock_ddl_per_table = FALSE;
|
||||||
static my_bool opt_check_privileges;
|
static my_bool opt_check_privileges;
|
||||||
@ -349,6 +354,212 @@ struct ddl_tracker_t {
|
|||||||
|
|
||||||
static ddl_tracker_t ddl_tracker;
|
static ddl_tracker_t ddl_tracker;
|
||||||
|
|
||||||
|
// Convert non-null terminated filename to space name
|
||||||
|
std::string filename_to_spacename(const byte *filename, size_t len);
|
||||||
|
|
||||||
|
CorruptedPages::CorruptedPages() { ut_a(!pthread_mutex_init(&m_mutex, NULL)); }
|
||||||
|
|
||||||
|
CorruptedPages::~CorruptedPages() { ut_a(!pthread_mutex_destroy(&m_mutex)); }
|
||||||
|
|
||||||
|
void CorruptedPages::add_page_no_lock(const char *space_name, ulint space_id,
|
||||||
|
unsigned page_no,
|
||||||
|
bool convert_space_name)
|
||||||
|
{
|
||||||
|
space_info_t &space_info = m_spaces[space_id];
|
||||||
|
if (space_info.space_name.empty())
|
||||||
|
space_info.space_name=
|
||||||
|
convert_space_name
|
||||||
|
? filename_to_spacename(reinterpret_cast<const byte *>(space_name),
|
||||||
|
strlen(space_name))
|
||||||
|
: space_name;
|
||||||
|
(void)space_info.pages.insert(page_no);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CorruptedPages::add_page(const char *file_name, ulint space_id,
|
||||||
|
unsigned page_no)
|
||||||
|
{
|
||||||
|
ut_a(!pthread_mutex_lock(&m_mutex));
|
||||||
|
add_page_no_lock(file_name, space_id, page_no, true);
|
||||||
|
ut_a(!pthread_mutex_unlock(&m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CorruptedPages::contains(ulint space_id, unsigned page_no) const
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
ut_a(!pthread_mutex_lock(&m_mutex));
|
||||||
|
container_t::const_iterator space_it= m_spaces.find(space_id);
|
||||||
|
if (space_it != m_spaces.end())
|
||||||
|
result = space_it->second.pages.count(page_no);
|
||||||
|
ut_a(!pthread_mutex_unlock(&m_mutex));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CorruptedPages::drop_space(ulint space_id)
|
||||||
|
{
|
||||||
|
ut_a(!pthread_mutex_lock(&m_mutex));
|
||||||
|
m_spaces.erase(space_id);
|
||||||
|
ut_a(!pthread_mutex_unlock(&m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CorruptedPages::rename_space(ulint space_id, const std::string &new_name)
|
||||||
|
{
|
||||||
|
ut_a(!pthread_mutex_lock(&m_mutex));
|
||||||
|
container_t::iterator space_it = m_spaces.find(space_id);
|
||||||
|
if (space_it != m_spaces.end())
|
||||||
|
space_it->second.space_name = new_name;
|
||||||
|
ut_a(!pthread_mutex_unlock(&m_mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CorruptedPages::print_to_file(const char *filename) const
|
||||||
|
{
|
||||||
|
std::ostringstream out;
|
||||||
|
ut_a(!pthread_mutex_lock(&m_mutex));
|
||||||
|
if (!m_spaces.size())
|
||||||
|
{
|
||||||
|
ut_a(!pthread_mutex_unlock(&m_mutex));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (container_t::const_iterator space_it=
|
||||||
|
m_spaces.begin();
|
||||||
|
space_it != m_spaces.end(); ++space_it)
|
||||||
|
{
|
||||||
|
out << space_it->second.space_name << " " << space_it->first << "\n";
|
||||||
|
bool first_page_no= true;
|
||||||
|
for (std::set<unsigned>::const_iterator page_it=
|
||||||
|
space_it->second.pages.begin();
|
||||||
|
page_it != space_it->second.pages.end(); ++page_it)
|
||||||
|
if (first_page_no)
|
||||||
|
{
|
||||||
|
out << *page_it;
|
||||||
|
first_page_no= false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out << " " << *page_it;
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
ut_a(!pthread_mutex_unlock(&m_mutex));
|
||||||
|
if (xtrabackup_backup)
|
||||||
|
return backup_file_print_buf(filename, out.str().c_str(),
|
||||||
|
static_cast<int>(out.str().size()));
|
||||||
|
std::ofstream outfile;
|
||||||
|
outfile.open(filename);
|
||||||
|
if (!outfile.is_open())
|
||||||
|
die("Can't open %s, error number: %d, error message: %s", filename, errno,
|
||||||
|
strerror(errno));
|
||||||
|
outfile << out.str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CorruptedPages::read_from_file(const char *file_name)
|
||||||
|
{
|
||||||
|
MY_STAT mystat;
|
||||||
|
if (!my_stat(file_name, &mystat, MYF(0)))
|
||||||
|
return;
|
||||||
|
std::ifstream infile;
|
||||||
|
infile.open(file_name);
|
||||||
|
if (!infile.is_open())
|
||||||
|
die("Can't open %s, error number: %d, error message: %s", file_name, errno,
|
||||||
|
strerror(errno));
|
||||||
|
std::string line;
|
||||||
|
std::string space_name;
|
||||||
|
ulint space_id;
|
||||||
|
ulint line_number= 0;
|
||||||
|
while (std::getline(infile, line))
|
||||||
|
{
|
||||||
|
++line_number;
|
||||||
|
std::istringstream iss(line);
|
||||||
|
if (line_number & 1) {
|
||||||
|
if (!(iss >> space_name))
|
||||||
|
die("Can't parse space name from corrupted pages file at "
|
||||||
|
"line " ULINTPF,
|
||||||
|
line_number);
|
||||||
|
if (!(iss >> space_id))
|
||||||
|
die("Can't parse space id from corrupted pages file at line " ULINTPF,
|
||||||
|
line_number);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::istringstream iss(line);
|
||||||
|
unsigned page_no;
|
||||||
|
while ((iss >> page_no))
|
||||||
|
add_page_no_lock(space_name.c_str(), space_id, page_no, false);
|
||||||
|
if (!iss.eof())
|
||||||
|
die("Corrupted pages file parse error on line number " ULINTPF,
|
||||||
|
line_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CorruptedPages::empty() const
|
||||||
|
{
|
||||||
|
ut_a(!pthread_mutex_lock(&m_mutex));
|
||||||
|
bool result= !m_spaces.size();
|
||||||
|
ut_a(!pthread_mutex_unlock(&m_mutex));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xb_load_single_table_tablespace(const std::string &space_name,
|
||||||
|
bool set_size);
|
||||||
|
static void xb_data_files_close();
|
||||||
|
static fil_space_t* fil_space_get_by_name(const char* name);
|
||||||
|
|
||||||
|
void CorruptedPages::zero_out_free_pages()
|
||||||
|
{
|
||||||
|
container_t non_free_pages;
|
||||||
|
byte *zero_page=
|
||||||
|
static_cast<byte *>(aligned_malloc(srv_page_size, srv_page_size));
|
||||||
|
memset(zero_page, 0, srv_page_size);
|
||||||
|
|
||||||
|
ut_a(!pthread_mutex_lock(&m_mutex));
|
||||||
|
for (container_t::const_iterator space_it= m_spaces.begin();
|
||||||
|
space_it != m_spaces.end(); ++space_it)
|
||||||
|
{
|
||||||
|
ulint space_id = space_it->first;
|
||||||
|
const std::string &space_name = space_it->second.space_name;
|
||||||
|
// There is no need to close tablespaces explixitly as they will be closed
|
||||||
|
// in innodb_shutdown().
|
||||||
|
xb_load_single_table_tablespace(space_name, false);
|
||||||
|
fil_space_t *space = fil_space_t::get(space_id);
|
||||||
|
if (!space)
|
||||||
|
die("Can't find space object for space name %s to check corrupted page",
|
||||||
|
space_name.c_str());
|
||||||
|
for (std::set<unsigned>::const_iterator page_it=
|
||||||
|
space_it->second.pages.begin();
|
||||||
|
page_it != space_it->second.pages.end(); ++page_it)
|
||||||
|
{
|
||||||
|
bool is_free= fseg_page_is_free(space, *page_it);
|
||||||
|
if (!is_free) {
|
||||||
|
space_info_t &space_info = non_free_pages[space_id];
|
||||||
|
space_info.pages.insert(*page_it);
|
||||||
|
if (space_info.space_name.empty())
|
||||||
|
space_info.space_name = space_name;
|
||||||
|
msg("Error: corrupted page " UINT32PF
|
||||||
|
" of tablespace %s can not be fixed",
|
||||||
|
*page_it, space_name.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
space->reacquire();
|
||||||
|
auto err= space
|
||||||
|
->io(IORequest(IORequest::PUNCH_RANGE),
|
||||||
|
*page_it * srv_page_size, srv_page_size, zero_page)
|
||||||
|
.err;
|
||||||
|
if (err != DB_SUCCESS)
|
||||||
|
die("Can't zero out corrupted page " UINT32PF " of tablespace %s",
|
||||||
|
*page_it, space_name.c_str());
|
||||||
|
msg("Corrupted page " UINT32PF
|
||||||
|
" of tablespace %s was successfuly fixed.",
|
||||||
|
*page_it, space_name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
space->flush();
|
||||||
|
space->release();
|
||||||
|
}
|
||||||
|
m_spaces.swap(non_free_pages);
|
||||||
|
ut_a(!pthread_mutex_unlock(&m_mutex));
|
||||||
|
aligned_free(zero_page);
|
||||||
|
}
|
||||||
|
|
||||||
/* Simple datasink creation tracking...add datasinks in the reverse order you
|
/* Simple datasink creation tracking...add datasinks in the reverse order you
|
||||||
want them destroyed. */
|
want them destroyed. */
|
||||||
#define XTRABACKUP_MAX_DATASINKS 10
|
#define XTRABACKUP_MAX_DATASINKS 10
|
||||||
@ -362,11 +573,12 @@ xtrabackup_add_datasink(ds_ctxt_t *ds)
|
|||||||
datasinks[actual_datasinks] = ds; actual_datasinks++;
|
datasinks[actual_datasinks] = ds; actual_datasinks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef void (*process_single_tablespace_func_t)(const char *dirname,
|
||||||
typedef void (*process_single_tablespace_func_t)(const char *dirname, const char *filname, bool is_remote);
|
const char *filname,
|
||||||
|
bool is_remote,
|
||||||
|
bool skip_node_page0);
|
||||||
static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback);
|
static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback);
|
||||||
|
|
||||||
|
|
||||||
/* ======== Datafiles iterator ======== */
|
/* ======== Datafiles iterator ======== */
|
||||||
struct datafiles_iter_t {
|
struct datafiles_iter_t {
|
||||||
fil_space_t *space;
|
fil_space_t *space;
|
||||||
@ -690,6 +902,7 @@ typedef struct {
|
|||||||
uint *count;
|
uint *count;
|
||||||
pthread_mutex_t* count_mutex;
|
pthread_mutex_t* count_mutex;
|
||||||
os_thread_id_t id;
|
os_thread_id_t id;
|
||||||
|
CorruptedPages *corrupted_pages;
|
||||||
} data_thread_ctxt_t;
|
} data_thread_ctxt_t;
|
||||||
|
|
||||||
/* ======== for option and variables ======== */
|
/* ======== for option and variables ======== */
|
||||||
@ -791,7 +1004,8 @@ enum options_xtrabackup
|
|||||||
OPT_ROCKSDB_DATADIR,
|
OPT_ROCKSDB_DATADIR,
|
||||||
OPT_BACKUP_ROCKSDB,
|
OPT_BACKUP_ROCKSDB,
|
||||||
OPT_XTRA_CHECK_PRIVILEGES,
|
OPT_XTRA_CHECK_PRIVILEGES,
|
||||||
OPT_XTRA_MYSQLD_ARGS
|
OPT_XTRA_MYSQLD_ARGS,
|
||||||
|
OPT_XB_IGNORE_INNODB_PAGE_CORRUPTION
|
||||||
};
|
};
|
||||||
|
|
||||||
struct my_option xb_client_options[]= {
|
struct my_option xb_client_options[]= {
|
||||||
@ -1182,6 +1396,17 @@ struct my_option xb_client_options[]= {
|
|||||||
" uses old (pre-4.1.1) protocol.",
|
" uses old (pre-4.1.1) protocol.",
|
||||||
&opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
|
&opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
|
||||||
0},
|
0},
|
||||||
|
|
||||||
|
{"log-innodb-page-corruption", OPT_XB_IGNORE_INNODB_PAGE_CORRUPTION,
|
||||||
|
"Continue backup if innodb corrupted pages are found. The pages are "
|
||||||
|
"logged in " MB_CORRUPTED_PAGES_FILE
|
||||||
|
" and backup is finished with error. "
|
||||||
|
"--prepare will try to fix corrupted pages. If " MB_CORRUPTED_PAGES_FILE
|
||||||
|
" exists after --prepare in base backup directory, backup still contains "
|
||||||
|
"corrupted pages and can not be considered as consistent.",
|
||||||
|
&opt_log_innodb_page_corruption, &opt_log_innodb_page_corruption, 0,
|
||||||
|
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||||
|
|
||||||
#define MYSQL_CLIENT
|
#define MYSQL_CLIENT
|
||||||
#include "sslopt-longopts.h"
|
#include "sslopt-longopts.h"
|
||||||
#undef MYSQL_CLIENT
|
#undef MYSQL_CLIENT
|
||||||
@ -1474,7 +1699,8 @@ debug_sync_point(const char *name)
|
|||||||
|
|
||||||
static std::set<std::string> tables_for_export;
|
static std::set<std::string> tables_for_export;
|
||||||
|
|
||||||
static void append_export_table(const char *dbname, const char *tablename, bool is_remote)
|
static void append_export_table(const char *dbname, const char *tablename,
|
||||||
|
bool is_remote, bool skip_node_page0)
|
||||||
{
|
{
|
||||||
if(dbname && tablename && !is_remote)
|
if(dbname && tablename && !is_remote)
|
||||||
{
|
{
|
||||||
@ -2473,7 +2699,8 @@ for full backup, pages filter for incremental backup, etc.
|
|||||||
@return FALSE on success and TRUE on error */
|
@return FALSE on success and TRUE on error */
|
||||||
static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n,
|
static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n,
|
||||||
const char *dest_name,
|
const char *dest_name,
|
||||||
const xb_write_filt_t &write_filter)
|
const xb_write_filt_t &write_filter,
|
||||||
|
CorruptedPages &corrupted_pages)
|
||||||
{
|
{
|
||||||
char dst_name[FN_REFLEN];
|
char dst_name[FN_REFLEN];
|
||||||
ds_file_t *dstfile = NULL;
|
ds_file_t *dstfile = NULL;
|
||||||
@ -2538,7 +2765,8 @@ static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n,
|
|||||||
ut_a(write_filter.process != NULL);
|
ut_a(write_filter.process != NULL);
|
||||||
|
|
||||||
if (write_filter.init != NULL &&
|
if (write_filter.init != NULL &&
|
||||||
!write_filter.init(&write_filt_ctxt, dst_name, &cursor)) {
|
!write_filter.init(&write_filt_ctxt, dst_name, &cursor,
|
||||||
|
opt_log_innodb_page_corruption ? &corrupted_pages : NULL)) {
|
||||||
msg (thread_n, "mariabackup: error: failed to initialize page write filter.");
|
msg (thread_n, "mariabackup: error: failed to initialize page write filter.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -2558,7 +2786,8 @@ static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* The main copy loop */
|
/* The main copy loop */
|
||||||
while ((res = xb_fil_cur_read(&cursor)) == XB_FIL_CUR_SUCCESS) {
|
while ((res = xb_fil_cur_read(&cursor, corrupted_pages)) ==
|
||||||
|
XB_FIL_CUR_SUCCESS) {
|
||||||
if (!write_filter.process(&write_filt_ctxt, dstfile)) {
|
if (!write_filter.process(&write_filt_ctxt, dstfile)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -2836,6 +3065,21 @@ static os_thread_ret_t DECLARE_THREAD(io_watching_thread)(void*)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
|
char *dbug_mariabackup_get_val(const char *event, const char *key)
|
||||||
|
{
|
||||||
|
char envvar[FN_REFLEN];
|
||||||
|
if (key) {
|
||||||
|
snprintf(envvar, sizeof(envvar), "%s_%s", event, key);
|
||||||
|
char *slash = strchr(envvar, '/');
|
||||||
|
if (slash)
|
||||||
|
*slash = '_';
|
||||||
|
} else {
|
||||||
|
strncpy(envvar, event, sizeof envvar - 1);
|
||||||
|
envvar[sizeof envvar - 1] = '\0';
|
||||||
|
}
|
||||||
|
return getenv(envvar);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
In debug mode, execute SQL statement that was passed via environment.
|
In debug mode, execute SQL statement that was passed via environment.
|
||||||
To use this facility, you need to
|
To use this facility, you need to
|
||||||
@ -2848,35 +3092,15 @@ To use this facility, you need to
|
|||||||
for the variable)
|
for the variable)
|
||||||
3. start mariabackup with --dbug=+d,debug_mariabackup_events
|
3. start mariabackup with --dbug=+d,debug_mariabackup_events
|
||||||
*/
|
*/
|
||||||
static void dbug_mariabackup_event(const char *event,const char *key)
|
void dbug_mariabackup_event(const char *event,const char *key)
|
||||||
{
|
{
|
||||||
char envvar[FN_REFLEN];
|
char *sql = dbug_mariabackup_get_val(event, key);
|
||||||
if (key) {
|
if (sql && *sql) {
|
||||||
snprintf(envvar, sizeof(envvar), "%s_%s", event, key);
|
|
||||||
char *slash = strchr(envvar, '/');
|
|
||||||
if (slash)
|
|
||||||
*slash = '_';
|
|
||||||
} else {
|
|
||||||
strncpy(envvar, event, sizeof envvar - 1);
|
|
||||||
envvar[sizeof envvar - 1] = '\0';
|
|
||||||
}
|
|
||||||
char *sql = getenv(envvar);
|
|
||||||
if (sql) {
|
|
||||||
msg("dbug_mariabackup_event : executing '%s'", sql);
|
msg("dbug_mariabackup_event : executing '%s'", sql);
|
||||||
xb_mysql_query(mysql_connection, sql, false, true);
|
xb_mysql_query(mysql_connection, sql, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#define DBUG_MARIABACKUP_EVENT(A, B) DBUG_EXECUTE_IF("mariabackup_events", dbug_mariabackup_event(A,B););
|
#endif // DBUG_OFF
|
||||||
#define DBUG_MB_INJECT_CODE(EVENT, KEY, CODE) \
|
|
||||||
DBUG_EXECUTE_IF("mariabackup_inject_code", {\
|
|
||||||
char *env = getenv(EVENT); \
|
|
||||||
if (env && !strcmp(env, KEY)) { CODE } \
|
|
||||||
})
|
|
||||||
#else
|
|
||||||
#define DBUG_MARIABACKUP_EVENT(A,B)
|
|
||||||
#define DBUG_MB_INJECT_CODE(EVENT, KEY, CODE)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
Datafiles copying thread.*/
|
Datafiles copying thread.*/
|
||||||
@ -2889,6 +3113,7 @@ DECLARE_THREAD(data_copy_thread_func)(
|
|||||||
data_thread_ctxt_t *ctxt = (data_thread_ctxt_t *) arg;
|
data_thread_ctxt_t *ctxt = (data_thread_ctxt_t *) arg;
|
||||||
uint num = ctxt->num;
|
uint num = ctxt->num;
|
||||||
fil_node_t* node;
|
fil_node_t* node;
|
||||||
|
ut_ad(ctxt->corrupted_pages);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialize mysys thread-specific memory so we can
|
Initialize mysys thread-specific memory so we can
|
||||||
@ -2900,11 +3125,12 @@ DECLARE_THREAD(data_copy_thread_func)(
|
|||||||
|
|
||||||
while ((node = datafiles_iter_next(ctxt->it)) != NULL) {
|
while ((node = datafiles_iter_next(ctxt->it)) != NULL) {
|
||||||
DBUG_MARIABACKUP_EVENT("before_copy", node->space->name);
|
DBUG_MARIABACKUP_EVENT("before_copy", node->space->name);
|
||||||
DBUG_MB_INJECT_CODE("wait_innodb_redo_before_copy", node->space->name,
|
DBUG_EXECUTE_FOR_KEY("wait_innodb_redo_before_copy", node->space->name,
|
||||||
backup_wait_for_lsn(get_current_lsn(mysql_connection)););
|
backup_wait_for_lsn(get_current_lsn(mysql_connection)););
|
||||||
/* copy the datafile */
|
/* copy the datafile */
|
||||||
if (xtrabackup_copy_datafile(node, num, NULL,
|
if (xtrabackup_copy_datafile(node, num, NULL,
|
||||||
xtrabackup_incremental ? wf_incremental : wf_write_through))
|
xtrabackup_incremental ? wf_incremental : wf_write_through,
|
||||||
|
*ctxt->corrupted_pages))
|
||||||
die("failed to copy datafile.");
|
die("failed to copy datafile.");
|
||||||
|
|
||||||
DBUG_MARIABACKUP_EVENT("after_copy", node->space->name);
|
DBUG_MARIABACKUP_EVENT("after_copy", node->space->name);
|
||||||
@ -3041,15 +3267,24 @@ xb_new_datafile(const char *name, bool is_remote)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
/** Load tablespace.
|
||||||
void
|
|
||||||
xb_load_single_table_tablespace(
|
@param[in] dirname directory name of the tablespace to open
|
||||||
const char *dirname,
|
@param[in] filname file name of the tablespece to open
|
||||||
const char *filname,
|
@param[in] is_remote true if tablespace file is .isl
|
||||||
bool is_remote)
|
@param[in] skip_node_page0 true if we don't need to read node page 0. Otherwise
|
||||||
|
node page0 will be read, and it's size and free pages limit
|
||||||
|
will be set from page 0, what is neccessary for checking and fixing corrupted
|
||||||
|
pages.
|
||||||
|
*/
|
||||||
|
static void xb_load_single_table_tablespace(const char *dirname,
|
||||||
|
const char *filname,
|
||||||
|
bool is_remote,
|
||||||
|
bool skip_node_page0)
|
||||||
{
|
{
|
||||||
ut_ad(srv_operation == SRV_OPERATION_BACKUP
|
ut_ad(srv_operation == SRV_OPERATION_BACKUP
|
||||||
|| srv_operation == SRV_OPERATION_RESTORE_DELTA);
|
|| srv_operation == SRV_OPERATION_RESTORE_DELTA
|
||||||
|
|| srv_operation == SRV_OPERATION_RESTORE);
|
||||||
/* Ignore .isl files on XtraBackup recovery. All tablespaces must be
|
/* Ignore .isl files on XtraBackup recovery. All tablespaces must be
|
||||||
local. */
|
local. */
|
||||||
if (is_remote && srv_operation == SRV_OPERATION_RESTORE_DELTA) {
|
if (is_remote && srv_operation == SRV_OPERATION_RESTORE_DELTA) {
|
||||||
@ -3102,8 +3337,8 @@ xb_load_single_table_tablespace(
|
|||||||
FIL_TYPE_TABLESPACE, NULL/* TODO: crypt_data */);
|
FIL_TYPE_TABLESPACE, NULL/* TODO: crypt_data */);
|
||||||
|
|
||||||
ut_a(space != NULL);
|
ut_a(space != NULL);
|
||||||
|
space->add(file->filepath(),
|
||||||
space->add(file->filepath(), file->detach(), 0, false, false);
|
skip_node_page0 ? file->detach() : pfs_os_file_t(), 0, false, false);
|
||||||
mutex_enter(&fil_system.mutex);
|
mutex_enter(&fil_system.mutex);
|
||||||
space->read_page0();
|
space->read_page0();
|
||||||
mutex_exit(&fil_system.mutex);
|
mutex_exit(&fil_system.mutex);
|
||||||
@ -3123,6 +3358,28 @@ xb_load_single_table_tablespace(
|
|||||||
ut_free(name);
|
ut_free(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void xb_load_single_table_tablespace(const std::string &space_name,
|
||||||
|
bool skip_node_page0)
|
||||||
|
{
|
||||||
|
std::string name(space_name);
|
||||||
|
bool is_remote= access((name + ".ibd").c_str(), R_OK) != 0;
|
||||||
|
const char *extension= is_remote ? ".isl" : ".ibd";
|
||||||
|
name.append(extension);
|
||||||
|
char buf[FN_REFLEN];
|
||||||
|
strncpy(buf, name.c_str(), sizeof buf - 1);
|
||||||
|
buf[sizeof buf - 1]= '\0';
|
||||||
|
const char *dbname= buf;
|
||||||
|
char *p= strchr(buf, '/');
|
||||||
|
if (p == 0)
|
||||||
|
die("Unexpected tablespace %s filename %s", space_name.c_str(),
|
||||||
|
name.c_str());
|
||||||
|
ut_a(p);
|
||||||
|
*p= 0;
|
||||||
|
const char *tablename= p + 1;
|
||||||
|
xb_load_single_table_tablespace(dbname, tablename, is_remote,
|
||||||
|
skip_node_page0);
|
||||||
|
}
|
||||||
|
|
||||||
/** Scan the database directories under the MySQL datadir, looking for
|
/** Scan the database directories under the MySQL datadir, looking for
|
||||||
.ibd files and determining the space id in each of them.
|
.ibd files and determining the space id in each of them.
|
||||||
@return DB_SUCCESS or error number */
|
@return DB_SUCCESS or error number */
|
||||||
@ -3164,7 +3421,7 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
|
|||||||
bool is_ibd = !is_isl && ends_with(dbinfo.name,".ibd");
|
bool is_ibd = !is_isl && ends_with(dbinfo.name,".ibd");
|
||||||
|
|
||||||
if (is_isl || is_ibd) {
|
if (is_isl || is_ibd) {
|
||||||
(*callback)(NULL, dbinfo.name, is_isl);
|
(*callback)(NULL, dbinfo.name, is_isl, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3221,7 +3478,7 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
|
|||||||
if (strlen(fileinfo.name) > 4) {
|
if (strlen(fileinfo.name) > 4) {
|
||||||
bool is_isl= false;
|
bool is_isl= false;
|
||||||
if (ends_with(fileinfo.name, ".ibd") || ((is_isl = ends_with(fileinfo.name, ".isl"))))
|
if (ends_with(fileinfo.name, ".ibd") || ((is_isl = ends_with(fileinfo.name, ".isl"))))
|
||||||
(*callback)(dbinfo.name, fileinfo.name, is_isl);
|
(*callback)(dbinfo.name, fileinfo.name, is_isl, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3935,6 +4192,7 @@ static bool xtrabackup_backup_func()
|
|||||||
uint i;
|
uint i;
|
||||||
uint count;
|
uint count;
|
||||||
pthread_mutex_t count_mutex;
|
pthread_mutex_t count_mutex;
|
||||||
|
CorruptedPages corrupted_pages;
|
||||||
data_thread_ctxt_t *data_threads;
|
data_thread_ctxt_t *data_threads;
|
||||||
pthread_mutex_init(&backup_mutex, NULL);
|
pthread_mutex_init(&backup_mutex, NULL);
|
||||||
pthread_cond_init(&scanned_lsn_cond, NULL);
|
pthread_cond_init(&scanned_lsn_cond, NULL);
|
||||||
@ -4201,6 +4459,7 @@ fail_before_log_copying_thread_start:
|
|||||||
data_threads[i].num = i+1;
|
data_threads[i].num = i+1;
|
||||||
data_threads[i].count = &count;
|
data_threads[i].count = &count;
|
||||||
data_threads[i].count_mutex = &count_mutex;
|
data_threads[i].count_mutex = &count_mutex;
|
||||||
|
data_threads[i].corrupted_pages = &corrupted_pages;
|
||||||
data_threads[i].id = os_thread_create(data_copy_thread_func,
|
data_threads[i].id = os_thread_create(data_copy_thread_func,
|
||||||
data_threads + i);
|
data_threads + i);
|
||||||
}
|
}
|
||||||
@ -4221,7 +4480,7 @@ fail_before_log_copying_thread_start:
|
|||||||
datafiles_iter_free(it);
|
datafiles_iter_free(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = backup_start();
|
bool ok = backup_start(corrupted_pages);
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
ok = xtrabackup_backup_low();
|
ok = xtrabackup_backup_low();
|
||||||
@ -4238,6 +4497,9 @@ fail_before_log_copying_thread_start:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt_log_innodb_page_corruption)
|
||||||
|
ok = corrupted_pages.print_to_file(MB_CORRUPTED_PAGES_FILE);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -4265,7 +4527,13 @@ fail_before_log_copying_thread_start:
|
|||||||
log_file_op = NULL;
|
log_file_op = NULL;
|
||||||
pthread_mutex_destroy(&backup_mutex);
|
pthread_mutex_destroy(&backup_mutex);
|
||||||
pthread_cond_destroy(&scanned_lsn_cond);
|
pthread_cond_destroy(&scanned_lsn_cond);
|
||||||
return(true);
|
if (opt_log_innodb_page_corruption && !corrupted_pages.empty()) {
|
||||||
|
msg("Error: corrupted innodb pages are found and logged to "
|
||||||
|
MB_CORRUPTED_PAGES_FILE " file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4287,7 +4555,7 @@ FTWRL. This ensures consistent backup in presence of DDL.
|
|||||||
It is the responsibility of the prepare phase to deal with .new, .ren, and .del
|
It is the responsibility of the prepare phase to deal with .new, .ren, and .del
|
||||||
files.
|
files.
|
||||||
*/
|
*/
|
||||||
void backup_fix_ddl(void)
|
void backup_fix_ddl(CorruptedPages &corrupted_pages)
|
||||||
{
|
{
|
||||||
std::set<std::string> new_tables;
|
std::set<std::string> new_tables;
|
||||||
std::set<std::string> dropped_tables;
|
std::set<std::string> dropped_tables;
|
||||||
@ -4309,6 +4577,7 @@ void backup_fix_ddl(void)
|
|||||||
|
|
||||||
if (ddl_tracker.drops.find(id) != ddl_tracker.drops.end()) {
|
if (ddl_tracker.drops.find(id) != ddl_tracker.drops.end()) {
|
||||||
dropped_tables.insert(name);
|
dropped_tables.insert(name);
|
||||||
|
corrupted_pages.drop_space(id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4320,6 +4589,8 @@ void backup_fix_ddl(void)
|
|||||||
const std::string new_name = ddl_tracker.id_to_name[id];
|
const std::string new_name = ddl_tracker.id_to_name[id];
|
||||||
if (new_name != name) {
|
if (new_name != name) {
|
||||||
renamed_tables[name] = new_name;
|
renamed_tables[name] = new_name;
|
||||||
|
if (opt_log_innodb_page_corruption)
|
||||||
|
corrupted_pages.rename_space(id, new_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4339,6 +4610,8 @@ void backup_fix_ddl(void)
|
|||||||
if (ddl_tracker.drops.find(id) == ddl_tracker.drops.end()) {
|
if (ddl_tracker.drops.find(id) == ddl_tracker.drops.end()) {
|
||||||
dropped_tables.erase(name);
|
dropped_tables.erase(name);
|
||||||
new_tables.insert(name);
|
new_tables.insert(name);
|
||||||
|
if (opt_log_innodb_page_corruption)
|
||||||
|
corrupted_pages.drop_space(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4386,23 +4659,7 @@ void backup_fix_ddl(void)
|
|||||||
const char *space_name = iter->c_str();
|
const char *space_name = iter->c_str();
|
||||||
if (check_if_skip_table(space_name))
|
if (check_if_skip_table(space_name))
|
||||||
continue;
|
continue;
|
||||||
std::string name(*iter);
|
xb_load_single_table_tablespace(*iter, false);
|
||||||
bool is_remote = access((name + ".ibd").c_str(), R_OK) != 0;
|
|
||||||
const char *extension = is_remote ? ".isl" : ".ibd";
|
|
||||||
name.append(extension);
|
|
||||||
char buf[FN_REFLEN];
|
|
||||||
strncpy(buf, name.c_str(), sizeof buf - 1);
|
|
||||||
buf[sizeof buf - 1] = '\0';
|
|
||||||
const char *dbname = buf;
|
|
||||||
char *p = strchr(buf, '/');
|
|
||||||
if (p == 0) {
|
|
||||||
msg("Unexpected tablespace %s filename %s", space_name, name.c_str());
|
|
||||||
ut_a(0);
|
|
||||||
}
|
|
||||||
ut_a(p);
|
|
||||||
*p = 0;
|
|
||||||
const char *tablename = p + 1;
|
|
||||||
xb_load_single_table_tablespace(dbname, tablename, is_remote);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it = datafiles_iter_new();
|
it = datafiles_iter_new();
|
||||||
@ -4415,7 +4672,8 @@ void backup_fix_ddl(void)
|
|||||||
continue;
|
continue;
|
||||||
std::string dest_name(node->space->name);
|
std::string dest_name(node->space->name);
|
||||||
dest_name.append(".new");
|
dest_name.append(".new");
|
||||||
xtrabackup_copy_datafile(node, 0, dest_name.c_str(), wf_write_through);
|
xtrabackup_copy_datafile(node, 0, dest_name.c_str(), wf_write_through,
|
||||||
|
corrupted_pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
datafiles_iter_free(it);
|
datafiles_iter_free(it);
|
||||||
@ -5341,6 +5599,7 @@ static ibool prepare_handle_del_files(const char *datadir, const char *db, const
|
|||||||
@return whether the operation succeeded */
|
@return whether the operation succeeded */
|
||||||
static bool xtrabackup_prepare_func(char** argv)
|
static bool xtrabackup_prepare_func(char** argv)
|
||||||
{
|
{
|
||||||
|
CorruptedPages corrupted_pages;
|
||||||
char metadata_path[FN_REFLEN];
|
char metadata_path[FN_REFLEN];
|
||||||
|
|
||||||
/* cd to target-dir */
|
/* cd to target-dir */
|
||||||
@ -5506,6 +5765,30 @@ static bool xtrabackup_prepare_func(char** argv)
|
|||||||
|
|
||||||
ut_ad(!fil_system.freeze_space_list);
|
ut_ad(!fil_system.freeze_space_list);
|
||||||
|
|
||||||
|
corrupted_pages.read_from_file(MB_CORRUPTED_PAGES_FILE);
|
||||||
|
if (xtrabackup_incremental)
|
||||||
|
{
|
||||||
|
char inc_filename[FN_REFLEN];
|
||||||
|
sprintf(inc_filename, "%s/%s", xtrabackup_incremental_dir,
|
||||||
|
MB_CORRUPTED_PAGES_FILE);
|
||||||
|
corrupted_pages.read_from_file(inc_filename);
|
||||||
|
}
|
||||||
|
if (!corrupted_pages.empty())
|
||||||
|
corrupted_pages.zero_out_free_pages();
|
||||||
|
if (corrupted_pages.empty())
|
||||||
|
{
|
||||||
|
if (!xtrabackup_incremental && unlink(MB_CORRUPTED_PAGES_FILE) &&
|
||||||
|
errno != ENOENT)
|
||||||
|
{
|
||||||
|
char errbuf[MYSYS_STRERROR_SIZE];
|
||||||
|
my_strerror(errbuf, sizeof(errbuf), errno);
|
||||||
|
die("Error: unlink %s failed: %s", MB_CORRUPTED_PAGES_FILE,
|
||||||
|
errbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
corrupted_pages.print_to_file(MB_CORRUPTED_PAGES_FILE);
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
msg("Last binlog file %s, position %lld",
|
msg("Last binlog file %s, position %lld",
|
||||||
trx_sys.recovered_binlog_filename,
|
trx_sys.recovered_binlog_filename,
|
||||||
@ -5564,7 +5847,7 @@ static bool xtrabackup_prepare_func(char** argv)
|
|||||||
|
|
||||||
error_cleanup:
|
error_cleanup:
|
||||||
xb_filters_free();
|
xb_filters_free();
|
||||||
return ok && !ib::error::was_logged();
|
return ok && !ib::error::was_logged() && corrupted_pages.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
|||||||
#include "datasink.h"
|
#include "datasink.h"
|
||||||
#include "xbstream.h"
|
#include "xbstream.h"
|
||||||
#include "changed_page_bitmap.h"
|
#include "changed_page_bitmap.h"
|
||||||
|
#include <set>
|
||||||
|
|
||||||
struct xb_delta_info_t
|
struct xb_delta_info_t
|
||||||
{
|
{
|
||||||
@ -36,6 +37,32 @@ struct xb_delta_info_t
|
|||||||
ulint space_id;
|
ulint space_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CorruptedPages
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CorruptedPages();
|
||||||
|
~CorruptedPages();
|
||||||
|
void add_page(const char *file_name, ulint space_id, unsigned page_no);
|
||||||
|
bool contains(ulint space_id, unsigned page_no) const;
|
||||||
|
void drop_space(ulint space_id);
|
||||||
|
void rename_space(ulint space_id, const std::string &new_name);
|
||||||
|
bool print_to_file(const char *file_name) const;
|
||||||
|
void read_from_file(const char *file_name);
|
||||||
|
bool empty() const;
|
||||||
|
void zero_out_free_pages();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void add_page_no_lock(const char *space_name, ulint space_id,
|
||||||
|
unsigned page_no, bool convert_space_name);
|
||||||
|
struct space_info_t {
|
||||||
|
std::string space_name;
|
||||||
|
std::set<unsigned> pages;
|
||||||
|
};
|
||||||
|
typedef std::map<ulint, space_info_t> container_t;
|
||||||
|
mutable pthread_mutex_t m_mutex;
|
||||||
|
container_t m_spaces;
|
||||||
|
};
|
||||||
|
|
||||||
/* value of the --incremental option */
|
/* value of the --incremental option */
|
||||||
extern lsn_t incremental_lsn;
|
extern lsn_t incremental_lsn;
|
||||||
|
|
||||||
@ -111,6 +138,7 @@ extern my_bool opt_remove_original;
|
|||||||
extern my_bool opt_extended_validation;
|
extern my_bool opt_extended_validation;
|
||||||
extern my_bool opt_encrypted_backup;
|
extern my_bool opt_encrypted_backup;
|
||||||
extern my_bool opt_lock_ddl_per_table;
|
extern my_bool opt_lock_ddl_per_table;
|
||||||
|
extern my_bool opt_log_innodb_page_corruption;
|
||||||
|
|
||||||
extern char *opt_incremental_history_name;
|
extern char *opt_incremental_history_name;
|
||||||
extern char *opt_incremental_history_uuid;
|
extern char *opt_incremental_history_uuid;
|
||||||
|
@ -514,6 +514,10 @@ sub mtr_report_stats ($$$$) {
|
|||||||
# if a test case has to be retried it should have the result MTR_RES_FAILED in jUnit XML
|
# if a test case has to be retried it should have the result MTR_RES_FAILED in jUnit XML
|
||||||
if ($test->{'result'} eq "MTR_RES_FAILED" || $test->{'retries'} > 0) {
|
if ($test->{'result'} eq "MTR_RES_FAILED" || $test->{'retries'} > 0) {
|
||||||
my $logcontents = $test->{'logfile-failed'} || $test->{'logfile'};
|
my $logcontents = $test->{'logfile-failed'} || $test->{'logfile'};
|
||||||
|
# remove any double ] that would end the cdata
|
||||||
|
$logcontents =~ s/]]/\x{fffd}/g;
|
||||||
|
# replace wide characters that aren't allowed in XML 1.0
|
||||||
|
$logcontents =~ s/[\x00-\x08\x0B\x0C\x0E-\x1F]/\x{fffd}/g;
|
||||||
|
|
||||||
$xml_report .= qq(>\n\t\t\t<failure message="" type="MTR_RES_FAILED">\n<![CDATA[$logcontents]]>\n\t\t\t</failure>\n\t\t</testcase>\n);
|
$xml_report .= qq(>\n\t\t\t<failure message="" type="MTR_RES_FAILED">\n<![CDATA[$logcontents]]>\n\t\t\t</failure>\n\t\t</testcase>\n);
|
||||||
} elsif ($test->{'result'} eq "MTR_RES_SKIPPED" && $test->{'disable'}) {
|
} elsif ($test->{'result'} eq "MTR_RES_SKIPPED" && $test->{'disable'}) {
|
||||||
@ -530,9 +534,9 @@ sub mtr_report_stats ($$$$) {
|
|||||||
# save to file
|
# save to file
|
||||||
my $xml_file = $::opt_xml_report;
|
my $xml_file = $::opt_xml_report;
|
||||||
|
|
||||||
open XML_FILE, ">", $xml_file or die "Cannot create file $xml_file: $!";
|
open (my $XML_UFILE, '>:encoding(UTF-8)', $xml_file) or die 'Cannot create file $xml_file: $!';
|
||||||
print XML_FILE $xml_report;
|
print $XML_UFILE $xml_report;
|
||||||
close XML_FILE;
|
close $XML_UFILE or warn "File close failed!";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@$extra_warnings)
|
if (@$extra_warnings)
|
||||||
|
@ -289,3 +289,51 @@ pk f
|
|||||||
5 a
|
5 a
|
||||||
6 <===
|
6 <===
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
#
|
||||||
|
# MDEV-21842: auto_increment does not increment with compound primary
|
||||||
|
# key on partitioned table
|
||||||
|
#
|
||||||
|
create or replace table `t` (
|
||||||
|
`id` bigint(20) unsigned not null auto_increment,
|
||||||
|
`a` int(10) not null ,
|
||||||
|
`dt` date not null,
|
||||||
|
primary key (`id`, `dt`) ,
|
||||||
|
unique key (`a`, `dt`)
|
||||||
|
)
|
||||||
|
partition by range columns(`dt`)
|
||||||
|
(
|
||||||
|
partition `p202002` values less than ('2020-03-01'),
|
||||||
|
partition `P202003` values less than ('2020-04-01')
|
||||||
|
);
|
||||||
|
connect con1, localhost, root,,;
|
||||||
|
connect con2, localhost, root,,;
|
||||||
|
connection con1;
|
||||||
|
start transaction;
|
||||||
|
insert into t (a, dt) values (1, '2020-02-29');
|
||||||
|
connection con2;
|
||||||
|
start transaction;
|
||||||
|
insert into t (a, dt) values (1, '2020-02-29');
|
||||||
|
connection con1;
|
||||||
|
insert into t (a, dt) values (2, '2020-02-29');
|
||||||
|
select auto_increment from information_schema.tables where table_name='t';
|
||||||
|
auto_increment
|
||||||
|
4
|
||||||
|
commit;
|
||||||
|
connection con2;
|
||||||
|
ERROR 23000: Duplicate entry '1-2020-02-29' for key 'a'
|
||||||
|
connection con1;
|
||||||
|
select auto_increment from information_schema.tables where table_name='t';
|
||||||
|
auto_increment
|
||||||
|
4
|
||||||
|
insert into t (a, dt) values (3, '2020-02-29');
|
||||||
|
insert into t (a, dt) values (4, '2020-02-29');
|
||||||
|
disconnect con1;
|
||||||
|
disconnect con2;
|
||||||
|
connection default;
|
||||||
|
select * from t;
|
||||||
|
id a dt
|
||||||
|
1 1 2020-02-29
|
||||||
|
3 2 2020-02-29
|
||||||
|
4 3 2020-02-29
|
||||||
|
5 4 2020-02-29
|
||||||
|
drop table t;
|
||||||
|
@ -18,3 +18,62 @@ select * from t1;
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
--let $datadir=`select @@datadir`
|
--let $datadir=`select @@datadir`
|
||||||
--remove_file $datadir/test/load.data
|
--remove_file $datadir/test/load.data
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-21842: auto_increment does not increment with compound primary
|
||||||
|
--echo # key on partitioned table
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create or replace table `t` (
|
||||||
|
`id` bigint(20) unsigned not null auto_increment,
|
||||||
|
`a` int(10) not null ,
|
||||||
|
`dt` date not null,
|
||||||
|
primary key (`id`, `dt`) ,
|
||||||
|
unique key (`a`, `dt`)
|
||||||
|
)
|
||||||
|
partition by range columns(`dt`)
|
||||||
|
(
|
||||||
|
partition `p202002` values less than ('2020-03-01'),
|
||||||
|
partition `P202003` values less than ('2020-04-01')
|
||||||
|
);
|
||||||
|
|
||||||
|
connect (con1, localhost, root,,);
|
||||||
|
connect (con2, localhost, root,,);
|
||||||
|
|
||||||
|
--connection con1
|
||||||
|
start transaction;
|
||||||
|
insert into t (a, dt) values (1, '2020-02-29');
|
||||||
|
|
||||||
|
--connection con2
|
||||||
|
start transaction;
|
||||||
|
let $conn2_id= `SELECT CONNECTION_ID()`;
|
||||||
|
send insert into t (a, dt) values (1, '2020-02-29');
|
||||||
|
|
||||||
|
--connection con1
|
||||||
|
# Ensure that the above insert via conn2 increments next_auto_inc_val
|
||||||
|
# before the following insert via conn1 starts.
|
||||||
|
let $wait_condition=select 1 from Information_schema.INNODB_TRX
|
||||||
|
where trx_mysql_thread_id = $conn2_id and trx_state = 'LOCK WAIT'
|
||||||
|
and trx_query = "insert into t (a, dt) values (1, '2020-02-29')";
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
insert into t (a, dt) values (2, '2020-02-29');
|
||||||
|
select auto_increment from information_schema.tables where table_name='t';
|
||||||
|
commit;
|
||||||
|
|
||||||
|
--connection con2
|
||||||
|
--error ER_DUP_ENTRY
|
||||||
|
reap;
|
||||||
|
|
||||||
|
--connection con1
|
||||||
|
select auto_increment from information_schema.tables where table_name='t';
|
||||||
|
insert into t (a, dt) values (3, '2020-02-29');
|
||||||
|
insert into t (a, dt) values (4, '2020-02-29');
|
||||||
|
|
||||||
|
disconnect con1;
|
||||||
|
disconnect con2;
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
select * from t;
|
||||||
|
drop table t;
|
||||||
|
|
||||||
|
@ -10566,6 +10566,47 @@ a
|
|||||||
abc
|
abc
|
||||||
DROP VIEW v1;
|
DROP VIEW v1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# MDEV-19179: pushdown into UNION of aggregation selects whose
|
||||||
|
# corresponding columns have different names
|
||||||
|
#
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (3), (7), (1);
|
||||||
|
select *
|
||||||
|
from (select min(a) as x from t1 union all select max(a) as y from t1) t
|
||||||
|
where x>0;
|
||||||
|
x
|
||||||
|
1
|
||||||
|
7
|
||||||
|
explain extended select *
|
||||||
|
from (select min(a) as x from t1 union all select max(a) as y from t1) t
|
||||||
|
where x>0;
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 6 100.00 Using where
|
||||||
|
2 DERIVED t1 ALL NULL NULL NULL NULL 3 100.00
|
||||||
|
3 UNION t1 ALL NULL NULL NULL NULL 3 100.00
|
||||||
|
Warnings:
|
||||||
|
Note 1003 /* select#1 */ select `t`.`x` AS `x` from (/* select#2 */ select min(`test`.`t1`.`a`) AS `x` from `test`.`t1` having `x` > 0 union all /* select#3 */ select max(`test`.`t1`.`a`) AS `x` from `test`.`t1` having `x` > 0) `t` where `t`.`x` > 0
|
||||||
|
prepare stmt from "select *
|
||||||
|
from (select min(a) as x from t1 union all select max(a) as y from t1) t
|
||||||
|
where x>0";
|
||||||
|
execute stmt;
|
||||||
|
x
|
||||||
|
1
|
||||||
|
7
|
||||||
|
execute stmt;
|
||||||
|
x
|
||||||
|
1
|
||||||
|
7
|
||||||
|
deallocate prepare stmt;
|
||||||
|
create view v1(m) as
|
||||||
|
select min(a) as x from t1 union all select max(a) as y from t1;
|
||||||
|
select * from v1 where m > 0;
|
||||||
|
m
|
||||||
|
1
|
||||||
|
7
|
||||||
|
drop view v1;
|
||||||
|
drop table t1;
|
||||||
# End of 10.2 tests
|
# End of 10.2 tests
|
||||||
#
|
#
|
||||||
# MDEV-14579: pushdown conditions into materialized views/derived tables
|
# MDEV-14579: pushdown conditions into materialized views/derived tables
|
||||||
|
@ -2185,6 +2185,34 @@ SELECT * FROM v1 WHERE IF( a REGEXP 'def', 'foo', a ) IN ('abc', 'foobar');
|
|||||||
DROP VIEW v1;
|
DROP VIEW v1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-19179: pushdown into UNION of aggregation selects whose
|
||||||
|
--echo # corresponding columns have different names
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (3), (7), (1);
|
||||||
|
|
||||||
|
let $q=
|
||||||
|
select *
|
||||||
|
from (select min(a) as x from t1 union all select max(a) as y from t1) t
|
||||||
|
where x>0;
|
||||||
|
|
||||||
|
eval $q;
|
||||||
|
eval explain extended $q;
|
||||||
|
|
||||||
|
eval prepare stmt from "$q";
|
||||||
|
execute stmt;
|
||||||
|
execute stmt;
|
||||||
|
deallocate prepare stmt;
|
||||||
|
|
||||||
|
create view v1(m) as
|
||||||
|
select min(a) as x from t1 union all select max(a) as y from t1;
|
||||||
|
select * from v1 where m > 0;
|
||||||
|
|
||||||
|
drop view v1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
--echo # End of 10.2 tests
|
--echo # End of 10.2 tests
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -2219,8 +2219,6 @@ SCHEMA_NAME
|
|||||||
# End of 10.1 tests
|
# End of 10.1 tests
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Start of 10.2 Test
|
|
||||||
#
|
|
||||||
# MDEV-14836: Assertion `m_status == DA_ERROR' failed in
|
# MDEV-14836: Assertion `m_status == DA_ERROR' failed in
|
||||||
# Diagnostics_area::sql_errno upon query from I_S with LIMIT ROWS EXAMINED
|
# Diagnostics_area::sql_errno upon query from I_S with LIMIT ROWS EXAMINED
|
||||||
#
|
#
|
||||||
@ -2305,5 +2303,12 @@ mysql global_priv Priv json_valid(`Priv`) def mysql
|
|||||||
test t a `i` > 0 def test
|
test t a `i` > 0 def test
|
||||||
drop table t;
|
drop table t;
|
||||||
#
|
#
|
||||||
|
# MDEV-24230 subquery on information_schema fails with error message
|
||||||
|
#
|
||||||
|
create table t1 (n int);
|
||||||
|
create table t2 (n int);
|
||||||
|
insert into t1 set n = (select table_rows from information_schema.tables where table_name='t2');
|
||||||
|
drop table t1, t2;
|
||||||
|
#
|
||||||
# End of 10.3 tests
|
# End of 10.3 tests
|
||||||
#
|
#
|
||||||
|
@ -1923,8 +1923,6 @@ SELECT SCHEMA_NAME from information_schema.schemata where schema_name=REPEAT('a'
|
|||||||
--echo # End of 10.1 tests
|
--echo # End of 10.1 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
--echo #
|
|
||||||
--echo # Start of 10.2 Test
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MDEV-14836: Assertion `m_status == DA_ERROR' failed in
|
--echo # MDEV-14836: Assertion `m_status == DA_ERROR' failed in
|
||||||
--echo # Diagnostics_area::sql_errno upon query from I_S with LIMIT ROWS EXAMINED
|
--echo # Diagnostics_area::sql_errno upon query from I_S with LIMIT ROWS EXAMINED
|
||||||
@ -1998,6 +1996,14 @@ from information_schema.TABLE_CONSTRAINTS tc
|
|||||||
|
|
||||||
drop table t;
|
drop table t;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-24230 subquery on information_schema fails with error message
|
||||||
|
--echo #
|
||||||
|
create table t1 (n int);
|
||||||
|
create table t2 (n int);
|
||||||
|
insert into t1 set n = (select table_rows from information_schema.tables where table_name='t2');
|
||||||
|
drop table t1, t2;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.3 tests
|
--echo # End of 10.3 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
source include/not_embedded.inc;
|
source include/not_embedded.inc;
|
||||||
|
source include/have_perfschema.inc;
|
||||||
#
|
#
|
||||||
# LOCK TABLES and privileges on views
|
# LOCK TABLES and privileges on views
|
||||||
#
|
#
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
--source include/have_udf.inc
|
--source include/have_udf.inc
|
||||||
--source include/platform.inc
|
--source include/platform.inc
|
||||||
|
|
||||||
|
if (!$AUTH_SOCKET_SO) {
|
||||||
|
--skip Need auth socket plugin
|
||||||
|
}
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MDEV-23630: mysqldump to logically dump system tables
|
--echo # MDEV-23630: mysqldump to logically dump system tables
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -1087,10 +1087,10 @@ INSERT INTO t1 VALUES ();
|
|||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
a
|
a
|
||||||
-1
|
-1
|
||||||
1
|
|
||||||
3
|
3
|
||||||
4
|
4
|
||||||
6
|
6
|
||||||
|
7
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
# End of 10.3 tests
|
# End of 10.3 tests
|
||||||
|
@ -8448,8 +8448,25 @@ ERROR 22007: Incorrect integer value: 'y' for column ``.``.`a` at row 1
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SET sql_mode=DEFAULT;
|
SET sql_mode=DEFAULT;
|
||||||
#
|
#
|
||||||
# Start of 10.3 tests
|
# MDEV-24220: error when opening a table for the second call of SP
|
||||||
#
|
#
|
||||||
|
CREATE TABLE t1 (a INT, b INT);
|
||||||
|
INSERT INTO t1 VALUES (1,1),(2,2);
|
||||||
|
CREATE VIEW v1 AS SELECT MAX(a) as f FROM t1;
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
BEGIN
|
||||||
|
SELECT * FROM v1;
|
||||||
|
END $
|
||||||
|
CALL p1;
|
||||||
|
f
|
||||||
|
2
|
||||||
|
ALTER TABLE t1 DROP a;
|
||||||
|
CALL p1;
|
||||||
|
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
#End of 10.2 tests
|
||||||
#
|
#
|
||||||
# MDEV-12007 Allow ROW variables as a cursor FETCH target
|
# MDEV-12007 Allow ROW variables as a cursor FETCH target
|
||||||
#
|
#
|
||||||
|
@ -9991,9 +9991,30 @@ DROP TABLE t1;
|
|||||||
SET sql_mode=DEFAULT;
|
SET sql_mode=DEFAULT;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # Start of 10.3 tests
|
--echo # MDEV-24220: error when opening a table for the second call of SP
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT, b INT);
|
||||||
|
INSERT INTO t1 VALUES (1,1),(2,2);
|
||||||
|
CREATE VIEW v1 AS SELECT MAX(a) as f FROM t1;
|
||||||
|
--delimiter $
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
BEGIN
|
||||||
|
SELECT * FROM v1;
|
||||||
|
END $
|
||||||
|
--delimiter ;
|
||||||
|
|
||||||
|
CALL p1;
|
||||||
|
ALTER TABLE t1 DROP a;
|
||||||
|
-- error ER_VIEW_INVALID
|
||||||
|
CALL p1;
|
||||||
|
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #End of 10.2 tests
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MDEV-12007 Allow ROW variables as a cursor FETCH target
|
--echo # MDEV-12007 Allow ROW variables as a cursor FETCH target
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -2719,6 +2719,41 @@ SET join_cache_level= @save_join_cache_level;
|
|||||||
DROP TABLE t1,t2,t3,t4;
|
DROP TABLE t1,t2,t3,t4;
|
||||||
# End of 10.2 tests
|
# End of 10.2 tests
|
||||||
#
|
#
|
||||||
|
# MDEV-21265: IN predicate conversion to IN subquery should be allowed for a broader set of datatype comparison
|
||||||
|
#
|
||||||
|
CREATE TABLE t1(a VARCHAR(50) collate utf8_general_ci, b INT);
|
||||||
|
INSERT INTO t1 VALUES ('abc',1), ('def', 2), ('ghi', 3), ('jkl', 4), ('mno', 5);
|
||||||
|
CREATE TABLE t2(a VARCHAR(50) collate utf8mb4_general_ci, b INT);
|
||||||
|
INSERT INTO t2 VALUES ('abc',1), ('def', 2), ('ghi', 3), ('jkl', 4), ('mno', 5);
|
||||||
|
set @save_in_predicate_conversion_threshold= @@in_predicate_conversion_threshold;
|
||||||
|
set in_predicate_conversion_threshold=2;
|
||||||
|
set names 'utf8mb4';
|
||||||
|
#
|
||||||
|
# IN predicate to IN subquery is not allowed as materialization is not allowed
|
||||||
|
# The character set on the inner side is not equal to or a proper subset of the outer side
|
||||||
|
#
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t1 WHERE (t1.a,t1.b) IN (('abx',1),('def',2), ('abc', 3));
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
|
||||||
|
set names 'utf8';
|
||||||
|
#
|
||||||
|
# IN predicate to IN subquery is performed as materialization is llowed
|
||||||
|
# The character set on the inner side is a proper subset of the outer side
|
||||||
|
#
|
||||||
|
# this test in 10.5 has only 2 rows in the IN predicate
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t2 WHERE (t2.a,t2.b) IN (('abc',1), ('def', 2));
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t2 ALL NULL NULL NULL NULL 5
|
||||||
|
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 16 func,func 1 Using where
|
||||||
|
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2
|
||||||
|
3 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||||
|
set names default;
|
||||||
|
set @@in_predicate_conversion_threshold= @save_in_predicate_conversion_threshold;
|
||||||
|
DROP TABLE t1,t2;
|
||||||
|
# End of 10.3 tests
|
||||||
|
#
|
||||||
# MDEV-19134: EXISTS() slower if ORDER BY is defined
|
# MDEV-19134: EXISTS() slower if ORDER BY is defined
|
||||||
#
|
#
|
||||||
create table t0 (a int);
|
create table t0 (a int);
|
||||||
|
@ -2239,6 +2239,45 @@ DROP TABLE t1,t2,t3,t4;
|
|||||||
|
|
||||||
--echo # End of 10.2 tests
|
--echo # End of 10.2 tests
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-21265: IN predicate conversion to IN subquery should be allowed for a broader set of datatype comparison
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1(a VARCHAR(50) collate utf8_general_ci, b INT);
|
||||||
|
INSERT INTO t1 VALUES ('abc',1), ('def', 2), ('ghi', 3), ('jkl', 4), ('mno', 5);
|
||||||
|
|
||||||
|
CREATE TABLE t2(a VARCHAR(50) collate utf8mb4_general_ci, b INT);
|
||||||
|
INSERT INTO t2 VALUES ('abc',1), ('def', 2), ('ghi', 3), ('jkl', 4), ('mno', 5);
|
||||||
|
|
||||||
|
set @save_in_predicate_conversion_threshold= @@in_predicate_conversion_threshold;
|
||||||
|
set in_predicate_conversion_threshold=2;
|
||||||
|
|
||||||
|
set names 'utf8mb4';
|
||||||
|
--echo #
|
||||||
|
--echo # IN predicate to IN subquery is not allowed as materialization is not allowed
|
||||||
|
--echo # The character set on the inner side is not equal to or a proper subset of the outer side
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t1 WHERE (t1.a,t1.b) IN (('abx',1),('def',2), ('abc', 3));
|
||||||
|
|
||||||
|
set names 'utf8';
|
||||||
|
--echo #
|
||||||
|
--echo # IN predicate to IN subquery is performed as materialization is llowed
|
||||||
|
--echo # The character set on the inner side is a proper subset of the outer side
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo # this test in 10.5 has only 2 rows in the IN predicate
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t2 WHERE (t2.a,t2.b) IN (('abc',1), ('def', 2));
|
||||||
|
|
||||||
|
set names default;
|
||||||
|
set @@in_predicate_conversion_threshold= @save_in_predicate_conversion_threshold;
|
||||||
|
DROP TABLE t1,t2;
|
||||||
|
|
||||||
|
--echo # End of 10.3 tests
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MDEV-19134: EXISTS() slower if ORDER BY is defined
|
--echo # MDEV-19134: EXISTS() slower if ORDER BY is defined
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -349,6 +349,32 @@ XA END 'xid1';
|
|||||||
XA ROLLBACK 'xid1';
|
XA ROLLBACK 'xid1';
|
||||||
DROP TABLE t1, t2, t3;
|
DROP TABLE t1, t2, t3;
|
||||||
#
|
#
|
||||||
|
# MDEV 15532 XA: Assertion `!log->same_pk' failed in
|
||||||
|
# row_log_table_apply_delete
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES (1),(2);
|
||||||
|
connect con1,localhost,root,,test;
|
||||||
|
XA START 'xid';
|
||||||
|
UPDATE t1 SET a = 5;
|
||||||
|
connection default;
|
||||||
|
SET innodb_lock_wait_timeout= 2, lock_wait_timeout= 2;
|
||||||
|
ALTER TABLE non_existing_table1;
|
||||||
|
ERROR 42S02: Table 'test.non_existing_table1' doesn't exist
|
||||||
|
ALTER TABLE t1 FORCE;;
|
||||||
|
connection con1;
|
||||||
|
ALTER TABLE non_existing_table2;
|
||||||
|
ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state
|
||||||
|
DELETE FROM t1 LIMIT 1;
|
||||||
|
connection default;
|
||||||
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||||
|
connection con1;
|
||||||
|
XA END 'xid';
|
||||||
|
XA ROLLBACK 'xid';
|
||||||
|
DROP TABLE t1;
|
||||||
|
disconnect con1;
|
||||||
|
connection default;
|
||||||
|
#
|
||||||
# MDEV-21766 - Forbid XID with empty 'gtrid'
|
# MDEV-21766 - Forbid XID with empty 'gtrid'
|
||||||
#
|
#
|
||||||
CREATE TABLE t1(a INT) ENGINE=InnoDB;
|
CREATE TABLE t1(a INT) ENGINE=InnoDB;
|
||||||
|
@ -478,6 +478,44 @@ XA END 'xid1';
|
|||||||
XA ROLLBACK 'xid1';
|
XA ROLLBACK 'xid1';
|
||||||
DROP TABLE t1, t2, t3;
|
DROP TABLE t1, t2, t3;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV 15532 XA: Assertion `!log->same_pk' failed in
|
||||||
|
--echo # row_log_table_apply_delete
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES (1),(2);
|
||||||
|
|
||||||
|
--connect (con1,localhost,root,,test)
|
||||||
|
|
||||||
|
XA START 'xid';
|
||||||
|
UPDATE t1 SET a = 5;
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
SET innodb_lock_wait_timeout= 2, lock_wait_timeout= 2;
|
||||||
|
|
||||||
|
--error ER_NO_SUCH_TABLE
|
||||||
|
ALTER TABLE non_existing_table1;
|
||||||
|
|
||||||
|
--send ALTER TABLE t1 FORCE;
|
||||||
|
|
||||||
|
--connection con1
|
||||||
|
--error ER_XAER_RMFAIL
|
||||||
|
|
||||||
|
ALTER TABLE non_existing_table2;
|
||||||
|
DELETE FROM t1 LIMIT 1;
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
--error ER_LOCK_WAIT_TIMEOUT
|
||||||
|
--reap
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
--connection con1
|
||||||
|
XA END 'xid';
|
||||||
|
XA ROLLBACK 'xid';
|
||||||
|
DROP TABLE t1;
|
||||||
|
--disconnect con1
|
||||||
|
connection default;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MDEV-21766 - Forbid XID with empty 'gtrid'
|
--echo # MDEV-21766 - Forbid XID with empty 'gtrid'
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
RESET MASTER;
|
||||||
|
CREATE TABLE t(f text);
|
||||||
|
INSERT INTO t VALUES (repeat('x',4096));
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
SELECT COUNT(*) FROM t;
|
||||||
|
COUNT(*)
|
||||||
|
512
|
||||||
|
FLUSH LOGS;
|
||||||
|
DROP TABLE t;
|
||||||
|
# 512- Rows must be present
|
||||||
|
include/assert.inc [Table t should have 512 rows.]
|
||||||
|
DROP TABLE t;
|
||||||
|
RESET MASTER;
|
@ -0,0 +1,51 @@
|
|||||||
|
# ==== Purpose ====
|
||||||
|
#
|
||||||
|
# Suppress the following informational note that gets printed to standard
|
||||||
|
# error when O_TMPFILE flag is not supported by underlying operating system.
|
||||||
|
#
|
||||||
|
# Note: ../client/mysqlbinlog: O_TMPFILE is not supported on /tmp (disabling
|
||||||
|
# future attempts)
|
||||||
|
#
|
||||||
|
# Step 1: Generate a binarylog file with a size greater than 1MB.
|
||||||
|
# Step 2: Use mysqlbinlog tool to generate sql file and redirect the standard
|
||||||
|
# error to standard output (2>&1)
|
||||||
|
# Step 3: Source the generated sql file as inpurt to mysql client, observe no
|
||||||
|
# syntax error is reported.
|
||||||
|
#
|
||||||
|
# ==== References ====
|
||||||
|
#
|
||||||
|
# MDEV-23846: O_TMPFILE error in mysqlbinlog stream output breaks restore
|
||||||
|
#
|
||||||
|
--source include/have_binlog_format_row.inc
|
||||||
|
|
||||||
|
RESET MASTER;
|
||||||
|
CREATE TABLE t(f text);
|
||||||
|
INSERT INTO t VALUES (repeat('x',4096));
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
INSERT INTO t SELECT * FROM t;
|
||||||
|
SELECT COUNT(*) FROM t;
|
||||||
|
FLUSH LOGS;
|
||||||
|
let $MYSQLD_DATADIR= `select @@datadir`;
|
||||||
|
|
||||||
|
--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_base64.sql 2>&1
|
||||||
|
#
|
||||||
|
# Clear database and restore from binlog
|
||||||
|
#
|
||||||
|
DROP TABLE t;
|
||||||
|
|
||||||
|
--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/mysqlbinlog_base64.sql
|
||||||
|
|
||||||
|
--echo # 512- Rows must be present
|
||||||
|
--let $assert_cond= COUNT(*) = 512 FROM t
|
||||||
|
--let $assert_text= Table t should have 512 rows.
|
||||||
|
--source include/assert.inc
|
||||||
|
|
||||||
|
DROP TABLE t;
|
||||||
|
RESET MASTER;
|
@ -12,14 +12,11 @@
|
|||||||
|
|
||||||
GCF-1081 : MDEV-18283 Galera test failure on galera.GCF-1081
|
GCF-1081 : MDEV-18283 Galera test failure on galera.GCF-1081
|
||||||
GCF-939 : MDEV-21520 galera.GCF-939
|
GCF-939 : MDEV-21520 galera.GCF-939
|
||||||
MDEV-16509 : MDEV-21523 galera.MDEV-16509
|
|
||||||
MDEV-20225 : MDEV-20886 galera.MDEV-20225
|
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-286 : MDEV-18464 Killing thread can cause mutex deadlock if done concurrently with Galera/replication victim kill
|
||||||
MW-328A : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002
|
MW-328A : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002
|
||||||
MW-328A : MDEV-22666?
|
|
||||||
MW-328B : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002
|
MW-328B : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002
|
||||||
MW-329 : MDEV-19962 Galera test failure on MW-329
|
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()
|
galera_as_slave_replication_bundle : MDEV-15785 OPTION_GTID_BEGIN is set in Gtid_log_event::do_apply_event()
|
||||||
galera_bf_abort_group_commit : MDEV-18282 Galera test failure on galera.galera_bf_abort_group_commit
|
galera_bf_abort_group_commit : MDEV-18282 Galera test failure on galera.galera_bf_abort_group_commit
|
||||||
galera_binlog_stmt_autoinc : MDEV-19959 Galera test failure on galera_binlog_stmt_autoinc
|
galera_binlog_stmt_autoinc : MDEV-19959 Galera test failure on galera_binlog_stmt_autoinc
|
||||||
@ -44,7 +41,6 @@ galera_var_reject_queries : assertion in inline_mysql_socket_send
|
|||||||
galera_var_replicate_myisam_on : MDEV-24062 Galera test failure on galera_var_replicate_myisam_on
|
galera_var_replicate_myisam_on : MDEV-24062 Galera test failure on galera_var_replicate_myisam_on
|
||||||
galera_var_retry_autocommit: MDEV-18181 Galera test failure on galera.galera_var_retry_autocommit
|
galera_var_retry_autocommit: MDEV-18181 Galera test failure on galera.galera_var_retry_autocommit
|
||||||
galera_wan : MDEV-17259 Test failure on galera.galera_wan
|
galera_wan : MDEV-17259 Test failure on galera.galera_wan
|
||||||
lp1376747-4 : MDEV-21911 Galera test failure on lp1376747-4
|
|
||||||
partition : MDEV-19958 Galera test failure on galera.partition
|
partition : MDEV-19958 Galera test failure on galera.partition
|
||||||
query_cache: MDEV-15805 Test failure on galera.query_cache
|
query_cache: MDEV-15805 Test failure on galera.query_cache
|
||||||
sql_log_bin : MDEV-21491 galera.sql_log_bin
|
sql_log_bin : MDEV-21491 galera.sql_log_bin
|
||||||
|
@ -2,6 +2,7 @@ connection node_2;
|
|||||||
connection node_1;
|
connection node_1;
|
||||||
connection node_1;
|
connection node_1;
|
||||||
SET SESSION wsrep_sync_wait=0;
|
SET SESSION wsrep_sync_wait=0;
|
||||||
|
# Correct Galera library found
|
||||||
SET SESSION wsrep_sync_wait=DEFAULT;
|
SET SESSION wsrep_sync_wait=DEFAULT;
|
||||||
SET GLOBAL wsrep_provider_options = 'pc.weight=3';
|
SET GLOBAL wsrep_provider_options = 'pc.weight=3';
|
||||||
SHOW GLOBAL VARIABLES LIKE 'wsrep_provider_options';
|
SHOW GLOBAL VARIABLES LIKE 'wsrep_provider_options';
|
||||||
|
95
mysql-test/suite/galera/r/galera_as_slave_replay.result
Normal file
95
mysql-test/suite/galera/r/galera_as_slave_replay.result
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
|
||||||
|
connection node_2a;
|
||||||
|
connection node_1;
|
||||||
|
RESET MASTER;
|
||||||
|
connection node_2a;
|
||||||
|
START SLAVE;
|
||||||
|
connection node_1;
|
||||||
|
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)) engine=innodb;
|
||||||
|
INSERT INTO t1 VALUES (1, 'a');
|
||||||
|
INSERT INTO t1 VALUES (3, 'a');
|
||||||
|
set binlog_format=STATEMENT;
|
||||||
|
SET AUTOCOMMIT=ON;
|
||||||
|
START TRANSACTION;
|
||||||
|
SELECT * FROM t1 FOR UPDATE;
|
||||||
|
f1 f2
|
||||||
|
1 a
|
||||||
|
3 a
|
||||||
|
UPDATE t1 SET f2 = 'c' WHERE f1 > 1;
|
||||||
|
connection node_2a;
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
|
||||||
|
connection node_3;
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
connection node_2a;
|
||||||
|
SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync';
|
||||||
|
SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb";
|
||||||
|
connection node_3;
|
||||||
|
INSERT INTO test.t1 VALUES (2, 'b');
|
||||||
|
connection node_1;
|
||||||
|
COMMIT;
|
||||||
|
connection node_2a;
|
||||||
|
SET SESSION wsrep_on = 0;
|
||||||
|
SET SESSION wsrep_on = 1;
|
||||||
|
SET GLOBAL debug_dbug = "";
|
||||||
|
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
|
||||||
|
connection node_2a;
|
||||||
|
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||||
|
SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync';
|
||||||
|
connection node_1;
|
||||||
|
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a';
|
||||||
|
COUNT(*) = 1
|
||||||
|
1
|
||||||
|
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
|
||||||
|
COUNT(*) = 1
|
||||||
|
1
|
||||||
|
SELECT * FROM t1;
|
||||||
|
f1 f2
|
||||||
|
1 a
|
||||||
|
3 c
|
||||||
|
connection node_2a;
|
||||||
|
set session wsrep_sync_wait=15;
|
||||||
|
set session wsrep_sync_wait=0;
|
||||||
|
wsrep_local_replays
|
||||||
|
1
|
||||||
|
SELECT * FROM t1;
|
||||||
|
f1 f2
|
||||||
|
1 a
|
||||||
|
2 b
|
||||||
|
3 c
|
||||||
|
SET DEBUG_SYNC = "RESET";
|
||||||
|
#
|
||||||
|
# test phase with real abort
|
||||||
|
#
|
||||||
|
connection node_1;
|
||||||
|
set binlog_format=ROW;
|
||||||
|
insert into t1 values (4, 'd');
|
||||||
|
SET AUTOCOMMIT=ON;
|
||||||
|
START TRANSACTION;
|
||||||
|
UPDATE t1 SET f2 = 'd' WHERE f1 = 3;
|
||||||
|
connection node_2a;
|
||||||
|
SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync';
|
||||||
|
SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb";
|
||||||
|
connection node_3;
|
||||||
|
UPDATE test.t1 SET f2 = 'e' WHERE f1 = 3;
|
||||||
|
connection node_1;
|
||||||
|
COMMIT;
|
||||||
|
connection node_2a;
|
||||||
|
SET GLOBAL debug_dbug = "";
|
||||||
|
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
|
||||||
|
connection node_2a;
|
||||||
|
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||||
|
SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync';
|
||||||
|
SET DEBUG_SYNC = "RESET";
|
||||||
|
connection node_2a;
|
||||||
|
set session wsrep_sync_wait=15;
|
||||||
|
SELECT COUNT(*) = 1 FROM test.t1 WHERE f2 = 'e';
|
||||||
|
COUNT(*) = 1
|
||||||
|
1
|
||||||
|
set session wsrep_sync_wait=0;
|
||||||
|
STOP SLAVE;
|
||||||
|
RESET SLAVE;
|
||||||
|
DROP TABLE t1;
|
||||||
|
connection node_1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
RESET MASTER;
|
@ -1,7 +1,8 @@
|
|||||||
connection node_2;
|
connection node_2;
|
||||||
connection node_1;
|
connection node_1;
|
||||||
SELECT COUNT(*) `expect 48` FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
|
# Correct Galera library found
|
||||||
expect 48
|
SELECT COUNT(*) `expect 49` FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
|
||||||
|
expect 49
|
||||||
49
|
49
|
||||||
SELECT VARIABLE_NAME, VARIABLE_VALUE
|
SELECT VARIABLE_NAME, VARIABLE_VALUE
|
||||||
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
connection node_2;
|
connection node_2;
|
||||||
connection node_1;
|
connection node_1;
|
||||||
connection node_1;
|
connection node_1;
|
||||||
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
|
CREATE TABLE ten (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB;
|
||||||
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
|
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
|
||||||
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
|
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
|
||||||
INSERT INTO t1 (f2) SELECT 1 FROM ten;
|
INSERT INTO t1 (f2) SELECT 1 FROM ten;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
--source include/galera_cluster.inc
|
--source include/galera_cluster.inc
|
||||||
|
--source include/have_debug.inc
|
||||||
--source include/have_debug_sync.inc
|
--source include/have_debug_sync.inc
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,12 +5,9 @@
|
|||||||
--connection node_1
|
--connection node_1
|
||||||
|
|
||||||
SET SESSION wsrep_sync_wait=0;
|
SET SESSION wsrep_sync_wait=0;
|
||||||
--disable_result_log
|
|
||||||
--disable_query_log
|
|
||||||
--let $galera_version=25.3.24
|
--let $galera_version=25.3.24
|
||||||
source ../../wsrep/include/check_galera_version.inc;
|
source ../../wsrep/include/check_galera_version.inc;
|
||||||
--enable_result_log
|
|
||||||
--enable_query_log
|
|
||||||
SET SESSION wsrep_sync_wait=DEFAULT;
|
SET SESSION wsrep_sync_wait=DEFAULT;
|
||||||
|
|
||||||
# Convert "... pc.weight = N; ..." to "N; ..."
|
# Convert "... pc.weight = N; ..." to "N; ..."
|
||||||
|
11
mysql-test/suite/galera/t/galera_as_slave_replay.cnf
Normal file
11
mysql-test/suite/galera/t/galera_as_slave_replay.cnf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
!include ../galera_2nodes_as_slave.cnf
|
||||||
|
|
||||||
|
[mysqld]
|
||||||
|
binlog-format=row
|
||||||
|
|
||||||
|
[mysqld.1]
|
||||||
|
wsrep_restart_slave=1
|
||||||
|
|
||||||
|
[mysqld.2]
|
||||||
|
wsrep_restart_slave=1
|
||||||
|
|
200
mysql-test/suite/galera/t/galera_as_slave_replay.test
Normal file
200
mysql-test/suite/galera/t/galera_as_slave_replay.test
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
#
|
||||||
|
# This test tests the operation of transaction replay for async replication slave.
|
||||||
|
# If a potentially conflicting galera transaction arrives at
|
||||||
|
# just the right time during the commit and has lock conflict with async replication transaction
|
||||||
|
# applied by slave SQL thread, then the async replication transaction should either abort
|
||||||
|
# or rollback and replay (depending on the nature of lock conflict).
|
||||||
|
#
|
||||||
|
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
--source include/have_debug.inc
|
||||||
|
--source include/have_debug_sync.inc
|
||||||
|
--source include/galera_have_debug_sync.inc
|
||||||
|
|
||||||
|
--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
|
||||||
|
|
||||||
|
--connection node_2a
|
||||||
|
--source include/galera_cluster.inc
|
||||||
|
#--source suite/galera/include/galera_have_debug_sync.inc
|
||||||
|
|
||||||
|
#
|
||||||
|
# node 1 is native MariaDB server operating as async replication master
|
||||||
|
#
|
||||||
|
--connection node_1
|
||||||
|
RESET MASTER;
|
||||||
|
|
||||||
|
--connection node_2a
|
||||||
|
#
|
||||||
|
# count the number of wsrep replay's done in the node
|
||||||
|
#
|
||||||
|
--let $wsrep_local_replays_old = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# nodes 2 and 3 form a galera cluster, node 2 operates as slave for native MariaDB naster in node 1
|
||||||
|
#
|
||||||
|
--disable_query_log
|
||||||
|
--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_1;
|
||||||
|
--enable_query_log
|
||||||
|
START SLAVE;
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)) engine=innodb;
|
||||||
|
INSERT INTO t1 VALUES (1, 'a');
|
||||||
|
INSERT INTO t1 VALUES (3, 'a');
|
||||||
|
|
||||||
|
#
|
||||||
|
# use statement format replication to cause a false positive conflict with async replication transaction
|
||||||
|
# and galera replication. The conflict will be on GAP lock, and slave SQL thread should rollback
|
||||||
|
# and replay
|
||||||
|
#
|
||||||
|
set binlog_format=STATEMENT;
|
||||||
|
|
||||||
|
SET AUTOCOMMIT=ON;
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
SELECT * FROM t1 FOR UPDATE;
|
||||||
|
UPDATE t1 SET f2 = 'c' WHERE f1 > 1;
|
||||||
|
|
||||||
|
--connection node_2a
|
||||||
|
# wait for create table and inserts to be replicated from master
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 2 FROM test.t1;
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
# wait for create table and inserts to be replicated in cluster
|
||||||
|
--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
|
||||||
|
--connection node_3
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 2 FROM test.t1;
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
--connection node_2a
|
||||||
|
# Block the future commit of async replication
|
||||||
|
--let $galera_sync_point = commit_monitor_enter_sync
|
||||||
|
--source include/galera_set_sync_point.inc
|
||||||
|
|
||||||
|
# block also the applier before applying begins
|
||||||
|
SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb";
|
||||||
|
|
||||||
|
#
|
||||||
|
# now inject a conflicting insert from node 3, it will replicate with
|
||||||
|
# earlier seqno (than async transaction) and pause before applying in node 2
|
||||||
|
#
|
||||||
|
--connection node_3
|
||||||
|
INSERT INTO test.t1 VALUES (2, 'b');
|
||||||
|
|
||||||
|
#
|
||||||
|
# send the update from master, this will succeed here, beceuase of async replication.
|
||||||
|
# async replication will apply this in node 2 and pause before commit phase,
|
||||||
|
--connection node_1
|
||||||
|
--error 0
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
# Wait until async slave commit is blocked in node_2
|
||||||
|
--connection node_2a
|
||||||
|
--source include/galera_wait_sync_point.inc
|
||||||
|
|
||||||
|
#
|
||||||
|
# release the applier
|
||||||
|
# note: have to clear wsrep_apply_cb sync point first, as async replication will go for replay
|
||||||
|
# and as this sync point, after BF applier is released to progress
|
||||||
|
#
|
||||||
|
SET GLOBAL debug_dbug = "";
|
||||||
|
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
|
||||||
|
|
||||||
|
# Unblock the async slave commit
|
||||||
|
--connection node_2a
|
||||||
|
--source include/galera_clear_sync_point.inc
|
||||||
|
--source include/galera_signal_sync_point.inc
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
|
||||||
|
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a';
|
||||||
|
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
|
||||||
|
--connection node_2a
|
||||||
|
|
||||||
|
# wsrep_local_replays has increased by 1
|
||||||
|
set session wsrep_sync_wait=15;
|
||||||
|
--let $wsrep_local_replays_new = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
|
||||||
|
set session wsrep_sync_wait=0;
|
||||||
|
|
||||||
|
--disable_query_log
|
||||||
|
--eval SELECT $wsrep_local_replays_new - $wsrep_local_replays_old = 1 AS wsrep_local_replays;
|
||||||
|
--enable_query_log
|
||||||
|
|
||||||
|
#
|
||||||
|
# replaying of async transaction should be effective, and row 3 having 'c' in f2
|
||||||
|
#
|
||||||
|
SELECT * FROM t1;
|
||||||
|
SET DEBUG_SYNC = "RESET";
|
||||||
|
|
||||||
|
#********************************************************************************
|
||||||
|
# test phase 2
|
||||||
|
#********************************************************************************
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # test phase with real abort
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
|
||||||
|
set binlog_format=ROW;
|
||||||
|
|
||||||
|
insert into t1 values (4, 'd');
|
||||||
|
|
||||||
|
SET AUTOCOMMIT=ON;
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
UPDATE t1 SET f2 = 'd' WHERE f1 = 3;
|
||||||
|
|
||||||
|
--connection node_2a
|
||||||
|
# wait for the last insert to be replicated from master
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 4 FROM test.t1;
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
# Block the commit
|
||||||
|
--let $galera_sync_point = commit_monitor_enter_sync
|
||||||
|
--source include/galera_set_sync_point.inc
|
||||||
|
|
||||||
|
# block applier
|
||||||
|
SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb";
|
||||||
|
|
||||||
|
# Inject a conflicting update from node 3
|
||||||
|
--connection node_3
|
||||||
|
UPDATE test.t1 SET f2 = 'e' WHERE f1 = 3;
|
||||||
|
|
||||||
|
# send the update from master
|
||||||
|
--connection node_1
|
||||||
|
--error 0
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
--connection node_2a
|
||||||
|
|
||||||
|
# release the applier
|
||||||
|
SET GLOBAL debug_dbug = "";
|
||||||
|
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
|
||||||
|
|
||||||
|
|
||||||
|
# Unblock the async slave commit
|
||||||
|
--connection node_2a
|
||||||
|
--source include/galera_clear_sync_point.inc
|
||||||
|
--source include/galera_signal_sync_point.inc
|
||||||
|
SET DEBUG_SYNC = "RESET";
|
||||||
|
|
||||||
|
--connection node_2a
|
||||||
|
|
||||||
|
set session wsrep_sync_wait=15;
|
||||||
|
SELECT COUNT(*) = 1 FROM test.t1 WHERE f2 = 'e';
|
||||||
|
set session wsrep_sync_wait=0;
|
||||||
|
|
||||||
|
STOP SLAVE;
|
||||||
|
RESET SLAVE;
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
DROP TABLE t1;
|
||||||
|
RESET MASTER;
|
7
mysql-test/suite/galera/t/galera_defaults.cnf
Normal file
7
mysql-test/suite/galera/t/galera_defaults.cnf
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
!include ../galera_2nodes.cnf
|
||||||
|
|
||||||
|
[mysqld.1]
|
||||||
|
wsrep_provider_options='base_port=@mysqld.1.#galera_port;gmcast.segment=1'
|
||||||
|
|
||||||
|
[mysqld.2]
|
||||||
|
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gmcast.segment=1'
|
@ -1,25 +1,24 @@
|
|||||||
#
|
#
|
||||||
# The purpose of this test is to preserve the current state of the following:
|
# The purpose of this test is to preserve the current state of the following:
|
||||||
# * SHOW VARIABLES LIKE 'wsrep%'
|
# * SHOW VARIABLES LIKE 'wsrep%'
|
||||||
# * wsrep_provider_options
|
|
||||||
# * The names of the Galera status variables
|
# * The names of the Galera status variables
|
||||||
#
|
#
|
||||||
|
# Note that wsrep_provider_options contains paths and other non-deterministic parts
|
||||||
|
#
|
||||||
# This way, if there is any change, inadvertent or not, the test will fail and the
|
# This way, if there is any change, inadvertent or not, the test will fail and the
|
||||||
# developer and QA will be alerted.
|
# developer and QA will be alerted.
|
||||||
#
|
#
|
||||||
|
|
||||||
--source include/galera_cluster.inc
|
--source include/galera_cluster.inc
|
||||||
--source include/have_innodb.inc
|
--source include/force_restart.inc
|
||||||
|
|
||||||
# Make sure that the test is operating on the right version of galera library.
|
# Make sure that the test is operating on the right version of galera library.
|
||||||
--disable_query_log
|
--let $galera_version=26.4.6
|
||||||
--let $galera_version=25.3.20
|
|
||||||
source ../wsrep/include/check_galera_version.inc;
|
source ../wsrep/include/check_galera_version.inc;
|
||||||
--enable_query_log
|
|
||||||
|
|
||||||
# Global Variables
|
# Global Variables
|
||||||
|
|
||||||
SELECT COUNT(*) `expect 48` FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
|
SELECT COUNT(*) `expect 49` FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
|
||||||
|
|
||||||
SELECT VARIABLE_NAME, VARIABLE_VALUE
|
SELECT VARIABLE_NAME, VARIABLE_VALUE
|
||||||
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
||||||
|
@ -40,11 +40,19 @@ set wsrep_sync_wait=0;
|
|||||||
|
|
||||||
--let $wait_condition = SELECT COUNT(*) = 2 FROM child;
|
--let $wait_condition = SELECT COUNT(*) = 2 FROM child;
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 2 FROM parent;
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 2 FROM grandparent;
|
||||||
|
--source include/wait_condition.inc
|
||||||
DELETE FROM grandparent WHERE id = 1;
|
DELETE FROM grandparent WHERE id = 1;
|
||||||
|
|
||||||
--connection node_1
|
--connection node_1
|
||||||
--let $wait_condition = SELECT COUNT(*) = 1 FROM child;
|
--let $wait_condition = SELECT COUNT(*) = 1 FROM child;
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 1 FROM parent;
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 1 FROM grandparent;
|
||||||
|
--source include/wait_condition.inc
|
||||||
SELECT COUNT(*), COUNT(*) = 0 FROM parent WHERE grandparent_id = 1;
|
SELECT COUNT(*), COUNT(*) = 0 FROM parent WHERE grandparent_id = 1;
|
||||||
SELECT COUNT(*), COUNT(*) = 0 FROM child WHERE parent_id = 1;
|
SELECT COUNT(*), COUNT(*) = 0 FROM child WHERE parent_id = 1;
|
||||||
|
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
|
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
|
||||||
|
|
||||||
--connection node_2
|
--connection node_2
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
SET SESSION wsrep_OSU_method = "RSU";
|
SET SESSION wsrep_OSU_method = "RSU";
|
||||||
ALTER TABLE t1 ADD COLUMN f2 INTEGER;
|
ALTER TABLE t1 ADD COLUMN f2 INTEGER;
|
||||||
SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
|
SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
--source include/have_innodb.inc
|
--source include/have_innodb.inc
|
||||||
|
|
||||||
--connection node_1
|
--connection node_1
|
||||||
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
|
CREATE TABLE ten (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB;
|
||||||
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
|
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
|
||||||
|
|
||||||
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
|
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
|
||||||
@ -83,6 +83,8 @@ SET GLOBAL auto_increment_offset = 1;
|
|||||||
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
|
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
|
||||||
|
|
||||||
--connection node_2a
|
--connection node_2a
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
ALTER TABLE t1 AUTO_INCREMENT=100;
|
ALTER TABLE t1 AUTO_INCREMENT=100;
|
||||||
|
|
||||||
|
@ -75,6 +75,9 @@ DELETE FROM t1 WHERE f1 = 1;
|
|||||||
--connection node_1
|
--connection node_1
|
||||||
SELECT COUNT(*) as expect_0 FROM t1;
|
SELECT COUNT(*) as expect_0 FROM t1;
|
||||||
--connection node_2
|
--connection node_2
|
||||||
|
--source include/galera_wait_ready.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
|
||||||
|
--source include/wait_condition.inc
|
||||||
SELECT COUNT(*) as expect_0 FROM t1;
|
SELECT COUNT(*) as expect_0 FROM t1;
|
||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
@ -96,6 +99,9 @@ COMMIT;
|
|||||||
--connection node_1
|
--connection node_1
|
||||||
SELECT COUNT(*) as expect_1 FROM t1;
|
SELECT COUNT(*) as expect_1 FROM t1;
|
||||||
--connection node_2
|
--connection node_2
|
||||||
|
--source include/galera_wait_ready.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
|
||||||
|
--source include/wait_condition.inc
|
||||||
SELECT COUNT(*) as expect_1 FROM t1;
|
SELECT COUNT(*) as expect_1 FROM t1;
|
||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
@ -120,6 +126,11 @@ DELETE FROM t1;
|
|||||||
|
|
||||||
SELECT COUNT(*) as expect_0 FROM t1;
|
SELECT COUNT(*) as expect_0 FROM t1;
|
||||||
--connection node_2
|
--connection node_2
|
||||||
|
--source include/galera_wait_ready.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
||||||
|
--source include/wait_condition.inc
|
||||||
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
||||||
SELECT COUNT(*) as expect_0 FROM t1;
|
SELECT COUNT(*) as expect_0 FROM t1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
@ -154,6 +165,11 @@ SET AUTOCOMMIT=ON;
|
|||||||
|
|
||||||
SELECT COUNT(*) as expect_0 FROM t1;
|
SELECT COUNT(*) as expect_0 FROM t1;
|
||||||
--connection node_2
|
--connection node_2
|
||||||
|
--source include/galera_wait_ready.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
||||||
|
--source include/wait_condition.inc
|
||||||
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
||||||
SELECT COUNT(*) as expect_0 FROM t1;
|
SELECT COUNT(*) as expect_0 FROM t1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
@ -183,6 +199,11 @@ DELETE t1, t2 FROM t1 JOIN t2 WHERE t1.f1 = t2.f1;
|
|||||||
SELECT COUNT(*) as expect_0 FROM t1;
|
SELECT COUNT(*) as expect_0 FROM t1;
|
||||||
|
|
||||||
--connection node_2
|
--connection node_2
|
||||||
|
--source include/galera_wait_ready.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
||||||
|
--source include/wait_condition.inc
|
||||||
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
||||||
SELECT COUNT(*) as expect_0 FROM t1;
|
SELECT COUNT(*) as expect_0 FROM t1;
|
||||||
DROP TABLE t1,t2;
|
DROP TABLE t1,t2;
|
||||||
@ -212,6 +233,11 @@ SELECT COUNT(*) as expect_0 FROM parent;
|
|||||||
SELECT COUNT(*) as expect_0 FROM child;
|
SELECT COUNT(*) as expect_0 FROM child;
|
||||||
|
|
||||||
--connection node_2
|
--connection node_2
|
||||||
|
--source include/galera_wait_ready.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
||||||
|
--source include/wait_condition.inc
|
||||||
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
|
||||||
SELECT COUNT(*) as expect_0 FROM parent;
|
SELECT COUNT(*) as expect_0 FROM parent;
|
||||||
SELECT COUNT(*) as expect_0 FROM child;
|
SELECT COUNT(*) as expect_0 FROM child;
|
||||||
|
@ -1,27 +1,35 @@
|
|||||||
connection node_2;
|
connection node_2;
|
||||||
connection node_1;
|
connection node_1;
|
||||||
|
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
|
||||||
|
connect node_1_ctrl, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||||
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
|
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
|
||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
connection node_3;
|
connection node_3;
|
||||||
SET GLOBAL wsrep_slave_threads = 2;
|
SET GLOBAL wsrep_slave_threads = 2;
|
||||||
|
connection node_1_ctrl;
|
||||||
|
SET SESSION wsrep_sync_wait=0;
|
||||||
connection node_1;
|
connection node_1;
|
||||||
|
SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue';
|
||||||
UPDATE t1 SET f1 = f1 + 10;;
|
UPDATE t1 SET f1 = f1 + 10;;
|
||||||
|
connection node_1_ctrl;
|
||||||
|
SET DEBUG_SYNC = 'now WAIT_FOR before_cert';
|
||||||
|
SET GLOBAL debug_dbug = '+d,sync.wsrep_retry_autocommit';
|
||||||
connection node_2;
|
connection node_2;
|
||||||
UPDATE t1 SET f1 = f1 + 100;;
|
UPDATE t1 SET f1 = f1 + 100;;
|
||||||
|
connection node_1_ctrl;
|
||||||
|
SET DEBUG_SYNC = 'now WAIT_FOR wsrep_retry_autocommit_reached';
|
||||||
|
SET GLOBAL debug_dbug = NULL;
|
||||||
|
SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue';
|
||||||
connection node_1;
|
connection node_1;
|
||||||
SELECT COUNT(*) FROM t1;
|
|
||||||
COUNT(*)
|
|
||||||
1
|
|
||||||
connection node_2;
|
connection node_2;
|
||||||
SELECT COUNT(*) FROM t1;
|
|
||||||
COUNT(*)
|
|
||||||
1
|
|
||||||
connection node_3;
|
connection node_3;
|
||||||
SELECT COUNT(*) FROM t1;
|
SELECT f1 = 111 FROM t1;
|
||||||
COUNT(*)
|
f1 = 111
|
||||||
1
|
1
|
||||||
SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%';
|
SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%';
|
||||||
COUNT(*) IN (1, 2)
|
COUNT(*) IN (1, 2)
|
||||||
1
|
1
|
||||||
SET GLOBAL wsrep_slave_threads = 1;;
|
SET GLOBAL wsrep_slave_threads = DEFAULT;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
connection node_1;
|
||||||
|
SET DEBUG_SYNC= 'RESET';
|
||||||
|
@ -5,46 +5,71 @@
|
|||||||
|
|
||||||
--source include/galera_cluster.inc
|
--source include/galera_cluster.inc
|
||||||
--source include/have_innodb.inc
|
--source include/have_innodb.inc
|
||||||
|
--source include/have_debug.inc
|
||||||
|
--source include/have_debug_sync.inc
|
||||||
|
|
||||||
--let $galera_connection_name = node_3
|
--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
|
||||||
--let $galera_server_number = 3
|
--connect node_1_ctrl, 127.0.0.1, root, , test, $NODE_MYPORT_1
|
||||||
--source include/galera_connect.inc
|
|
||||||
|
|
||||||
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
|
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
|
||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
|
|
||||||
|
--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
|
||||||
|
|
||||||
--connection node_3
|
--connection node_3
|
||||||
--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
|
|
||||||
SET GLOBAL wsrep_slave_threads = 2;
|
SET GLOBAL wsrep_slave_threads = 2;
|
||||||
|
|
||||||
|
--connection node_1_ctrl
|
||||||
|
SET SESSION wsrep_sync_wait=0;
|
||||||
|
|
||||||
|
#
|
||||||
|
# We will make the following UPDATE depend on the UPDATE below
|
||||||
|
#
|
||||||
--connection node_1
|
--connection node_1
|
||||||
|
SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue';
|
||||||
--send UPDATE t1 SET f1 = f1 + 10;
|
--send UPDATE t1 SET f1 = f1 + 10;
|
||||||
|
|
||||||
|
--connection node_1_ctrl
|
||||||
|
SET DEBUG_SYNC = 'now WAIT_FOR before_cert';
|
||||||
|
SET GLOBAL debug_dbug = '+d,sync.wsrep_retry_autocommit';
|
||||||
|
|
||||||
--connection node_2
|
--connection node_2
|
||||||
--send UPDATE t1 SET f1 = f1 + 100;
|
--send UPDATE t1 SET f1 = f1 + 100;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Let's wait for the first UPDATE the be BF aborted
|
||||||
|
#
|
||||||
|
--connection node_1_ctrl
|
||||||
|
SET DEBUG_SYNC = 'now WAIT_FOR wsrep_retry_autocommit_reached';
|
||||||
|
|
||||||
|
#
|
||||||
|
# and make sure the second has committed
|
||||||
|
#
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE > $wsrep_last_committed_before FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
#
|
||||||
|
# now release the first UPDATE.
|
||||||
|
#
|
||||||
|
SET GLOBAL debug_dbug = NULL;
|
||||||
|
SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue';
|
||||||
|
|
||||||
|
#
|
||||||
|
# Both UPDATEs should succeed.
|
||||||
|
#
|
||||||
--connection node_1
|
--connection node_1
|
||||||
#
|
|
||||||
# Note that test is not deterministic. We have following cases possible
|
|
||||||
# (1) Both updates are certified locally and then executed by the applier
|
|
||||||
# (2) Certification of update in node_1 fails because applier has started
|
|
||||||
# update from node_2
|
|
||||||
# (3) Certification of update in node_2 fails because applier has started
|
|
||||||
# update from node_1
|
|
||||||
#
|
|
||||||
--error 0,ER_LOCK_DEADLOCK
|
|
||||||
--reap
|
--reap
|
||||||
SELECT COUNT(*) FROM t1;
|
|
||||||
|
|
||||||
--connection node_2
|
--connection node_2
|
||||||
--error 0,ER_LOCK_DEADLOCK
|
|
||||||
--reap
|
--reap
|
||||||
SELECT COUNT(*) FROM t1;
|
|
||||||
|
|
||||||
--connection node_3
|
--connection node_3
|
||||||
SELECT COUNT(*) FROM t1;
|
SELECT f1 = 111 FROM t1;
|
||||||
SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%';
|
SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%';
|
||||||
|
|
||||||
--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
|
SET GLOBAL wsrep_slave_threads = DEFAULT;
|
||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
SET DEBUG_SYNC= 'RESET';
|
||||||
|
@ -409,6 +409,7 @@ CREATE TABLE x AS SELECT * FROM t1;
|
|||||||
ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state
|
ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state
|
||||||
connect con1,localhost,root,,test;
|
connect con1,localhost,root,,test;
|
||||||
SET foreign_key_checks= OFF, innodb_lock_wait_timeout= 1;
|
SET foreign_key_checks= OFF, innodb_lock_wait_timeout= 1;
|
||||||
|
SET lock_wait_timeout=5;
|
||||||
ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE;
|
ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE;
|
||||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
@ -74,7 +74,6 @@ DELETE FROM t1;
|
|||||||
# Kill the server
|
# Kill the server
|
||||||
disconnect ddl;
|
disconnect ddl;
|
||||||
# restart
|
# restart
|
||||||
SET @saved_frequency= @@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
|
||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
FOUND 3 /\[Note\] InnoDB: Rolled back recovered transaction / in mysqld.1.err
|
FOUND 3 /\[Note\] InnoDB: Rolled back recovered transaction / in mysqld.1.err
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
@ -138,6 +137,23 @@ header=0x080008030000 (id=0x000000000000000100)
|
|||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
DELETE FROM t2;
|
DELETE FROM t2;
|
||||||
InnoDB 0 transactions not purged
|
InnoDB 0 transactions not purged
|
||||||
|
#
|
||||||
|
# MDEV-24323 Crash on recovery after kill during instant ADD COLUMN
|
||||||
|
#
|
||||||
|
connect ddl, localhost, root;
|
||||||
|
CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2))
|
||||||
|
ENGINE=InnoDB;
|
||||||
|
INSERT INTO t3 SET id=1,c2=1;
|
||||||
|
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
|
||||||
|
ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi';
|
||||||
|
connection default;
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||||
|
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||||
|
SET debug_dbug='+d,dict_sys_mutex_avoid';
|
||||||
|
INSERT INTO t1 VALUES(0,0);
|
||||||
|
# Kill the server
|
||||||
|
disconnect ddl;
|
||||||
|
# restart
|
||||||
SHOW CREATE TABLE t1;
|
SHOW CREATE TABLE t1;
|
||||||
Table Create Table
|
Table Create Table
|
||||||
t1 CREATE TABLE `t1` (
|
t1 CREATE TABLE `t1` (
|
||||||
@ -154,6 +170,14 @@ t2 CREATE TABLE `t2` (
|
|||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `c2` (`c2`)
|
UNIQUE KEY `c2` (`c2`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT
|
||||||
DROP TABLE t1,t2;
|
SHOW CREATE TABLE t3;
|
||||||
|
Table Create Table
|
||||||
|
t3 CREATE TABLE `t3` (
|
||||||
|
`id` int(11) NOT NULL,
|
||||||
|
`c2` int(11) DEFAULT NULL,
|
||||||
|
`v2` int(11) GENERATED ALWAYS AS (`c2`) VIRTUAL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `v2` (`v2`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
db.opt
|
db.opt
|
||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency=@saved_frequency;
|
|
||||||
|
@ -414,6 +414,7 @@ INSERT INTO t1 VALUES (1,2);
|
|||||||
CREATE TABLE x AS SELECT * FROM t1;
|
CREATE TABLE x AS SELECT * FROM t1;
|
||||||
--connect (con1,localhost,root,,test)
|
--connect (con1,localhost,root,,test)
|
||||||
SET foreign_key_checks= OFF, innodb_lock_wait_timeout= 1;
|
SET foreign_key_checks= OFF, innodb_lock_wait_timeout= 1;
|
||||||
|
SET lock_wait_timeout=5;
|
||||||
--error ER_LOCK_WAIT_TIMEOUT
|
--error ER_LOCK_WAIT_TIMEOUT
|
||||||
ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE;# Cleanup
|
ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE;# Cleanup
|
||||||
--disconnect con1
|
--disconnect con1
|
||||||
|
@ -91,7 +91,6 @@ DELETE FROM t1;
|
|||||||
disconnect ddl;
|
disconnect ddl;
|
||||||
--source include/start_mysqld.inc
|
--source include/start_mysqld.inc
|
||||||
|
|
||||||
SET @saved_frequency= @@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
|
||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
|
|
||||||
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
|
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
|
||||||
@ -177,11 +176,32 @@ UNLOCK TABLES;
|
|||||||
DELETE FROM t2;
|
DELETE FROM t2;
|
||||||
--source include/wait_all_purged.inc
|
--source include/wait_all_purged.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-24323 Crash on recovery after kill during instant ADD COLUMN
|
||||||
|
--echo #
|
||||||
|
connect ddl, localhost, root;
|
||||||
|
CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2))
|
||||||
|
ENGINE=InnoDB;
|
||||||
|
INSERT INTO t3 SET id=1,c2=1;
|
||||||
|
|
||||||
|
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
|
||||||
|
--send
|
||||||
|
ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi';
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||||
|
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||||
|
SET debug_dbug='+d,dict_sys_mutex_avoid';
|
||||||
|
INSERT INTO t1 VALUES(0,0);
|
||||||
|
|
||||||
|
--source include/kill_mysqld.inc
|
||||||
|
disconnect ddl;
|
||||||
|
--source include/start_mysqld.inc
|
||||||
|
|
||||||
SHOW CREATE TABLE t1;
|
SHOW CREATE TABLE t1;
|
||||||
SHOW CREATE TABLE t2;
|
SHOW CREATE TABLE t2;
|
||||||
DROP TABLE t1,t2;
|
SHOW CREATE TABLE t3;
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
|
||||||
--remove_files_wildcard $MYSQLD_DATADIR/test #sql*.frm
|
--remove_files_wildcard $MYSQLD_DATADIR/test #sql*.frm
|
||||||
--list_files $MYSQLD_DATADIR/test
|
--list_files $MYSQLD_DATADIR/test
|
||||||
|
|
||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency=@saved_frequency;
|
|
||||||
|
1
mysql-test/suite/maria/create.opt
Normal file
1
mysql-test/suite/maria/create.opt
Normal file
@ -0,0 +1 @@
|
|||||||
|
--symbolic-links=1
|
146
mysql-test/suite/mariabackup/include/corrupt-page.pl
Normal file
146
mysql-test/suite/mariabackup/include/corrupt-page.pl
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Fcntl qw(:DEFAULT :seek);
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl";
|
||||||
|
|
||||||
|
sub corrupt_space_page_id {
|
||||||
|
my $file_name = shift;
|
||||||
|
my @pages_to_corrupt = @_;
|
||||||
|
|
||||||
|
my $page_size = $ENV{INNODB_PAGE_SIZE};
|
||||||
|
|
||||||
|
sysopen my $ibd_file, $file_name, O_RDWR || die "Cannot open $file_name\n";
|
||||||
|
sysread($ibd_file, $_, 38) || die "Cannot read $file_name\n";
|
||||||
|
my $space = unpack("x[34]N", $_);
|
||||||
|
foreach my $page_no (@pages_to_corrupt) {
|
||||||
|
$space += 10; # generate wrong space id
|
||||||
|
sysseek($ibd_file, $page_size * $page_no, SEEK_SET)
|
||||||
|
|| die "Cannot seek $file_name\n";
|
||||||
|
|
||||||
|
my $head = pack("Nx[18]", $page_no + 10); # generate wrong page number
|
||||||
|
my $body = chr(0) x ($page_size - 38 - 8);
|
||||||
|
|
||||||
|
# Calculate innodb_checksum_algorithm=crc32 for the unencrypted page.
|
||||||
|
# The following bytes are excluded:
|
||||||
|
# bytes 0..3 (the checksum is stored there)
|
||||||
|
# bytes 26..37 (encryption key version, post-encryption checksum, tablespace id)
|
||||||
|
# bytes $page_size-8..$page_size-1 (checksum, LSB of FIL_PAGE_LSN)
|
||||||
|
my $polynomial = 0x82f63b78; # CRC-32C
|
||||||
|
my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial);
|
||||||
|
|
||||||
|
my $page= pack("N",$ck).$head.pack("NNN",1,$ck,$space).$body.pack("Nx[4]",$ck);
|
||||||
|
die unless syswrite($ibd_file, $page, $page_size) == $page_size;
|
||||||
|
}
|
||||||
|
close $ibd_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub extend_space {
|
||||||
|
my $file_name = shift;
|
||||||
|
my $n_pages = shift;
|
||||||
|
|
||||||
|
my $page_size = $ENV{INNODB_PAGE_SIZE};
|
||||||
|
my $page;
|
||||||
|
|
||||||
|
sysopen my $ibd_file, $file_name, O_RDWR || die "Cannot open $file_name\n";
|
||||||
|
sysread($ibd_file, $page, $page_size)
|
||||||
|
|| die "Cannot read $file_name\n";
|
||||||
|
my $size = unpack("N", substr($page, 46, 4));
|
||||||
|
my $packed_new_size = pack("N", $size + $n_pages);
|
||||||
|
substr($page, 46, 4, $packed_new_size);
|
||||||
|
|
||||||
|
my $head = substr($page, 4, 22);
|
||||||
|
my $body = substr($page, 38, $page_size - 38 - 8);
|
||||||
|
my $polynomial = 0x82f63b78; # CRC-32C
|
||||||
|
my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial);
|
||||||
|
my $packed_ck = pack("N", $ck);
|
||||||
|
substr($page, 0, 4, $packed_ck);
|
||||||
|
substr($page, $page_size - 8, 4, $packed_ck);
|
||||||
|
|
||||||
|
sysseek($ibd_file, 0, SEEK_SET)
|
||||||
|
|| die "Cannot seek $file_name\n";
|
||||||
|
die unless syswrite($ibd_file, $page, $page_size) == $page_size;
|
||||||
|
|
||||||
|
sysseek($ibd_file, 0, SEEK_END)
|
||||||
|
|| die "Cannot seek $file_name\n";
|
||||||
|
my $pages_size = $page_size*$n_pages;
|
||||||
|
my $pages = chr(0) x $pages_size;
|
||||||
|
die unless syswrite($ibd_file, $pages, $pages_size) == $pages_size;
|
||||||
|
close $ibd_file;
|
||||||
|
return $size;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub die_if_page_is_not_zero {
|
||||||
|
my $file_name = shift;
|
||||||
|
my @pages_to_check = @_;
|
||||||
|
|
||||||
|
no locale;
|
||||||
|
my $page_size = $ENV{INNODB_PAGE_SIZE};
|
||||||
|
my $zero_page = chr(0) x $page_size;
|
||||||
|
sysopen my $ibd_file, $file_name, O_RDWR || die "Cannot open $file_name\n";
|
||||||
|
foreach my $page_no_to_check (@pages_to_check) {
|
||||||
|
sysseek($ibd_file, $page_size*$page_no_to_check, SEEK_SET) ||
|
||||||
|
die "Cannot seek $file_name\n";
|
||||||
|
sysread($ibd_file, my $read_page, $page_size) ||
|
||||||
|
die "Cannot read $file_name\n";
|
||||||
|
die "The page $page_no_to_check is not zero-filed in $file_name"
|
||||||
|
if ($read_page cmp $zero_page);
|
||||||
|
}
|
||||||
|
close $ibd_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub print_corrupted_pages_file {
|
||||||
|
my $file_in = shift;
|
||||||
|
my $file_out = shift;
|
||||||
|
open my $fh, '<', $file_in || die $!;
|
||||||
|
my $line_number = 0;
|
||||||
|
my $space = {};
|
||||||
|
my @spaces;
|
||||||
|
while (my $line = <$fh>) {
|
||||||
|
++$line_number;
|
||||||
|
if ($line_number & 1) {
|
||||||
|
my ($name, $id) = split(/ /, $line);
|
||||||
|
$space->{name} = $name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$space->{pages} = $line;
|
||||||
|
push (@spaces, $space);
|
||||||
|
$space = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close $fh;
|
||||||
|
my @sorted_spaces = sort { $a->{name} cmp $b->{name} } @spaces;
|
||||||
|
open $fh, '>', $file_out || die $!;
|
||||||
|
foreach my $space (@sorted_spaces) {
|
||||||
|
print $fh $space->{name};
|
||||||
|
print $fh "\n";
|
||||||
|
print $fh $space->{pages};
|
||||||
|
}
|
||||||
|
close $fh;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub append_corrupted_pages {
|
||||||
|
my $file_name = shift;
|
||||||
|
my $space_name = shift;
|
||||||
|
my $pages = shift;
|
||||||
|
open my $fh, '<', $file_name || die $!;
|
||||||
|
my $line_number = 0;
|
||||||
|
my $space_line;
|
||||||
|
while (my $line = <$fh>) {
|
||||||
|
++$line_number;
|
||||||
|
if ($line_number & 1) {
|
||||||
|
my ($name, $id) = split(/ /, $line);
|
||||||
|
if ($name eq $space_name) {
|
||||||
|
$space_line = $line;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close $fh;
|
||||||
|
if (not defined $space_line) {
|
||||||
|
die "Can't find requested space $space_name in file $file_name";
|
||||||
|
}
|
||||||
|
open $fh, '>>', $file_name || die $!;
|
||||||
|
print $fh $space_line;
|
||||||
|
print $fh "$pages\n";
|
||||||
|
close $fh;
|
||||||
|
}
|
@ -22,7 +22,7 @@ INSERT into t1 values(1);
|
|||||||
--let after_copy_test_t2=DROP TABLE test.t2
|
--let after_copy_test_t2=DROP TABLE test.t2
|
||||||
--let after_copy_test_t3=CREATE INDEX a_i ON test.t3(i);
|
--let after_copy_test_t3=CREATE INDEX a_i ON test.t3(i);
|
||||||
--let before_copy_test_t10=DROP TABLE test.t10
|
--let before_copy_test_t10=DROP TABLE test.t10
|
||||||
--let wait_innodb_redo_before_copy=test/t10
|
--let wait_innodb_redo_before_copy_test_t10 = 1
|
||||||
|
|
||||||
# mariabackup should crash with assertion if MDEV-24026 is not fixed
|
# mariabackup should crash with assertion if MDEV-24026 is not fixed
|
||||||
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir --dbug=+d,mariabackup_events,mariabackup_inject_code;
|
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir --dbug=+d,mariabackup_events,mariabackup_inject_code;
|
||||||
|
1
mysql-test/suite/mariabackup/log_page_corruption.opt
Normal file
1
mysql-test/suite/mariabackup/log_page_corruption.opt
Normal file
@ -0,0 +1 @@
|
|||||||
|
--innodb-checksum-algorithm=crc32
|
145
mysql-test/suite/mariabackup/log_page_corruption.result
Normal file
145
mysql-test/suite/mariabackup/log_page_corruption.result
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
########
|
||||||
|
# Test for generating "innodb_corrupted_pages" file during full and
|
||||||
|
# incremental backup, including DDL processing
|
||||||
|
###
|
||||||
|
|
||||||
|
CREATE TABLE t1_corrupted(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t2_corrupted(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t3(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t5_corrupted_to_rename(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t6_corrupted_to_drop(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t7_corrupted_to_alter(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t1_inc_corrupted(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t2_inc_corrupted(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t3_inc(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t5_inc_corrupted_to_rename(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t6_inc_corrupted_to_drop(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t7_inc_corrupted_to_alter(c INT) ENGINE INNODB;
|
||||||
|
INSERT INTO t1_corrupted VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t2_corrupted VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t3 VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t5_corrupted_to_rename VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t6_corrupted_to_drop VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t7_corrupted_to_alter VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
# Corrupt tables
|
||||||
|
# restart
|
||||||
|
# Backup must fail due to page corruption
|
||||||
|
FOUND 1 /Database page corruption detected.*/ in backup.log
|
||||||
|
# "innodb_corrupted_pages" file must not exist
|
||||||
|
# Backup must fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option
|
||||||
|
FOUND 1 /Database page corruption detected.*/ in backup.log
|
||||||
|
--- "innodb_corrupted_pages" file content: ---
|
||||||
|
test/t1_corrupted
|
||||||
|
6 8 9
|
||||||
|
test/t2_corrupted
|
||||||
|
7 8 10
|
||||||
|
test/t4_corrupted_new
|
||||||
|
1
|
||||||
|
test/t5_corrupted_to_rename_renamed
|
||||||
|
6
|
||||||
|
test/t7_corrupted_to_alter
|
||||||
|
3
|
||||||
|
------
|
||||||
|
INSERT INTO t1_inc_corrupted VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t2_inc_corrupted VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t3_inc VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
# restart
|
||||||
|
# Backup must fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option
|
||||||
|
--- "innodb_corrupted_pages" file content: ---
|
||||||
|
test/t1_corrupted
|
||||||
|
6 8 9
|
||||||
|
test/t1_inc_corrupted
|
||||||
|
6 8 9
|
||||||
|
test/t2_corrupted
|
||||||
|
7 8 10
|
||||||
|
test/t2_inc_corrupted
|
||||||
|
7 8 10
|
||||||
|
test/t4_inc_corrupted_new
|
||||||
|
1
|
||||||
|
test/t5_corrupted_to_rename_renamed
|
||||||
|
6
|
||||||
|
test/t5_inc_corrupted_to_rename_renamed
|
||||||
|
6
|
||||||
|
test/t7_inc_corrupted_to_alter
|
||||||
|
3
|
||||||
|
------
|
||||||
|
# Check if corrupted pages were copied to delta files, and non-corrupted pages are not copied.
|
||||||
|
DROP TABLE t1_corrupted;
|
||||||
|
DROP TABLE t2_corrupted;
|
||||||
|
DROP TABLE t4_corrupted_new;
|
||||||
|
DROP TABLE t5_corrupted_to_rename_renamed;
|
||||||
|
DROP TABLE t7_corrupted_to_alter;
|
||||||
|
DROP TABLE t1_inc_corrupted;
|
||||||
|
DROP TABLE t2_inc_corrupted;
|
||||||
|
DROP TABLE t4_inc_corrupted_new;
|
||||||
|
DROP TABLE t5_inc_corrupted_to_rename_renamed;
|
||||||
|
DROP TABLE t7_inc_corrupted_to_alter;
|
||||||
|
|
||||||
|
########
|
||||||
|
# Test for --prepare with "innodb_corrupted_pages" file
|
||||||
|
###
|
||||||
|
|
||||||
|
# Extend some tablespace and corrupt extended pages for full backup
|
||||||
|
# restart
|
||||||
|
# Full backup with --log-innodb-page-corruption
|
||||||
|
--- "innodb_corrupted_pages" file content: ---
|
||||||
|
test/t3
|
||||||
|
6 8
|
||||||
|
------
|
||||||
|
# Extend some tablespace and corrupt extended pages for incremental backup
|
||||||
|
# restart
|
||||||
|
# Incremental backup --log-innodb-page-corruption
|
||||||
|
--- "innodb_corrupted_pages" file content: ---
|
||||||
|
test/t3
|
||||||
|
6 8
|
||||||
|
test/t3_inc
|
||||||
|
6 8
|
||||||
|
------
|
||||||
|
# Full backup prepare
|
||||||
|
# "innodb_corrupted_pages" file must not exist after successful prepare
|
||||||
|
FOUND 1 /was successfuly fixed.*/ in backup.log
|
||||||
|
# Check that fixed pages are zero-filled
|
||||||
|
# Incremental backup prepare
|
||||||
|
# "innodb_corrupted_pages" file must not exist after successful prepare
|
||||||
|
# do not remove "innodb_corrupted_pages" in incremental dir
|
||||||
|
FOUND 1 /was successfuly fixed.*/ in backup.log
|
||||||
|
# Check that fixed pages are zero-filled
|
||||||
|
# shutdown server
|
||||||
|
# remove datadir
|
||||||
|
# xtrabackup move back
|
||||||
|
# restart
|
||||||
|
SELECT * FROM t3;
|
||||||
|
c
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8
|
||||||
|
9
|
||||||
|
SELECT * FROM t3_inc;
|
||||||
|
c
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8
|
||||||
|
9
|
||||||
|
# Test the case when not all corrupted pages are fixed
|
||||||
|
|
||||||
|
# Add some fake corrupted pages
|
||||||
|
# Full backup prepare
|
||||||
|
FOUND 1 /Error: corrupted page.*/ in backup.log
|
||||||
|
--- "innodb_corrupted_pages" file content: ---
|
||||||
|
test/t3
|
||||||
|
3
|
||||||
|
------
|
||||||
|
# Incremental backup prepare
|
||||||
|
FOUND 1 /Error: corrupted page.*/ in backup.log
|
||||||
|
--- "innodb_corrupted_pages" file content: ---
|
||||||
|
test/t3
|
||||||
|
3
|
||||||
|
------
|
||||||
|
DROP TABLE t3;
|
||||||
|
DROP TABLE t3_inc;
|
426
mysql-test/suite/mariabackup/log_page_corruption.test
Normal file
426
mysql-test/suite/mariabackup/log_page_corruption.test
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
--source include/have_debug.inc
|
||||||
|
|
||||||
|
--echo ########
|
||||||
|
--echo # Test for generating "innodb_corrupted_pages" file during full and
|
||||||
|
--echo # incremental backup, including DDL processing
|
||||||
|
--echo ###
|
||||||
|
--echo
|
||||||
|
|
||||||
|
CREATE TABLE t1_corrupted(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t2_corrupted(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t3(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t5_corrupted_to_rename(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t6_corrupted_to_drop(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t7_corrupted_to_alter(c INT) ENGINE INNODB;
|
||||||
|
|
||||||
|
CREATE TABLE t1_inc_corrupted(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t2_inc_corrupted(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t3_inc(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t5_inc_corrupted_to_rename(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t6_inc_corrupted_to_drop(c INT) ENGINE INNODB;
|
||||||
|
CREATE TABLE t7_inc_corrupted_to_alter(c INT) ENGINE INNODB;
|
||||||
|
|
||||||
|
# Fill tables with several pages
|
||||||
|
INSERT INTO t1_corrupted VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t2_corrupted VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t3 VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t5_corrupted_to_rename VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t6_corrupted_to_drop VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t7_corrupted_to_alter VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
|
||||||
|
--let MYSQLD_DATADIR=`select @@datadir`
|
||||||
|
--let INNODB_PAGE_SIZE=`select @@innodb_page_size`
|
||||||
|
|
||||||
|
--source include/shutdown_mysqld.inc
|
||||||
|
--echo # Corrupt tables
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
my $schema = "$ENV{MYSQLD_DATADIR}/test";
|
||||||
|
|
||||||
|
my $last_page_no = extend_space("$schema/t1_corrupted.ibd", 4);
|
||||||
|
corrupt_space_page_id("$schema/t1_corrupted.ibd",
|
||||||
|
$last_page_no, $last_page_no + 2, $last_page_no + 3);
|
||||||
|
|
||||||
|
$last_page_no = extend_space("$schema/t2_corrupted.ibd", 5);
|
||||||
|
corrupt_space_page_id("$schema/t2_corrupted.ibd",
|
||||||
|
$last_page_no + 1, $last_page_no + 2, $last_page_no + 4);
|
||||||
|
|
||||||
|
$last_page_no = extend_space("$schema/t5_corrupted_to_rename.ibd", 1);
|
||||||
|
corrupt_space_page_id("$schema/t5_corrupted_to_rename.ibd", $last_page_no);
|
||||||
|
|
||||||
|
$last_page_no = extend_space("$schema/t6_corrupted_to_drop.ibd", );
|
||||||
|
corrupt_space_page_id("$schema/t6_corrupted_to_drop.ibd", $last_page_no);
|
||||||
|
EOF
|
||||||
|
--source include/start_mysqld.inc
|
||||||
|
|
||||||
|
--let targetdir=$MYSQLTEST_VARDIR/tmp/backup
|
||||||
|
--let $backuplog=$MYSQLTEST_VARDIR/tmp/backup.log
|
||||||
|
--let corrupted_pages_file = $targetdir/innodb_corrupted_pages
|
||||||
|
--let corrupted_pages_file_filt = $MYSQLTEST_VARDIR/tmp/innodb_corrupted_pages_filt
|
||||||
|
--let perl_result_file=$MYSQLTEST_VARDIR/tmp/perl_result
|
||||||
|
|
||||||
|
--echo # Backup must fail due to page corruption
|
||||||
|
--disable_result_log
|
||||||
|
--error 1
|
||||||
|
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir > $backuplog;
|
||||||
|
--enable_result_log
|
||||||
|
|
||||||
|
--let SEARCH_PATTERN=Database page corruption detected.*
|
||||||
|
--let SEARCH_FILE=$backuplog
|
||||||
|
--source include/search_pattern_in_file.inc
|
||||||
|
--echo # "innodb_corrupted_pages" file must not exist
|
||||||
|
--error 1
|
||||||
|
--file_exists $corrupted_pages_file
|
||||||
|
--rmdir $targetdir
|
||||||
|
|
||||||
|
--let after_load_tablespaces=CREATE TABLE test.t4_corrupted_new ENGINE=INNODB SELECT UUID() from test.seq_1_to_10
|
||||||
|
--let add_corrupted_page_for_test_t4_corrupted_new=1
|
||||||
|
--let after_copy_test_t5_corrupted_to_rename=RENAME TABLE test.t5_corrupted_to_rename TO test.t5_corrupted_to_rename_renamed
|
||||||
|
--let after_copy_test_t6_corrupted_to_drop=DROP TABLE test.t6_corrupted_to_drop
|
||||||
|
--let after_copy_test_t7_corrupted_to_alter=ALTER TABLE test.t7_corrupted_to_alter ADD COLUMN (d INT)
|
||||||
|
--let add_corrupted_page_for_test_t7_corrupted_to_alter=3
|
||||||
|
|
||||||
|
--echo # Backup must fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option
|
||||||
|
--disable_result_log
|
||||||
|
--error 1
|
||||||
|
--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --log-innodb-page-corruption --target-dir=$targetdir --dbug=+d,mariabackup_events,mariabackup_inject_code > $backuplog
|
||||||
|
--enable_result_log
|
||||||
|
|
||||||
|
--let SEARCH_PATTERN=Database page corruption detected.*
|
||||||
|
--let SEARCH_FILE=$backuplog
|
||||||
|
--source include/search_pattern_in_file.inc
|
||||||
|
--echo --- "innodb_corrupted_pages" file content: ---
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
print_corrupted_pages_file($ENV{corrupted_pages_file},
|
||||||
|
$ENV{corrupted_pages_file_filt});
|
||||||
|
EOF
|
||||||
|
--cat_file $corrupted_pages_file_filt
|
||||||
|
--echo ------
|
||||||
|
--let after_load_tablespaces=
|
||||||
|
--let add_corrupted_page_for_test_t4_corrupted_new=
|
||||||
|
--let after_copy_test_t5_corrupted_to_rename=
|
||||||
|
--let after_copy_test_t6_corrupted_to_drop=
|
||||||
|
--let after_copy_test_t7_corrupted_to_alter=
|
||||||
|
--let add_corrupted_page_for_test_t7_corrupted_to_alter=
|
||||||
|
# Fill tables for incremental backup with several pages
|
||||||
|
INSERT INTO t1_inc_corrupted VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t2_inc_corrupted VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
INSERT INTO t3_inc VALUES (3), (4), (5), (6), (7), (8), (9);
|
||||||
|
|
||||||
|
--source include/shutdown_mysqld.inc
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
my $schema="$ENV{MYSQLD_DATADIR}/test";
|
||||||
|
|
||||||
|
open(my $fh, '>', $ENV{perl_result_file}) or die $!;
|
||||||
|
|
||||||
|
my $last_page_no = extend_space("$schema/t1_inc_corrupted.ibd", 4);
|
||||||
|
corrupt_space_page_id("$schema/t1_inc_corrupted.ibd",
|
||||||
|
$last_page_no, $last_page_no + 2, $last_page_no + 3);
|
||||||
|
print $fh "$last_page_no\n";
|
||||||
|
|
||||||
|
$last_page_no = extend_space("$schema/t2_inc_corrupted.ibd", 5);
|
||||||
|
corrupt_space_page_id("$schema/t2_inc_corrupted.ibd",
|
||||||
|
$last_page_no + 1, $last_page_no + 2, $last_page_no + 4);
|
||||||
|
print $fh "$last_page_no\n";
|
||||||
|
|
||||||
|
$last_page_no = extend_space("$schema/t5_inc_corrupted_to_rename.ibd", 1);
|
||||||
|
corrupt_space_page_id("$schema/t5_inc_corrupted_to_rename.ibd", $last_page_no);
|
||||||
|
print $fh "$last_page_no\n";
|
||||||
|
|
||||||
|
$last_page_no = extend_space("$schema/t6_inc_corrupted_to_drop.ibd", );
|
||||||
|
corrupt_space_page_id("$schema/t6_inc_corrupted_to_drop.ibd", $last_page_no);
|
||||||
|
|
||||||
|
close $fh;
|
||||||
|
EOF
|
||||||
|
--source include/start_mysqld.inc
|
||||||
|
|
||||||
|
--let incdir=$MYSQLTEST_VARDIR/tmp/backup_inc
|
||||||
|
|
||||||
|
--let after_load_tablespaces=CREATE TABLE test.t4_inc_corrupted_new ENGINE=INNODB SELECT UUID() from test.seq_1_to_10
|
||||||
|
--let add_corrupted_page_for_test_t4_inc_corrupted_new=1
|
||||||
|
--let after_copy_test_t5_inc_corrupted_to_rename=RENAME TABLE test.t5_inc_corrupted_to_rename TO test.t5_inc_corrupted_to_rename_renamed
|
||||||
|
--let after_copy_test_t6_inc_corrupted_to_drop=DROP TABLE test.t6_inc_corrupted_to_drop
|
||||||
|
--let after_copy_test_t7_inc_corrupted_to_alter=ALTER TABLE test.t7_inc_corrupted_to_alter ADD COLUMN (d INT)
|
||||||
|
--let add_corrupted_page_for_test_t7_inc_corrupted_to_alter=3
|
||||||
|
|
||||||
|
--echo # Backup must fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option
|
||||||
|
--disable_result_log
|
||||||
|
--error 1
|
||||||
|
--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --log-innodb-page-corruption --target-dir=$incdir --incremental-basedir=$targetdir --dbug=+d,mariabackup_events,mariabackup_inject_code > $backuplog
|
||||||
|
--disable_result_log
|
||||||
|
|
||||||
|
--let after_load_tablespaces=
|
||||||
|
--let add_corrupted_page_for_test_t4_inc_corrupted_new=
|
||||||
|
--let after_copy_test_t5_inc_corrupted_to_rename=
|
||||||
|
--let after_copy_test_t6_inc_corrupted_to_drop=
|
||||||
|
--let after_copy_test_t7_inc_corrupted_to_alter=
|
||||||
|
--let add_corrupted_page_for_test_t7_inc_corrupted_to_alter=
|
||||||
|
|
||||||
|
--let SEARCH_PATTERN=Database page corruption detected.*
|
||||||
|
--let SEARCH_FILE=$backuplog
|
||||||
|
--source include/search_pattern_in_file.inc
|
||||||
|
--let corrupted_pages_file = $incdir/innodb_corrupted_pages
|
||||||
|
--echo --- "innodb_corrupted_pages" file content: ---
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
print_corrupted_pages_file($ENV{corrupted_pages_file},
|
||||||
|
$ENV{corrupted_pages_file_filt});
|
||||||
|
EOF
|
||||||
|
--cat_file $corrupted_pages_file_filt
|
||||||
|
--echo ------
|
||||||
|
|
||||||
|
--echo # Check if corrupted pages were copied to delta files, and non-corrupted pages are not copied.
|
||||||
|
perl;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
my $schema = "$ENV{incdir}/test";
|
||||||
|
|
||||||
|
open(my $fh, '<', $ENV{perl_result_file}) or die $!;
|
||||||
|
|
||||||
|
my $last_page_no = <$fh>;
|
||||||
|
die_if_no_pages("$schema/t1_corrupted.ibd.delta",
|
||||||
|
$last_page_no, $last_page_no + 2, $last_page_no + 3);
|
||||||
|
|
||||||
|
$last_page_no = <$fh>;
|
||||||
|
die_if_no_pages("$schema/t2_corrupted.ibd.delta",
|
||||||
|
$last_page_no + 1, $last_page_no + 2, $last_page_no + 4);
|
||||||
|
|
||||||
|
$last_page_no = <$fh>;
|
||||||
|
die_if_no_pages("$schema/t5_corrupted_to_rename_renamed.ibd.delta",
|
||||||
|
$last_page_no);
|
||||||
|
|
||||||
|
close $fh;
|
||||||
|
|
||||||
|
die_if_not_empty("$schema/t3.ibd.delta");
|
||||||
|
|
||||||
|
sub read_first_page_from_delta {
|
||||||
|
my $file_name = shift;
|
||||||
|
my $pages_count = shift;
|
||||||
|
|
||||||
|
open my $file, '<:raw', $file_name || die "Cannot open $file_name\n";
|
||||||
|
read $file, my $buffer, $pages_count*4 || die "Cannot read $file_name\n";
|
||||||
|
close $file;
|
||||||
|
|
||||||
|
return unpack("N[$pages_count]", $buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub die_if_no_pages {
|
||||||
|
my $file_name = shift;
|
||||||
|
my @check_pages = @_;
|
||||||
|
my @read_pages =
|
||||||
|
read_first_page_from_delta($file_name, scalar(@check_pages) + 1);
|
||||||
|
for (my $i = 1; $i < @check_pages + 1; ++$i) {
|
||||||
|
my $check_page_no = $check_pages[$i - 1];
|
||||||
|
die "Corrupted page $check_page_no was not copied to $file_name."
|
||||||
|
if ($i >= @read_pages || $read_pages[$i] != $check_page_no);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub die_if_not_empty {
|
||||||
|
my $file_name = shift;
|
||||||
|
my ($magic, $full) = read_first_page_from_delta($file_name, 2);
|
||||||
|
die "Delta $file_name must be empty."
|
||||||
|
if ($full != 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
--rmdir $incdir
|
||||||
|
--rmdir $targetdir
|
||||||
|
|
||||||
|
DROP TABLE t1_corrupted;
|
||||||
|
DROP TABLE t2_corrupted;
|
||||||
|
DROP TABLE t4_corrupted_new;
|
||||||
|
DROP TABLE t5_corrupted_to_rename_renamed;
|
||||||
|
DROP TABLE t7_corrupted_to_alter;
|
||||||
|
DROP TABLE t1_inc_corrupted;
|
||||||
|
DROP TABLE t2_inc_corrupted;
|
||||||
|
DROP TABLE t4_inc_corrupted_new;
|
||||||
|
DROP TABLE t5_inc_corrupted_to_rename_renamed;
|
||||||
|
DROP TABLE t7_inc_corrupted_to_alter;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo ########
|
||||||
|
--echo # Test for --prepare with "innodb_corrupted_pages" file
|
||||||
|
--echo ###
|
||||||
|
--echo
|
||||||
|
|
||||||
|
--echo # Extend some tablespace and corrupt extended pages for full backup
|
||||||
|
--source include/shutdown_mysqld.inc
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
my $schema="$ENV{MYSQLD_DATADIR}/test";
|
||||||
|
my $last_page_no = extend_space("$schema/t3.ibd", 3);
|
||||||
|
corrupt_space_page_id("$schema/t3.ibd", $last_page_no, $last_page_no + 2);
|
||||||
|
open(my $fh, '>', $ENV{perl_result_file}) or die $!;
|
||||||
|
print $fh "$last_page_no\n";
|
||||||
|
close $fh;
|
||||||
|
EOF
|
||||||
|
--source include/start_mysqld.inc
|
||||||
|
|
||||||
|
--echo # Full backup with --log-innodb-page-corruption
|
||||||
|
--disable_result_log
|
||||||
|
--error 1
|
||||||
|
--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --log-innodb-page-corruption --target-dir=$targetdir
|
||||||
|
--enable_result_log
|
||||||
|
--let corrupted_pages_file = $targetdir/innodb_corrupted_pages
|
||||||
|
--echo --- "innodb_corrupted_pages" file content: ---
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
print_corrupted_pages_file($ENV{corrupted_pages_file},
|
||||||
|
$ENV{corrupted_pages_file_filt});
|
||||||
|
EOF
|
||||||
|
--cat_file $corrupted_pages_file_filt
|
||||||
|
--echo ------
|
||||||
|
|
||||||
|
--echo # Extend some tablespace and corrupt extended pages for incremental backup
|
||||||
|
--source include/shutdown_mysqld.inc
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
my $schema="$ENV{MYSQLD_DATADIR}/test";
|
||||||
|
my $last_page_no = extend_space("$schema/t3_inc.ibd", 3);
|
||||||
|
corrupt_space_page_id("$schema/t3_inc.ibd", $last_page_no, $last_page_no + 2);
|
||||||
|
open(my $fh, '>>', $ENV{perl_result_file}) or die $!;
|
||||||
|
print $fh "$last_page_no";
|
||||||
|
close $fh;
|
||||||
|
EOF
|
||||||
|
--source include/start_mysqld.inc
|
||||||
|
|
||||||
|
--echo # Incremental backup --log-innodb-page-corruption
|
||||||
|
--disable_result_log
|
||||||
|
--error 1
|
||||||
|
--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --log-innodb-page-corruption --target-dir=$incdir --incremental-basedir=$targetdir --dbug=+d,mariabackup_events,mariabackup_inject_code > $backuplog
|
||||||
|
--disable_result_log
|
||||||
|
--let corrupted_pages_file = $incdir/innodb_corrupted_pages
|
||||||
|
--echo --- "innodb_corrupted_pages" file content: ---
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
print_corrupted_pages_file($ENV{corrupted_pages_file},
|
||||||
|
$ENV{corrupted_pages_file_filt});
|
||||||
|
EOF
|
||||||
|
--cat_file $corrupted_pages_file_filt
|
||||||
|
--echo ------
|
||||||
|
|
||||||
|
--let targetdir2=$targetdir-2
|
||||||
|
--let incdir2=$incdir-2
|
||||||
|
perl;
|
||||||
|
use lib "lib";
|
||||||
|
use My::Handles { suppress_init_messages => 1 };
|
||||||
|
use My::File::Path;
|
||||||
|
copytree($ENV{'targetdir'}, $ENV{'targetdir2'});
|
||||||
|
copytree($ENV{'incdir'}, $ENV{'incdir2'});
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--echo # Full backup prepare
|
||||||
|
--disable_result_log
|
||||||
|
exec $XTRABACKUP --prepare --target-dir=$targetdir > $backuplog;
|
||||||
|
--enable_result_log
|
||||||
|
|
||||||
|
--echo # "innodb_corrupted_pages" file must not exist after successful prepare
|
||||||
|
--error 1
|
||||||
|
--file_exists $targetdir/innodb_corrupted_pages
|
||||||
|
--let SEARCH_PATTERN=was successfuly fixed.*
|
||||||
|
--let SEARCH_FILE=$backuplog
|
||||||
|
--source include/search_pattern_in_file.inc
|
||||||
|
|
||||||
|
--echo # Check that fixed pages are zero-filled
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
open(my $fh, '<', $ENV{perl_result_file}) or die $!;
|
||||||
|
my $last_page_no = <$fh>;
|
||||||
|
close $fh;
|
||||||
|
my $schema = "$ENV{targetdir}/test";
|
||||||
|
die_if_page_is_not_zero("$schema/t3.ibd", $last_page_no, $last_page_no + 2);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--echo # Incremental backup prepare
|
||||||
|
--disable_result_log
|
||||||
|
exec $XTRABACKUP --prepare --target-dir=$targetdir --incremental-dir=$incdir > $backuplog;
|
||||||
|
--enable_result_log
|
||||||
|
|
||||||
|
--echo # "innodb_corrupted_pages" file must not exist after successful prepare
|
||||||
|
--error 1
|
||||||
|
--file_exists $targetdir/innodb_corrupted_pages
|
||||||
|
--echo # do not remove "innodb_corrupted_pages" in incremental dir
|
||||||
|
--file_exists $incdir/innodb_corrupted_pages
|
||||||
|
--let SEARCH_PATTERN=was successfuly fixed.*
|
||||||
|
--let SEARCH_FILE=$backuplog
|
||||||
|
--source include/search_pattern_in_file.inc
|
||||||
|
|
||||||
|
--echo # Check that fixed pages are zero-filled
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
open(my $fh, '<', $ENV{perl_result_file}) or die $!;
|
||||||
|
my $last_page_no_full = <$fh>;
|
||||||
|
my $last_page_no_inc = <$fh>;
|
||||||
|
close $fh;
|
||||||
|
my $schema = "$ENV{targetdir}/test";
|
||||||
|
die_if_page_is_not_zero("$schema/t3.ibd",
|
||||||
|
$last_page_no_full, $last_page_no_full + 2);
|
||||||
|
die_if_page_is_not_zero("$schema/t3_inc.ibd",
|
||||||
|
$last_page_no_inc, $last_page_no_inc + 2);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--source include/restart_and_restore.inc
|
||||||
|
|
||||||
|
SELECT * FROM t3;
|
||||||
|
SELECT * FROM t3_inc;
|
||||||
|
|
||||||
|
--echo # Test the case when not all corrupted pages are fixed
|
||||||
|
--echo
|
||||||
|
--echo # Add some fake corrupted pages
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
append_corrupted_pages(
|
||||||
|
"$ENV{targetdir2}/innodb_corrupted_pages", 'test/t3', '3 4');
|
||||||
|
append_corrupted_pages(
|
||||||
|
"$ENV{incdir2}/innodb_corrupted_pages", 'test/t3_inc', '4 5');
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--echo # Full backup prepare
|
||||||
|
--disable_result_log
|
||||||
|
--error 1
|
||||||
|
exec $XTRABACKUP --prepare --target-dir=$targetdir2 > $backuplog;
|
||||||
|
--enable_result_log
|
||||||
|
|
||||||
|
--let SEARCH_PATTERN=Error: corrupted page.*
|
||||||
|
--let SEARCH_FILE=$backuplog
|
||||||
|
--source include/search_pattern_in_file.inc
|
||||||
|
--let corrupted_pages_file = $targetdir2/innodb_corrupted_pages
|
||||||
|
--echo --- "innodb_corrupted_pages" file content: ---
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
print_corrupted_pages_file($ENV{corrupted_pages_file},
|
||||||
|
$ENV{corrupted_pages_file_filt});
|
||||||
|
EOF
|
||||||
|
--cat_file $corrupted_pages_file_filt
|
||||||
|
--echo ------
|
||||||
|
|
||||||
|
--echo # Incremental backup prepare
|
||||||
|
--disable_result_log
|
||||||
|
--error 1
|
||||||
|
exec $XTRABACKUP --prepare --target-dir=$targetdir2 --incremental-dir=$incdir2 > $backuplog;
|
||||||
|
--enable_result_log
|
||||||
|
|
||||||
|
--let SEARCH_PATTERN=Error: corrupted page.*
|
||||||
|
--let SEARCH_FILE=$backuplog
|
||||||
|
--source include/search_pattern_in_file.inc
|
||||||
|
--let corrupted_pages_file = $targetdir2/innodb_corrupted_pages
|
||||||
|
--echo --- "innodb_corrupted_pages" file content: ---
|
||||||
|
perl;
|
||||||
|
do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl";
|
||||||
|
print_corrupted_pages_file($ENV{corrupted_pages_file},
|
||||||
|
$ENV{corrupted_pages_file_filt});
|
||||||
|
EOF
|
||||||
|
--cat_file $corrupted_pages_file_filt
|
||||||
|
--echo ------
|
||||||
|
|
||||||
|
DROP TABLE t3;
|
||||||
|
DROP TABLE t3_inc;
|
||||||
|
--remove_file $backuplog
|
||||||
|
--remove_file $perl_result_file
|
||||||
|
--remove_file $corrupted_pages_file_filt
|
||||||
|
--rmdir $targetdir
|
||||||
|
--rmdir $targetdir2
|
||||||
|
--rmdir $incdir
|
||||||
|
--rmdir $incdir2
|
@ -147,3 +147,18 @@ drop role test_role2;
|
|||||||
delete from mysql.roles_mapping where Role='test_role1';
|
delete from mysql.roles_mapping where Role='test_role1';
|
||||||
delete from mysql.roles_mapping where Role='test_role2';
|
delete from mysql.roles_mapping where Role='test_role2';
|
||||||
flush privileges;
|
flush privileges;
|
||||||
|
#
|
||||||
|
# MDEV-24289: show grants missing with grant option
|
||||||
|
#
|
||||||
|
create role anel;
|
||||||
|
GRANT SELECT, UPDATE, DELETE, ALTER ON *.* TO 'anel';
|
||||||
|
SHOW GRANTS for 'anel';
|
||||||
|
Grants for anel
|
||||||
|
GRANT SELECT, UPDATE, DELETE, ALTER ON *.* TO `anel`
|
||||||
|
create role MariaDB_admin;
|
||||||
|
GRANT SELECT, UPDATE, DELETE, ALTER ON *.* TO 'MariaDB_admin' WITH GRANT OPTION;
|
||||||
|
SHOW GRANTS for 'MariaDB_admin';
|
||||||
|
Grants for MariaDB_admin
|
||||||
|
GRANT SELECT, UPDATE, DELETE, ALTER ON *.* TO `MariaDB_admin` WITH GRANT OPTION
|
||||||
|
drop role MariaDB_admin;
|
||||||
|
drop role anel;
|
||||||
|
@ -88,3 +88,16 @@ drop role test_role2;
|
|||||||
delete from mysql.roles_mapping where Role='test_role1';
|
delete from mysql.roles_mapping where Role='test_role1';
|
||||||
delete from mysql.roles_mapping where Role='test_role2';
|
delete from mysql.roles_mapping where Role='test_role2';
|
||||||
flush privileges;
|
flush privileges;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-24289: show grants missing with grant option
|
||||||
|
--echo #
|
||||||
|
create role anel;
|
||||||
|
GRANT SELECT, UPDATE, DELETE, ALTER ON *.* TO 'anel';
|
||||||
|
SHOW GRANTS for 'anel';
|
||||||
|
|
||||||
|
create role MariaDB_admin;
|
||||||
|
GRANT SELECT, UPDATE, DELETE, ALTER ON *.* TO 'MariaDB_admin' WITH GRANT OPTION;
|
||||||
|
SHOW GRANTS for 'MariaDB_admin';
|
||||||
|
drop role MariaDB_admin;
|
||||||
|
drop role anel;
|
||||||
|
@ -21,23 +21,27 @@ SELECT CAST(REGEXP_REPLACE(@GALERA_VERSION,'^(\\d+)\\.(\\d+)\\.(\\d+).*','\\3')
|
|||||||
|
|
||||||
# Actual
|
# Actual
|
||||||
SELECT VARIABLE_VALUE INTO @ACTUAL_GALERA_VERSION FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE 'wsrep_provider_version';
|
SELECT VARIABLE_VALUE INTO @ACTUAL_GALERA_VERSION FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE 'wsrep_provider_version';
|
||||||
|
SELECT CAST(REGEXP_REPLACE(@ACTUAL_GALERA_VERSION,'^(\\d+)\\.(\\d+).*','\\1') AS UNSIGNED) INTO @ACTUAL_GALERA_MAJOR_VERSION;
|
||||||
SELECT CAST(REGEXP_REPLACE(@ACTUAL_GALERA_VERSION,'^[\\d\\.]*(\\d+)\\.\\d+.*','\\1') AS UNSIGNED) INTO @ACTUAL_GALERA_MINOR_VERSION;
|
SELECT CAST(REGEXP_REPLACE(@ACTUAL_GALERA_VERSION,'^[\\d\\.]*(\\d+)\\.\\d+.*','\\1') AS UNSIGNED) INTO @ACTUAL_GALERA_MINOR_VERSION;
|
||||||
SELECT CAST(REGEXP_REPLACE(@ACTUAL_GALERA_VERSION,'^[\\d\\.]*\\.(\\d+).*','\\1') AS UNSIGNED) INTO @ACTUAL_GALERA_RELEASE_VERSION;
|
SELECT CAST(REGEXP_REPLACE(@ACTUAL_GALERA_VERSION,'^[\\d\\.]*\\.(\\d+).*','\\1') AS UNSIGNED) INTO @ACTUAL_GALERA_RELEASE_VERSION;
|
||||||
|
--enable_query_log
|
||||||
|
|
||||||
# For testing
|
# For testing
|
||||||
#SELECT @GALERA_MAJOR_VERSION;
|
#SELECT @GALERA_MAJOR_VERSION;
|
||||||
#SELECT @GALERA_MINOR_VERSION;
|
#SELECT @GALERA_MINOR_VERSION;
|
||||||
#SELECT @GALERA_RELEASE_VERSION;
|
#SELECT @GALERA_RELEASE_VERSION;
|
||||||
#SELECT @ACTUAL_GALERA_VERSION;
|
#SELECT @ACTUAL_GALERA_MAJOR_VERSION;
|
||||||
#SELECT @ACTUAL_GALERA_MINOR_VERSION;
|
#SELECT @ACTUAL_GALERA_MINOR_VERSION;
|
||||||
#SELECT @ACTUAL_GALERA_RELEASE_VERSION;
|
#SELECT @ACTUAL_GALERA_RELEASE_VERSION;
|
||||||
|
|
||||||
if (!`SELECT (@ACTUAL_GALERA_MINOR_VERSION > @GALERA_MINOR_VERSION) OR
|
if (!`SELECT (@ACTUAL_GALERA_MAJOR_VERSION >= @GALERA_MAJOR_VERSION AND @ACTUAL_GALERA_MINOR_VERSION > @GALERA_MINOR_VERSION) OR
|
||||||
(@ACTUAL_GALERA_MINOR_VERSION = @GALERA_MINOR_VERSION AND
|
(@ACTUAL_GALERA_MAJOR_VERSION = @GALERA_MAJOR_VERSION AND
|
||||||
|
@ACTUAL_GALERA_MINOR_VERSION = @GALERA_MINOR_VERSION AND
|
||||||
@ACTUAL_GALERA_RELEASE_VERSION >= @GALERA_RELEASE_VERSION)
|
@ACTUAL_GALERA_RELEASE_VERSION >= @GALERA_RELEASE_VERSION)
|
||||||
`)
|
`)
|
||||||
{
|
{
|
||||||
skip Test requires Galera library version >= $galera_version;
|
skip Test requires Galera library version >= $galera_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
--enable_query_log
|
--echo # Correct Galera library found
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ void my_message_stderr(uint error __attribute__((unused)),
|
|||||||
DBUG_ENTER("my_message_stderr");
|
DBUG_ENTER("my_message_stderr");
|
||||||
DBUG_PRINT("enter",("message: %s",str));
|
DBUG_PRINT("enter",("message: %s",str));
|
||||||
(void) fflush(stdout);
|
(void) fflush(stdout);
|
||||||
|
if (MyFlags & (ME_NOTE | ME_ERROR_LOG_ONLY))
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
if (MyFlags & ME_BELL)
|
if (MyFlags & ME_BELL)
|
||||||
(void) fputc('\007', stderr);
|
(void) fputc('\007', stderr);
|
||||||
if (my_progname)
|
if (my_progname)
|
||||||
|
@ -471,9 +471,7 @@ dbcontext::close_tables_if()
|
|||||||
unlock_tables_if();
|
unlock_tables_if();
|
||||||
DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK close tables\n"));
|
DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK close tables\n"));
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
#if MYSQL_VERSION_ID >= 50505
|
thd->mdl_context.release_transactional_locks(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
|
||||||
#endif
|
|
||||||
if (!table_vec.empty()) {
|
if (!table_vec.empty()) {
|
||||||
statistic_increment(close_tables_count, &LOCK_status);
|
statistic_increment(close_tables_count, &LOCK_status);
|
||||||
table_vec.clear();
|
table_vec.clear();
|
||||||
|
@ -653,7 +653,7 @@ public:
|
|||||||
}
|
}
|
||||||
bool
|
bool
|
||||||
subquery_type_allows_materialization(const Item *inner,
|
subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const override
|
const Item *outer, bool) const override
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Example:
|
Example:
|
||||||
|
@ -401,6 +401,14 @@ then
|
|||||||
MODULE="rsync_sst"
|
MODULE="rsync_sst"
|
||||||
|
|
||||||
RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid"
|
RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid"
|
||||||
|
# give some time for lingering rsync from previous SST to complete
|
||||||
|
check_round=0
|
||||||
|
while check_pid $RSYNC_PID && [ $check_round -lt 10 ]
|
||||||
|
do
|
||||||
|
wsrep_log_info "lingering rsync daemon found at startup, waiting for it to exit"
|
||||||
|
check_round=$(( check_round + 1 ))
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
if check_pid $RSYNC_PID
|
if check_pid $RSYNC_PID
|
||||||
then
|
then
|
||||||
|
@ -4443,7 +4443,7 @@ int ha_partition::write_row(const uchar * buf)
|
|||||||
|
|
||||||
DBUG_ASSERT(!m_file[part_id]->row_logging);
|
DBUG_ASSERT(!m_file[part_id]->row_logging);
|
||||||
error= m_file[part_id]->ha_write_row(buf);
|
error= m_file[part_id]->ha_write_row(buf);
|
||||||
if (have_auto_increment && !table->s->next_number_keypart)
|
if (!error && have_auto_increment && !table->s->next_number_keypart)
|
||||||
set_auto_increment_if_higher(table->next_number_field);
|
set_auto_increment_if_higher(table->next_number_field);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
@ -92,7 +92,6 @@ public:
|
|||||||
bool auto_inc_initialized;
|
bool auto_inc_initialized;
|
||||||
mysql_mutex_t auto_inc_mutex; /**< protecting auto_inc val */
|
mysql_mutex_t auto_inc_mutex; /**< protecting auto_inc val */
|
||||||
ulonglong next_auto_inc_val; /**< first non reserved value */
|
ulonglong next_auto_inc_val; /**< first non reserved value */
|
||||||
ulonglong prev_auto_inc_val; /**< stored next_auto_inc_val */
|
|
||||||
/**
|
/**
|
||||||
Hash of partition names. Initialized in the first ha_partition::open()
|
Hash of partition names. Initialized in the first ha_partition::open()
|
||||||
for the table_share. After that it is read-only, i.e. no locking required.
|
for the table_share. After that it is read-only, i.e. no locking required.
|
||||||
@ -104,7 +103,6 @@ public:
|
|||||||
Partition_share()
|
Partition_share()
|
||||||
: auto_inc_initialized(false),
|
: auto_inc_initialized(false),
|
||||||
next_auto_inc_val(0),
|
next_auto_inc_val(0),
|
||||||
prev_auto_inc_val(0),
|
|
||||||
partition_name_hash_initialized(false),
|
partition_name_hash_initialized(false),
|
||||||
partition_names(NULL)
|
partition_names(NULL)
|
||||||
{
|
{
|
||||||
@ -429,24 +427,6 @@ private:
|
|||||||
MY_BITMAP m_locked_partitions;
|
MY_BITMAP m_locked_partitions;
|
||||||
/** Stores shared auto_increment etc. */
|
/** Stores shared auto_increment etc. */
|
||||||
Partition_share *part_share;
|
Partition_share *part_share;
|
||||||
/** Fix spurious -Werror=overloaded-virtual in GCC 9 */
|
|
||||||
virtual void restore_auto_increment(ulonglong prev_insert_id) override
|
|
||||||
{
|
|
||||||
handler::restore_auto_increment(prev_insert_id);
|
|
||||||
}
|
|
||||||
/** Store and restore next_auto_inc_val over duplicate key errors. */
|
|
||||||
void store_auto_increment() override
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(part_share);
|
|
||||||
part_share->prev_auto_inc_val= part_share->next_auto_inc_val;
|
|
||||||
handler::store_auto_increment();
|
|
||||||
}
|
|
||||||
void restore_auto_increment() override
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(part_share);
|
|
||||||
part_share->next_auto_inc_val= part_share->prev_auto_inc_val;
|
|
||||||
handler::restore_auto_increment();
|
|
||||||
}
|
|
||||||
void sum_copy_info(handler *file);
|
void sum_copy_info(handler *file);
|
||||||
void sum_copy_infos();
|
void sum_copy_infos();
|
||||||
void reset_copy_info() override;
|
void reset_copy_info() override;
|
||||||
|
@ -3514,7 +3514,6 @@ int handler::update_auto_increment()
|
|||||||
THD *thd= table->in_use;
|
THD *thd= table->in_use;
|
||||||
struct system_variables *variables= &thd->variables;
|
struct system_variables *variables= &thd->variables;
|
||||||
int result=0, tmp;
|
int result=0, tmp;
|
||||||
enum enum_check_fields save_count_cuted_fields;
|
|
||||||
DBUG_ENTER("handler::update_auto_increment");
|
DBUG_ENTER("handler::update_auto_increment");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3656,10 +3655,10 @@ int handler::update_auto_increment()
|
|||||||
nr, append ? nb_reserved_values : 0));
|
nr, append ? nb_reserved_values : 0));
|
||||||
|
|
||||||
/* Store field without warning (Warning will be printed by insert) */
|
/* Store field without warning (Warning will be printed by insert) */
|
||||||
save_count_cuted_fields= thd->count_cuted_fields;
|
{
|
||||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
Check_level_instant_set check_level_save(thd, CHECK_FIELD_IGNORE);
|
||||||
tmp= table->next_number_field->store((longlong)nr, TRUE);
|
tmp= table->next_number_field->store((longlong)nr, TRUE);
|
||||||
thd->count_cuted_fields= save_count_cuted_fields;
|
}
|
||||||
|
|
||||||
if (unlikely(tmp)) // Out of range value in store
|
if (unlikely(tmp)) // Out of range value in store
|
||||||
{
|
{
|
||||||
|
@ -3278,9 +3278,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
Handler_share **ha_share;
|
Handler_share **ha_share;
|
||||||
|
|
||||||
/** Stores next_insert_id for handling duplicate key errors. */
|
|
||||||
ulonglong m_prev_insert_id;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
|
handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
|
||||||
:table_share(share_arg), table(0),
|
:table_share(share_arg), table(0),
|
||||||
@ -3308,7 +3305,7 @@ public:
|
|||||||
m_psi_numrows(0),
|
m_psi_numrows(0),
|
||||||
m_psi_locker(NULL),
|
m_psi_locker(NULL),
|
||||||
row_logging(0), row_logging_init(0),
|
row_logging(0), row_logging_init(0),
|
||||||
m_lock_type(F_UNLCK), ha_share(NULL), m_prev_insert_id(0)
|
m_lock_type(F_UNLCK), ha_share(NULL)
|
||||||
{
|
{
|
||||||
DBUG_PRINT("info",
|
DBUG_PRINT("info",
|
||||||
("handler created F_UNLCK %d F_RDLCK %d F_WRLCK %d",
|
("handler created F_UNLCK %d F_RDLCK %d F_WRLCK %d",
|
||||||
@ -4028,16 +4025,6 @@ public:
|
|||||||
insert_id_for_cur_row;
|
insert_id_for_cur_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Store and restore next_insert_id over duplicate key errors. */
|
|
||||||
virtual void store_auto_increment()
|
|
||||||
{
|
|
||||||
m_prev_insert_id= next_insert_id;
|
|
||||||
}
|
|
||||||
virtual void restore_auto_increment()
|
|
||||||
{
|
|
||||||
restore_auto_increment(m_prev_insert_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void update_create_info(HA_CREATE_INFO *create_info) {}
|
virtual void update_create_info(HA_CREATE_INFO *create_info) {}
|
||||||
int check_old_types();
|
int check_old_types();
|
||||||
virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt)
|
virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt)
|
||||||
|
@ -1442,16 +1442,12 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
|
|||||||
int res;
|
int res;
|
||||||
TABLE *table= field->table;
|
TABLE *table= field->table;
|
||||||
THD *thd= table->in_use;
|
THD *thd= table->in_use;
|
||||||
enum_check_fields tmp= thd->count_cuted_fields;
|
Check_level_instant_set check_level_save(thd, CHECK_FIELD_IGNORE);
|
||||||
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
|
|
||||||
Sql_mode_save sms(thd);
|
Sql_mode_save sms(thd);
|
||||||
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
|
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
|
||||||
thd->variables.sql_mode|= MODE_INVALID_DATES;
|
thd->variables.sql_mode|= MODE_INVALID_DATES;
|
||||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
|
||||||
|
|
||||||
res= save_in_field(field, no_conversions);
|
res= save_in_field(field, no_conversions);
|
||||||
|
|
||||||
thd->count_cuted_fields= tmp;
|
|
||||||
dbug_tmp_restore_column_map(table->write_set, old_map);
|
dbug_tmp_restore_column_map(table->write_set, old_map);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -973,6 +973,13 @@ public:
|
|||||||
void set_name_no_truncate(THD *thd, const char *str, uint length,
|
void set_name_no_truncate(THD *thd, const char *str, uint length,
|
||||||
CHARSET_INFO *cs);
|
CHARSET_INFO *cs);
|
||||||
void init_make_send_field(Send_field *tmp_field, const Type_handler *h);
|
void init_make_send_field(Send_field *tmp_field, const Type_handler *h);
|
||||||
|
void share_name_with(const Item *item)
|
||||||
|
{
|
||||||
|
name= item->name;
|
||||||
|
common_flags= static_cast<uint8>
|
||||||
|
((common_flags & ~IS_AUTO_GENERATED_NAME) |
|
||||||
|
(item->common_flags & IS_AUTO_GENERATED_NAME));
|
||||||
|
}
|
||||||
virtual void cleanup();
|
virtual void cleanup();
|
||||||
virtual void make_send_field(THD *thd, Send_field *field);
|
virtual void make_send_field(THD *thd, Send_field *field);
|
||||||
|
|
||||||
|
@ -321,8 +321,8 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item,
|
|||||||
if ((*item)->const_item() && !(*item)->is_expensive())
|
if ((*item)->const_item() && !(*item)->is_expensive())
|
||||||
{
|
{
|
||||||
TABLE *table= field->table;
|
TABLE *table= field->table;
|
||||||
sql_mode_t orig_sql_mode= thd->variables.sql_mode;
|
Sql_mode_save sql_mode(thd);
|
||||||
enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields;
|
Check_level_instant_set check_level_save(thd, CHECK_FIELD_IGNORE);
|
||||||
my_bitmap_map *old_maps[2] = { NULL, NULL };
|
my_bitmap_map *old_maps[2] = { NULL, NULL };
|
||||||
ulonglong UNINIT_VAR(orig_field_val); /* original field value if valid */
|
ulonglong UNINIT_VAR(orig_field_val); /* original field value if valid */
|
||||||
|
|
||||||
@ -331,9 +331,8 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item,
|
|||||||
dbug_tmp_use_all_columns(table, old_maps,
|
dbug_tmp_use_all_columns(table, old_maps,
|
||||||
table->read_set, table->write_set);
|
table->read_set, table->write_set);
|
||||||
/* For comparison purposes allow invalid dates like 2000-01-32 */
|
/* For comparison purposes allow invalid dates like 2000-01-32 */
|
||||||
thd->variables.sql_mode= (orig_sql_mode & ~MODE_NO_ZERO_DATE) |
|
thd->variables.sql_mode= (thd->variables.sql_mode & ~MODE_NO_ZERO_DATE) |
|
||||||
MODE_INVALID_DATES;
|
MODE_INVALID_DATES;
|
||||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Store the value of the field/constant because the call to save_in_field
|
Store the value of the field/constant because the call to save_in_field
|
||||||
@ -370,8 +369,6 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item,
|
|||||||
/* orig_field_val must be a valid value that can be restored back. */
|
/* orig_field_val must be a valid value that can be restored back. */
|
||||||
DBUG_ASSERT(!result);
|
DBUG_ASSERT(!result);
|
||||||
}
|
}
|
||||||
thd->variables.sql_mode= orig_sql_mode;
|
|
||||||
thd->count_cuted_fields= orig_count_cuted_fields;
|
|
||||||
if (table && table->read_set)
|
if (table && table->read_set)
|
||||||
dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_maps);
|
dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_maps);
|
||||||
}
|
}
|
||||||
|
@ -1520,7 +1520,8 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
|
|||||||
pushed_cond_guards(NULL), do_not_convert_to_sj(FALSE), is_jtbm_merged(FALSE),
|
pushed_cond_guards(NULL), do_not_convert_to_sj(FALSE), is_jtbm_merged(FALSE),
|
||||||
is_jtbm_const_tab(FALSE), is_flattenable_semijoin(FALSE),
|
is_jtbm_const_tab(FALSE), is_flattenable_semijoin(FALSE),
|
||||||
is_registered_semijoin(FALSE),
|
is_registered_semijoin(FALSE),
|
||||||
upper_item(0)
|
upper_item(0),
|
||||||
|
converted_from_in_predicate(FALSE)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
|
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
|
||||||
DBUG_PRINT("info", ("in_strategy: %u", (uint)in_strategy));
|
DBUG_PRINT("info", ("in_strategy: %u", (uint)in_strategy));
|
||||||
|
@ -613,12 +613,18 @@ public:
|
|||||||
|
|
||||||
Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery
|
Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery
|
||||||
|
|
||||||
|
/*
|
||||||
|
SET to TRUE if IN subquery is converted from an IN predicate
|
||||||
|
*/
|
||||||
|
bool converted_from_in_predicate;
|
||||||
|
|
||||||
Item_in_subselect(THD *thd_arg, Item * left_expr, st_select_lex *select_lex);
|
Item_in_subselect(THD *thd_arg, Item * left_expr, st_select_lex *select_lex);
|
||||||
Item_in_subselect(THD *thd_arg):
|
Item_in_subselect(THD *thd_arg):
|
||||||
Item_exists_subselect(thd_arg), left_expr_cache(0), first_execution(TRUE),
|
Item_exists_subselect(thd_arg), left_expr_cache(0), first_execution(TRUE),
|
||||||
in_strategy(SUBS_NOT_TRANSFORMED),
|
in_strategy(SUBS_NOT_TRANSFORMED),
|
||||||
pushed_cond_guards(NULL), func(NULL), do_not_convert_to_sj(FALSE),
|
pushed_cond_guards(NULL), func(NULL), do_not_convert_to_sj(FALSE),
|
||||||
is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE), upper_item(0) {}
|
is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE), upper_item(0),
|
||||||
|
converted_from_in_predicate(FALSE) {}
|
||||||
void cleanup() override;
|
void cleanup() override;
|
||||||
subs_type substype() override { return IN_SUBS; }
|
subs_type substype() override { return IN_SUBS; }
|
||||||
void reset() override
|
void reset() override
|
||||||
|
@ -2988,10 +2988,10 @@ error:
|
|||||||
if (thd->transaction_rollback_request)
|
if (thd->transaction_rollback_request)
|
||||||
{
|
{
|
||||||
trans_rollback_implicit(thd);
|
trans_rollback_implicit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
else if (! thd->in_multi_stmt_transaction_mode())
|
else if (! thd->in_multi_stmt_transaction_mode())
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
else
|
else
|
||||||
thd->mdl_context.release_statement_locks();
|
thd->mdl_context.release_statement_locks();
|
||||||
|
|
||||||
@ -4039,7 +4039,7 @@ int Xid_log_event::do_commit()
|
|||||||
{
|
{
|
||||||
bool res;
|
bool res;
|
||||||
res= trans_commit(thd); /* Automatically rolls back on error. */
|
res= trans_commit(thd); /* Automatically rolls back on error. */
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -4088,10 +4088,7 @@ int XA_prepare_log_event::do_commit()
|
|||||||
res= trans_xa_prepare(thd);
|
res= trans_xa_prepare(thd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
res= trans_xa_commit(thd);
|
res= trans_xa_commit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -3039,15 +3039,17 @@ void MDL_context::rollback_to_savepoint(const MDL_savepoint &mdl_savepoint)
|
|||||||
implementation of COMMIT (implicit or explicit) and ROLLBACK.
|
implementation of COMMIT (implicit or explicit) and ROLLBACK.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void MDL_context::release_transactional_locks()
|
void MDL_context::release_transactional_locks(THD *thd)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("MDL_context::release_transactional_locks");
|
DBUG_ENTER("MDL_context::release_transactional_locks");
|
||||||
|
/* Fail if there are active transactions */
|
||||||
|
DBUG_ASSERT(!(thd->server_status &
|
||||||
|
(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY)));
|
||||||
release_locks_stored_before(MDL_STATEMENT, NULL);
|
release_locks_stored_before(MDL_STATEMENT, NULL);
|
||||||
release_locks_stored_before(MDL_TRANSACTION, NULL);
|
release_locks_stored_before(MDL_TRANSACTION, NULL);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MDL_context::release_statement_locks()
|
void MDL_context::release_statement_locks()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("MDL_context::release_transactional_locks");
|
DBUG_ENTER("MDL_context::release_transactional_locks");
|
||||||
|
@ -921,7 +921,7 @@ public:
|
|||||||
void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration);
|
void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration);
|
||||||
|
|
||||||
void release_statement_locks();
|
void release_statement_locks();
|
||||||
void release_transactional_locks();
|
void release_transactional_locks(THD *thd);
|
||||||
void release_explicit_locks();
|
void release_explicit_locks();
|
||||||
void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
|
void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
|
||||||
|
|
||||||
|
@ -872,6 +872,7 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
|
|||||||
|
|
||||||
bool all_are_fields= TRUE;
|
bool all_are_fields= TRUE;
|
||||||
uint32 total_key_length = 0;
|
uint32 total_key_length = 0;
|
||||||
|
bool converted_from_in_predicate= in_subs->converted_from_in_predicate;
|
||||||
for (uint i= 0; i < elements; i++)
|
for (uint i= 0; i < elements; i++)
|
||||||
{
|
{
|
||||||
Item *outer= left_exp->element_index(i);
|
Item *outer= left_exp->element_index(i);
|
||||||
@ -879,8 +880,11 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
|
|||||||
all_are_fields &= (outer->real_item()->type() == Item::FIELD_ITEM &&
|
all_are_fields &= (outer->real_item()->type() == Item::FIELD_ITEM &&
|
||||||
inner->real_item()->type() == Item::FIELD_ITEM);
|
inner->real_item()->type() == Item::FIELD_ITEM);
|
||||||
total_key_length += inner->max_length;
|
total_key_length += inner->max_length;
|
||||||
if (!inner->type_handler()->subquery_type_allows_materialization(inner,
|
if (!inner->
|
||||||
outer))
|
type_handler()->
|
||||||
|
subquery_type_allows_materialization(inner,
|
||||||
|
outer,
|
||||||
|
converted_from_in_predicate))
|
||||||
{
|
{
|
||||||
trace_transform.add("possible", false);
|
trace_transform.add("possible", false);
|
||||||
trace_transform.add("cause", "types mismatch");
|
trace_transform.add("cause", "types mismatch");
|
||||||
|
@ -445,7 +445,7 @@ rpl_slave_state::truncate_state_table(THD *thd)
|
|||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
ha_commit_trans(thd, TRUE);
|
ha_commit_trans(thd, TRUE);
|
||||||
}
|
}
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -736,7 +736,7 @@ end:
|
|||||||
if (in_transaction)
|
if (in_transaction)
|
||||||
thd->mdl_context.release_statement_locks();
|
thd->mdl_context.release_statement_locks();
|
||||||
else
|
else
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
thd->lex->restore_backup_query_tables_list(&lex_backup);
|
thd->lex->restore_backup_query_tables_list(&lex_backup);
|
||||||
thd->variables.option_bits= thd_saved_option;
|
thd->variables.option_bits= thd_saved_option;
|
||||||
@ -991,7 +991,7 @@ end:
|
|||||||
ha_rollback_trans(thd, FALSE);
|
ha_rollback_trans(thd, FALSE);
|
||||||
}
|
}
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
thd->lex->restore_backup_query_tables_list(&lex_backup);
|
thd->lex->restore_backup_query_tables_list(&lex_backup);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -69,34 +69,34 @@ injector::transaction::~transaction()
|
|||||||
*/
|
*/
|
||||||
int injector::transaction::commit()
|
int injector::transaction::commit()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("injector::transaction::commit()");
|
DBUG_ENTER("injector::transaction::commit()");
|
||||||
int error= m_thd->binlog_flush_pending_rows_event(true);
|
int error= m_thd->binlog_flush_pending_rows_event(true);
|
||||||
/*
|
/*
|
||||||
Cluster replication does not preserve statement or
|
Cluster replication does not preserve statement or
|
||||||
transaction boundaries of the master. Instead, a new
|
transaction boundaries of the master. Instead, a new
|
||||||
transaction on replication slave is started when a new GCI
|
transaction on replication slave is started when a new GCI
|
||||||
(global checkpoint identifier) is issued, and is committed
|
(global checkpoint identifier) is issued, and is committed
|
||||||
when the last event of the check point has been received and
|
when the last event of the check point has been received and
|
||||||
processed. This ensures consistency of each cluster in
|
processed. This ensures consistency of each cluster in
|
||||||
cluster replication, and there is no requirement for stronger
|
cluster replication, and there is no requirement for stronger
|
||||||
consistency: MySQL replication is asynchronous with other
|
consistency: MySQL replication is asynchronous with other
|
||||||
engines as well.
|
engines as well.
|
||||||
|
|
||||||
A practical consequence of that is that row level replication
|
A practical consequence of that is that row level replication
|
||||||
stream passed through the injector thread never contains
|
stream passed through the injector thread never contains
|
||||||
COMMIT events.
|
COMMIT events.
|
||||||
Here we should preserve the server invariant that there is no
|
Here we should preserve the server invariant that there is no
|
||||||
outstanding statement transaction when the normal transaction
|
outstanding statement transaction when the normal transaction
|
||||||
is committed by committing the statement transaction
|
is committed by committing the statement transaction
|
||||||
explicitly.
|
explicitly.
|
||||||
*/
|
*/
|
||||||
trans_commit_stmt(m_thd);
|
trans_commit_stmt(m_thd);
|
||||||
if (!trans_commit(m_thd))
|
if (!trans_commit(m_thd))
|
||||||
{
|
{
|
||||||
close_thread_tables(m_thd);
|
close_thread_tables(m_thd);
|
||||||
m_thd->mdl_context.release_transactional_locks();
|
m_thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1677,7 +1677,7 @@ end:
|
|||||||
{
|
{
|
||||||
*out_hton= table->s->db_type();
|
*out_hton= table->s->db_type();
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1704,7 +1704,7 @@ scan_all_gtid_slave_pos_table(THD *thd, int (*cb)(THD *, LEX_CSTRING *, void *),
|
|||||||
{
|
{
|
||||||
my_error(ER_FILE_NOT_FOUND, MYF(0), path, my_errno);
|
my_error(ER_FILE_NOT_FOUND, MYF(0), path, my_errno);
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1717,7 +1717,7 @@ scan_all_gtid_slave_pos_table(THD *thd, int (*cb)(THD *, LEX_CSTRING *, void *),
|
|||||||
err= ha_discover_table_names(thd, &MYSQL_SCHEMA_NAME, dirp, &tl, false);
|
err= ha_discover_table_names(thd, &MYSQL_SCHEMA_NAME, dirp, &tl, false);
|
||||||
my_dirend(dirp);
|
my_dirend(dirp);
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -2003,7 +2003,7 @@ end:
|
|||||||
ha_commit_trans(thd, FALSE);
|
ha_commit_trans(thd, FALSE);
|
||||||
ha_commit_trans(thd, TRUE);
|
ha_commit_trans(thd, TRUE);
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -2292,7 +2292,7 @@ void rpl_group_info::cleanup_context(THD *thd, bool error)
|
|||||||
if (thd->transaction->xid_state.is_explicit_XA())
|
if (thd->transaction->xid_state.is_explicit_XA())
|
||||||
xa_trans_force_rollback(thd);
|
xa_trans_force_rollback(thd);
|
||||||
|
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
|
|
||||||
if (thd == rli->sql_driver_thd)
|
if (thd == rli->sql_driver_thd)
|
||||||
{
|
{
|
||||||
@ -2406,10 +2406,10 @@ void rpl_group_info::slave_close_thread_tables(THD *thd)
|
|||||||
if (thd->transaction_rollback_request)
|
if (thd->transaction_rollback_request)
|
||||||
{
|
{
|
||||||
trans_rollback_implicit(thd);
|
trans_rollback_implicit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
else if (! thd->in_multi_stmt_transaction_mode())
|
else if (! thd->in_multi_stmt_transaction_mode())
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
else
|
else
|
||||||
thd->mdl_context.release_statement_locks();
|
thd->mdl_context.release_statement_locks();
|
||||||
|
|
||||||
|
@ -1205,8 +1205,6 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
|
|||||||
|
|
||||||
CHARSET_INFO *db_cs= get_default_db_collation(thd, sp->m_db.str);
|
CHARSET_INFO *db_cs= get_default_db_collation(thd, sp->m_db.str);
|
||||||
|
|
||||||
enum_check_fields saved_count_cuted_fields;
|
|
||||||
|
|
||||||
bool store_failed= FALSE;
|
bool store_failed= FALSE;
|
||||||
DBUG_ENTER("sp_create_routine");
|
DBUG_ENTER("sp_create_routine");
|
||||||
DBUG_PRINT("enter", ("type: %s name: %.*s",
|
DBUG_PRINT("enter", ("type: %s name: %.*s",
|
||||||
@ -1240,8 +1238,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
|
|||||||
/* Reset sql_mode during data dictionary operations. */
|
/* Reset sql_mode during data dictionary operations. */
|
||||||
thd->variables.sql_mode= 0;
|
thd->variables.sql_mode= 0;
|
||||||
|
|
||||||
saved_count_cuted_fields= thd->count_cuted_fields;
|
Check_level_instant_set check_level_save(thd, CHECK_FIELD_WARN);
|
||||||
thd->count_cuted_fields= CHECK_FIELD_WARN;
|
|
||||||
|
|
||||||
if (!(table= open_proc_table_for_update(thd)))
|
if (!(table= open_proc_table_for_update(thd)))
|
||||||
{
|
{
|
||||||
@ -1500,7 +1497,6 @@ log:
|
|||||||
ret= FALSE;
|
ret= FALSE;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
thd->count_cuted_fields= saved_count_cuted_fields;
|
|
||||||
thd->variables.sql_mode= saved_mode;
|
thd->variables.sql_mode= saved_mode;
|
||||||
DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
|
DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
|
@ -2390,10 +2390,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||||||
if (thd->transaction_rollback_request)
|
if (thd->transaction_rollback_request)
|
||||||
{
|
{
|
||||||
trans_rollback_implicit(thd);
|
trans_rollback_implicit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
else if (! thd->in_multi_stmt_transaction_mode())
|
else if (! thd->in_multi_stmt_transaction_mode())
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
else
|
else
|
||||||
thd->mdl_context.release_statement_locks();
|
thd->mdl_context.release_statement_locks();
|
||||||
}
|
}
|
||||||
@ -3518,10 +3518,10 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
|
|||||||
if (thd->transaction_rollback_request)
|
if (thd->transaction_rollback_request)
|
||||||
{
|
{
|
||||||
trans_rollback_implicit(thd);
|
trans_rollback_implicit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
else if (! thd->in_multi_stmt_transaction_mode())
|
else if (! thd->in_multi_stmt_transaction_mode())
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
else
|
else
|
||||||
thd->mdl_context.release_statement_locks();
|
thd->mdl_context.release_statement_locks();
|
||||||
}
|
}
|
||||||
|
@ -9463,6 +9463,8 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry,
|
|||||||
add_user_parameters(thd, &global, (ACL_USER *)acl_entry,
|
add_user_parameters(thd, &global, (ACL_USER *)acl_entry,
|
||||||
(want_access & GRANT_ACL));
|
(want_access & GRANT_ACL));
|
||||||
|
|
||||||
|
else if (want_access & GRANT_ACL)
|
||||||
|
global.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
|
||||||
protocol->prepare_for_resend();
|
protocol->prepare_for_resend();
|
||||||
protocol->store(global.ptr(),global.length(),global.charset());
|
protocol->store(global.ptr(),global.length(),global.charset());
|
||||||
if (protocol->write())
|
if (protocol->write())
|
||||||
|
@ -42,7 +42,7 @@ static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list)
|
|||||||
trans_rollback_stmt(thd);
|
trans_rollback_stmt(thd);
|
||||||
trans_rollback(thd);
|
trans_rollback(thd);
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
table_list->table has been closed and freed. Do not reference
|
table_list->table has been closed and freed. Do not reference
|
||||||
@ -115,7 +115,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
|||||||
acquire the exclusive lock to satisfy MDL asserts and avoid
|
acquire the exclusive lock to satisfy MDL asserts and avoid
|
||||||
deadlocks.
|
deadlocks.
|
||||||
*/
|
*/
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
/*
|
/*
|
||||||
Attempt to do full-blown table open in mysql_admin_table() has failed.
|
Attempt to do full-blown table open in mysql_admin_table() has failed.
|
||||||
Let us try to open at least a .FRM for this table.
|
Let us try to open at least a .FRM for this table.
|
||||||
@ -278,7 +278,7 @@ end:
|
|||||||
}
|
}
|
||||||
/* In case of a temporary table there will be no metadata lock. */
|
/* In case of a temporary table there will be no metadata lock. */
|
||||||
if (unlikely(error) && has_mdl_lock)
|
if (unlikely(error) && has_mdl_lock)
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
|
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
@ -607,7 +607,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||||||
trans_rollback(thd);
|
trans_rollback(thd);
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
table->table= NULL;
|
table->table= NULL;
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str,
|
MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str,
|
||||||
table->table_name.str, MDL_SHARED_NO_READ_WRITE,
|
table->table_name.str, MDL_SHARED_NO_READ_WRITE,
|
||||||
MDL_TRANSACTION);
|
MDL_TRANSACTION);
|
||||||
@ -668,7 +668,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||||||
trans_rollback_stmt(thd);
|
trans_rollback_stmt(thd);
|
||||||
trans_rollback(thd);
|
trans_rollback(thd);
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
DBUG_PRINT("admin", ("simple error, admin next table"));
|
DBUG_PRINT("admin", ("simple error, admin next table"));
|
||||||
continue;
|
continue;
|
||||||
case -1: // error, message could be written to net
|
case -1: // error, message could be written to net
|
||||||
@ -735,7 +735,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||||||
trans_commit_stmt(thd);
|
trans_commit_stmt(thd);
|
||||||
trans_commit(thd);
|
trans_commit(thd);
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
lex->reset_query_tables_list(FALSE);
|
lex->reset_query_tables_list(FALSE);
|
||||||
/*
|
/*
|
||||||
Restore Query_tables_list::sql_command value to make statement
|
Restore Query_tables_list::sql_command value to make statement
|
||||||
@ -868,7 +868,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||||||
thd->open_options|= extra_open_options;
|
thd->open_options|= extra_open_options;
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
table->table= NULL;
|
table->table= NULL;
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str,
|
MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str,
|
||||||
table->table_name.str, MDL_SHARED_NO_READ_WRITE,
|
table->table_name.str, MDL_SHARED_NO_READ_WRITE,
|
||||||
MDL_TRANSACTION);
|
MDL_TRANSACTION);
|
||||||
@ -1099,7 +1099,7 @@ send_result_message:
|
|||||||
trans_commit_stmt(thd);
|
trans_commit_stmt(thd);
|
||||||
trans_commit(thd);
|
trans_commit(thd);
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
/* Clear references to TABLE and MDL_ticket after releasing them. */
|
/* Clear references to TABLE and MDL_ticket after releasing them. */
|
||||||
table->mdl_request.ticket= NULL;
|
table->mdl_request.ticket= NULL;
|
||||||
|
|
||||||
@ -1258,7 +1258,7 @@ send_result_message:
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If it is CHECK TABLE v1, v2, v3, and v1, v2, v3 are views, we will run
|
If it is CHECK TABLE v1, v2, v3, and v1, v2, v3 are views, we will run
|
||||||
@ -1296,7 +1296,7 @@ err:
|
|||||||
table->table= 0;
|
table->table= 0;
|
||||||
}
|
}
|
||||||
close_thread_tables(thd); // Shouldn't be needed
|
close_thread_tables(thd); // Shouldn't be needed
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
thd->resume_subsequent_commits(suspended_wfc);
|
thd->resume_subsequent_commits(suspended_wfc);
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
@ -9040,9 +9040,12 @@ void
|
|||||||
close_mysql_tables(THD *thd)
|
close_mysql_tables(THD *thd)
|
||||||
{
|
{
|
||||||
if (! thd->in_sub_stmt)
|
if (! thd->in_sub_stmt)
|
||||||
|
{
|
||||||
trans_commit_stmt(thd);
|
trans_commit_stmt(thd);
|
||||||
|
trans_commit(thd);
|
||||||
|
}
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1565,7 +1565,7 @@ void THD::cleanup(void)
|
|||||||
and left the mode a few lines above), there will be outstanding
|
and left the mode a few lines above), there will be outstanding
|
||||||
metadata locks. Release them.
|
metadata locks. Release them.
|
||||||
*/
|
*/
|
||||||
mdl_context.release_transactional_locks();
|
mdl_context.release_transactional_locks(this);
|
||||||
|
|
||||||
backup_end(this);
|
backup_end(this);
|
||||||
backup_unlock(this);
|
backup_unlock(this);
|
||||||
@ -4919,7 +4919,7 @@ void destroy_background_thd(MYSQL_THD thd)
|
|||||||
void reset_thd(MYSQL_THD thd)
|
void reset_thd(MYSQL_THD thd)
|
||||||
{
|
{
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
thd->free_items();
|
thd->free_items();
|
||||||
free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
|
free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
|
||||||
}
|
}
|
||||||
|
@ -4730,6 +4730,13 @@ public:
|
|||||||
locked_tables_mode= mode_arg;
|
locked_tables_mode= mode_arg;
|
||||||
}
|
}
|
||||||
void leave_locked_tables_mode();
|
void leave_locked_tables_mode();
|
||||||
|
/* Relesae transactional locks if there are no active transactions */
|
||||||
|
void release_transactional_locks()
|
||||||
|
{
|
||||||
|
if (!(server_status &
|
||||||
|
(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY)))
|
||||||
|
mdl_context.release_transactional_locks(this);
|
||||||
|
}
|
||||||
int decide_logging_format(TABLE_LIST *tables);
|
int decide_logging_format(TABLE_LIST *tables);
|
||||||
/*
|
/*
|
||||||
In Some cases when decide_logging_format is called it does not have all
|
In Some cases when decide_logging_format is called it does not have all
|
||||||
|
@ -248,7 +248,7 @@ int update_portion_of_time(THD *thd, TABLE *table,
|
|||||||
uint dst_fieldno= lcond ? table->s->period.end_fieldno
|
uint dst_fieldno= lcond ? table->s->period.end_fieldno
|
||||||
: table->s->period.start_fieldno;
|
: table->s->period.start_fieldno;
|
||||||
|
|
||||||
table->file->store_auto_increment();
|
ulonglong prev_insert_id= table->file->next_insert_id;
|
||||||
store_record(table, record[1]);
|
store_record(table, record[1]);
|
||||||
if (likely(!res))
|
if (likely(!res))
|
||||||
res= src->save_in_field(table->field[dst_fieldno], true);
|
res= src->save_in_field(table->field[dst_fieldno], true);
|
||||||
@ -264,7 +264,7 @@ int update_portion_of_time(THD *thd, TABLE *table,
|
|||||||
TRG_ACTION_AFTER, true);
|
TRG_ACTION_AFTER, true);
|
||||||
restore_record(table, record[1]);
|
restore_record(table, record[1]);
|
||||||
if (res)
|
if (res)
|
||||||
table->file->restore_auto_increment();
|
table->file->restore_auto_increment(prev_insert_id);
|
||||||
|
|
||||||
if (likely(!res) && lcond && rcond)
|
if (likely(!res) && lcond && rcond)
|
||||||
res= table->period_make_insert(period_conds.end.item,
|
res= table->period_make_insert(period_conds.end.item,
|
||||||
|
@ -1401,7 +1401,8 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
|
|||||||
DBUG_RETURN(false);
|
DBUG_RETURN(false);
|
||||||
|
|
||||||
st_select_lex_unit *unit= derived->get_unit();
|
st_select_lex_unit *unit= derived->get_unit();
|
||||||
st_select_lex *sl= unit->first_select();
|
st_select_lex *first_sl= unit->first_select();
|
||||||
|
st_select_lex *sl= first_sl;
|
||||||
|
|
||||||
if (derived->prohibit_cond_pushdown)
|
if (derived->prohibit_cond_pushdown)
|
||||||
DBUG_RETURN(false);
|
DBUG_RETURN(false);
|
||||||
@ -1460,6 +1461,20 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
|
|||||||
if (!extracted_cond_copy)
|
if (!extracted_cond_copy)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rename the columns of all non-first selects of a union to be compatible
|
||||||
|
by names with the columns of the first select. It will allow to use copies
|
||||||
|
of the same expression pushed into having clauses of different selects.
|
||||||
|
*/
|
||||||
|
if (sl != first_sl)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(sl->item_list.elements == first_sl->item_list.elements);
|
||||||
|
List_iterator_fast<Item> it(sl->item_list);
|
||||||
|
List_iterator_fast<Item> nm_it(unit->types);
|
||||||
|
while (Item *item= it++)
|
||||||
|
item->share_name_with(nm_it++);
|
||||||
|
}
|
||||||
|
|
||||||
/* Collect fields that are used in the GROUP BY of sl */
|
/* Collect fields that are used in the GROUP BY of sl */
|
||||||
if (sl->have_window_funcs())
|
if (sl->have_window_funcs())
|
||||||
{
|
{
|
||||||
|
@ -1769,7 +1769,7 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink)
|
|||||||
int error, trg_error= 0;
|
int error, trg_error= 0;
|
||||||
char *key=0;
|
char *key=0;
|
||||||
MY_BITMAP *save_read_set, *save_write_set;
|
MY_BITMAP *save_read_set, *save_write_set;
|
||||||
table->file->store_auto_increment();
|
ulonglong prev_insert_id= table->file->next_insert_id;
|
||||||
ulonglong insert_id_for_cur_row= 0;
|
ulonglong insert_id_for_cur_row= 0;
|
||||||
ulonglong prev_insert_id_for_cur_row= 0;
|
ulonglong prev_insert_id_for_cur_row= 0;
|
||||||
DBUG_ENTER("write_record");
|
DBUG_ENTER("write_record");
|
||||||
@ -1918,7 +1918,7 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink)
|
|||||||
if (res == VIEW_CHECK_ERROR)
|
if (res == VIEW_CHECK_ERROR)
|
||||||
goto before_trg_err;
|
goto before_trg_err;
|
||||||
|
|
||||||
table->file->restore_auto_increment();
|
table->file->restore_auto_increment(prev_insert_id);
|
||||||
info->touched++;
|
info->touched++;
|
||||||
if (different_records)
|
if (different_records)
|
||||||
{
|
{
|
||||||
@ -2110,7 +2110,7 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink)
|
|||||||
if (!(thd->variables.old_behavior &
|
if (!(thd->variables.old_behavior &
|
||||||
OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE))
|
OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE))
|
||||||
table->file->print_error(error, MYF(ME_WARNING));
|
table->file->print_error(error, MYF(ME_WARNING));
|
||||||
table->file->restore_auto_increment();
|
table->file->restore_auto_increment(prev_insert_id);
|
||||||
goto after_trg_or_ignored_err;
|
goto after_trg_or_ignored_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2143,7 +2143,7 @@ err:
|
|||||||
table->file->print_error(error,MYF(0));
|
table->file->print_error(error,MYF(0));
|
||||||
|
|
||||||
before_trg_err:
|
before_trg_err:
|
||||||
table->file->restore_auto_increment();
|
table->file->restore_auto_increment(prev_insert_id);
|
||||||
if (key)
|
if (key)
|
||||||
my_safe_afree(key, table->s->max_unique_length);
|
my_safe_afree(key, table->s->max_unique_length);
|
||||||
table->column_bitmaps_set(save_read_set, save_write_set);
|
table->column_bitmaps_set(save_read_set, save_write_set);
|
||||||
@ -2297,7 +2297,7 @@ public:
|
|||||||
if (table)
|
if (table)
|
||||||
{
|
{
|
||||||
close_thread_tables(&thd);
|
close_thread_tables(&thd);
|
||||||
thd.mdl_context.release_transactional_locks();
|
thd.mdl_context.release_transactional_locks(&thd);
|
||||||
}
|
}
|
||||||
mysql_mutex_destroy(&mutex);
|
mysql_mutex_destroy(&mutex);
|
||||||
mysql_cond_destroy(&cond);
|
mysql_cond_destroy(&cond);
|
||||||
@ -3130,7 +3130,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
|||||||
if (thd->mdl_context.clone_ticket(&di->grl_protection) ||
|
if (thd->mdl_context.clone_ticket(&di->grl_protection) ||
|
||||||
thd->mdl_context.clone_ticket(&di->table_list.mdl_request))
|
thd->mdl_context.clone_ticket(&di->table_list.mdl_request))
|
||||||
{
|
{
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
di->handler_thread_initialized= TRUE;
|
di->handler_thread_initialized= TRUE;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -3356,7 +3356,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
|||||||
thd->set_killed(KILL_CONNECTION_HARD); // If error
|
thd->set_killed(KILL_CONNECTION_HARD); // If error
|
||||||
|
|
||||||
close_thread_tables(thd); // Free the table
|
close_thread_tables(thd); // Free the table
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
mysql_cond_broadcast(&di->cond_client); // Safety
|
mysql_cond_broadcast(&di->cond_client); // Safety
|
||||||
|
|
||||||
mysql_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table
|
mysql_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table
|
||||||
@ -4971,6 +4971,7 @@ bool select_create::send_eof()
|
|||||||
WSREP_ERROR("Appending table key for CTAS failed: %s, %d",
|
WSREP_ERROR("Appending table key for CTAS failed: %s, %d",
|
||||||
(wsrep_thd_query(thd)) ?
|
(wsrep_thd_query(thd)) ?
|
||||||
wsrep_thd_query(thd) : "void", rcode);
|
wsrep_thd_query(thd) : "void", rcode);
|
||||||
|
abort_result_set();
|
||||||
DBUG_RETURN(true);
|
DBUG_RETURN(true);
|
||||||
}
|
}
|
||||||
/* If commit fails, we should be able to reset the OK status. */
|
/* If commit fails, we should be able to reset the OK status. */
|
||||||
|
@ -2088,7 +2088,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||||||
locks.
|
locks.
|
||||||
*/
|
*/
|
||||||
trans_rollback_implicit(thd);
|
trans_rollback_implicit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->cleanup_after_query();
|
thd->cleanup_after_query();
|
||||||
@ -2153,7 +2153,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||||||
ulonglong options= (ulonglong) (uchar) packet[0];
|
ulonglong options= (ulonglong) (uchar) packet[0];
|
||||||
if (trans_commit_implicit(thd))
|
if (trans_commit_implicit(thd))
|
||||||
break;
|
break;
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
if (check_global_access(thd,RELOAD_ACL))
|
if (check_global_access(thd,RELOAD_ACL))
|
||||||
break;
|
break;
|
||||||
general_log_print(thd, command, NullS);
|
general_log_print(thd, command, NullS);
|
||||||
@ -2188,7 +2188,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||||||
if (trans_commit_implicit(thd))
|
if (trans_commit_implicit(thd))
|
||||||
break;
|
break;
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
my_ok(thd);
|
my_ok(thd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3031,7 +3031,7 @@ err:
|
|||||||
/* Close tables and release metadata locks. */
|
/* Close tables and release metadata locks. */
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
DBUG_ASSERT(!thd->locked_tables_mode);
|
DBUG_ASSERT(!thd->locked_tables_mode);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3776,7 +3776,7 @@ mysql_execute_command(THD *thd)
|
|||||||
/* Commit the normal transaction if one is active. */
|
/* Commit the normal transaction if one is active. */
|
||||||
bool commit_failed= trans_commit_implicit(thd);
|
bool commit_failed= trans_commit_implicit(thd);
|
||||||
/* Release metadata locks acquired in this transaction. */
|
/* Release metadata locks acquired in this transaction. */
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
if (commit_failed)
|
if (commit_failed)
|
||||||
{
|
{
|
||||||
WSREP_DEBUG("implicit commit failed, MDL released: %lld",
|
WSREP_DEBUG("implicit commit failed, MDL released: %lld",
|
||||||
@ -5087,7 +5087,7 @@ mysql_execute_command(THD *thd)
|
|||||||
res= trans_commit_implicit(thd);
|
res= trans_commit_implicit(thd);
|
||||||
if (thd->locked_tables_list.unlock_locked_tables(thd))
|
if (thd->locked_tables_list.unlock_locked_tables(thd))
|
||||||
res= 1;
|
res= 1;
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
|
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
|
||||||
thd->reset_binlog_for_next_statement();
|
thd->reset_binlog_for_next_statement();
|
||||||
}
|
}
|
||||||
@ -5104,7 +5104,7 @@ mysql_execute_command(THD *thd)
|
|||||||
if (thd->locked_tables_list.unlock_locked_tables(thd))
|
if (thd->locked_tables_list.unlock_locked_tables(thd))
|
||||||
res= 1;
|
res= 1;
|
||||||
/* Release transactional metadata locks. */
|
/* Release transactional metadata locks. */
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
if (res)
|
if (res)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -5620,7 +5620,7 @@ mysql_execute_command(THD *thd)
|
|||||||
DBUG_PRINT("info", ("Executing SQLCOM_BEGIN thd: %p", thd));
|
DBUG_PRINT("info", ("Executing SQLCOM_BEGIN thd: %p", thd));
|
||||||
if (trans_begin(thd, lex->start_transaction_opt))
|
if (trans_begin(thd, lex->start_transaction_opt))
|
||||||
{
|
{
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
WSREP_DEBUG("BEGIN failed, MDL released: %lld",
|
WSREP_DEBUG("BEGIN failed, MDL released: %lld",
|
||||||
(longlong) thd->thread_id);
|
(longlong) thd->thread_id);
|
||||||
WSREP_DEBUG("stmt_da, sql_errno: %d", (thd->get_stmt_da()->is_error()) ? thd->get_stmt_da()->sql_errno() : 0);
|
WSREP_DEBUG("stmt_da, sql_errno: %d", (thd->get_stmt_da()->is_error()) ? thd->get_stmt_da()->sql_errno() : 0);
|
||||||
@ -5639,7 +5639,7 @@ mysql_execute_command(THD *thd)
|
|||||||
(thd->variables.completion_type == 2 &&
|
(thd->variables.completion_type == 2 &&
|
||||||
lex->tx_release != TVL_NO));
|
lex->tx_release != TVL_NO));
|
||||||
bool commit_failed= trans_commit(thd);
|
bool commit_failed= trans_commit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
if (commit_failed)
|
if (commit_failed)
|
||||||
{
|
{
|
||||||
WSREP_DEBUG("COMMIT failed, MDL released: %lld",
|
WSREP_DEBUG("COMMIT failed, MDL released: %lld",
|
||||||
@ -5677,7 +5677,7 @@ mysql_execute_command(THD *thd)
|
|||||||
(thd->variables.completion_type == 2 &&
|
(thd->variables.completion_type == 2 &&
|
||||||
lex->tx_release != TVL_NO));
|
lex->tx_release != TVL_NO));
|
||||||
bool rollback_failed= trans_rollback(thd);
|
bool rollback_failed= trans_rollback(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
|
|
||||||
if (rollback_failed)
|
if (rollback_failed)
|
||||||
{
|
{
|
||||||
@ -5864,7 +5864,6 @@ mysql_execute_command(THD *thd)
|
|||||||
case SQLCOM_XA_COMMIT:
|
case SQLCOM_XA_COMMIT:
|
||||||
{
|
{
|
||||||
bool commit_failed= trans_xa_commit(thd);
|
bool commit_failed= trans_xa_commit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
|
||||||
if (commit_failed)
|
if (commit_failed)
|
||||||
{
|
{
|
||||||
WSREP_DEBUG("XA commit failed, MDL released: %lld",
|
WSREP_DEBUG("XA commit failed, MDL released: %lld",
|
||||||
@ -5882,7 +5881,6 @@ mysql_execute_command(THD *thd)
|
|||||||
case SQLCOM_XA_ROLLBACK:
|
case SQLCOM_XA_ROLLBACK:
|
||||||
{
|
{
|
||||||
bool rollback_failed= trans_xa_rollback(thd);
|
bool rollback_failed= trans_xa_rollback(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
|
||||||
if (rollback_failed)
|
if (rollback_failed)
|
||||||
{
|
{
|
||||||
WSREP_DEBUG("XA rollback failed, MDL released: %lld",
|
WSREP_DEBUG("XA rollback failed, MDL released: %lld",
|
||||||
@ -6093,7 +6091,7 @@ finish:
|
|||||||
*/
|
*/
|
||||||
THD_STAGE_INFO(thd, stage_rollback_implicit);
|
THD_STAGE_INFO(thd, stage_rollback_implicit);
|
||||||
trans_rollback_implicit(thd);
|
trans_rollback_implicit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
else if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
|
else if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
|
||||||
{
|
{
|
||||||
@ -6107,7 +6105,7 @@ finish:
|
|||||||
/* Commit the normal transaction if one is active. */
|
/* Commit the normal transaction if one is active. */
|
||||||
trans_commit_implicit(thd);
|
trans_commit_implicit(thd);
|
||||||
thd->get_stmt_da()->set_overwrite_status(false);
|
thd->get_stmt_da()->set_overwrite_status(false);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
|
else if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
|
||||||
@ -6122,7 +6120,7 @@ finish:
|
|||||||
- If in autocommit mode, or outside a transactional context,
|
- If in autocommit mode, or outside a transactional context,
|
||||||
automatically release metadata locks of the current statement.
|
automatically release metadata locks of the current statement.
|
||||||
*/
|
*/
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
else if (! thd->in_sub_stmt)
|
else if (! thd->in_sub_stmt)
|
||||||
{
|
{
|
||||||
@ -6147,7 +6145,7 @@ finish:
|
|||||||
{
|
{
|
||||||
WSREP_DEBUG("Forcing release of transactional locks for thd: %lld",
|
WSREP_DEBUG("Forcing release of transactional locks for thd: %lld",
|
||||||
(longlong) thd->thread_id);
|
(longlong) thd->thread_id);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4289,7 +4289,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||||||
if (thd->transaction_rollback_request)
|
if (thd->transaction_rollback_request)
|
||||||
{
|
{
|
||||||
trans_rollback_implicit(thd);
|
trans_rollback_implicit(thd);
|
||||||
thd->mdl_context.release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Preserve CHANGE MASTER attributes */
|
/* Preserve CHANGE MASTER attributes */
|
||||||
|
@ -24256,8 +24256,7 @@ cmp_buffer_with_ref(THD *thd, TABLE *table, TABLE_REF *tab_ref)
|
|||||||
bool
|
bool
|
||||||
cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
|
cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
|
||||||
{
|
{
|
||||||
enum enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
|
Check_level_instant_set check_level_save(thd, CHECK_FIELD_IGNORE);
|
||||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
|
||||||
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
|
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
|
||||||
bool result= 0;
|
bool result= 0;
|
||||||
|
|
||||||
@ -24269,7 +24268,6 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thd->count_cuted_fields= save_count_cuted_fields;
|
|
||||||
dbug_tmp_restore_column_map(table->write_set, old_map);
|
dbug_tmp_restore_column_map(table->write_set, old_map);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1902,18 +1902,11 @@ public:
|
|||||||
{
|
{
|
||||||
enum store_key_result result;
|
enum store_key_result result;
|
||||||
THD *thd= to_field->table->in_use;
|
THD *thd= to_field->table->in_use;
|
||||||
enum_check_fields saved_count_cuted_fields= thd->count_cuted_fields;
|
Check_level_instant_set check_level_save(thd, CHECK_FIELD_IGNORE);
|
||||||
sql_mode_t orig_sql_mode= thd->variables.sql_mode;
|
Sql_mode_save sql_mode(thd);
|
||||||
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
|
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
|
||||||
thd->variables.sql_mode|= MODE_INVALID_DATES;
|
thd->variables.sql_mode|= MODE_INVALID_DATES;
|
||||||
|
|
||||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
|
||||||
|
|
||||||
result= copy_inner();
|
result= copy_inner();
|
||||||
|
|
||||||
thd->count_cuted_fields= saved_count_cuted_fields;
|
|
||||||
thd->variables.sql_mode= orig_sql_mode;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3671,7 +3671,6 @@ static bool show_status_array(THD *thd, const char *wild,
|
|||||||
char name_buffer[NAME_CHAR_LEN];
|
char name_buffer[NAME_CHAR_LEN];
|
||||||
int len;
|
int len;
|
||||||
SHOW_VAR tmp, *var;
|
SHOW_VAR tmp, *var;
|
||||||
enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
|
|
||||||
bool res= FALSE;
|
bool res= FALSE;
|
||||||
CHARSET_INFO *charset= system_charset_info;
|
CHARSET_INFO *charset= system_charset_info;
|
||||||
DBUG_ENTER("show_status_array");
|
DBUG_ENTER("show_status_array");
|
||||||
@ -3794,7 +3793,6 @@ static bool show_status_array(THD *thd, const char *wild,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
thd->count_cuted_fields= save_count_cuted_fields;
|
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4521,8 +4519,7 @@ fill_schema_table_by_open(THD *thd, MEM_ROOT *mem_root,
|
|||||||
Open_tables_backup *open_tables_state_backup,
|
Open_tables_backup *open_tables_state_backup,
|
||||||
bool can_deadlock)
|
bool can_deadlock)
|
||||||
{
|
{
|
||||||
Query_arena i_s_arena(mem_root,
|
Query_arena i_s_arena(mem_root, Query_arena::STMT_CONVENTIONAL_EXECUTION),
|
||||||
Query_arena::STMT_CONVENTIONAL_EXECUTION),
|
|
||||||
backup_arena, *old_arena;
|
backup_arena, *old_arena;
|
||||||
LEX *old_lex= thd->lex, temp_lex, *lex;
|
LEX *old_lex= thd->lex, temp_lex, *lex;
|
||||||
LEX_CSTRING db_name, table_name;
|
LEX_CSTRING db_name, table_name;
|
||||||
@ -5037,12 +5034,9 @@ end:
|
|||||||
class Warnings_only_error_handler : public Internal_error_handler
|
class Warnings_only_error_handler : public Internal_error_handler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool handle_condition(THD *thd,
|
bool handle_condition(THD *thd, uint sql_errno, const char* sqlstate,
|
||||||
uint sql_errno,
|
|
||||||
const char* sqlstate,
|
|
||||||
Sql_condition::enum_warning_level *level,
|
Sql_condition::enum_warning_level *level,
|
||||||
const char* msg,
|
const char* msg, Sql_condition ** cond_hdl)
|
||||||
Sql_condition ** cond_hdl)
|
|
||||||
{
|
{
|
||||||
if (sql_errno == ER_TRG_NO_DEFINER || sql_errno == ER_TRG_NO_CREATION_CTX)
|
if (sql_errno == ER_TRG_NO_DEFINER || sql_errno == ER_TRG_NO_CREATION_CTX)
|
||||||
return true;
|
return true;
|
||||||
@ -8493,13 +8487,6 @@ static int optimize_schema_tables_memory_usage(TABLE_LIST *table_list)
|
|||||||
DBUG_ASSERT(table->s->keys == 0);
|
DBUG_ASSERT(table->s->keys == 0);
|
||||||
DBUG_ASSERT(table->s->uniques == 0);
|
DBUG_ASSERT(table->s->uniques == 0);
|
||||||
|
|
||||||
// XXX HACK HACK HACK: in a stored function, RETURN (SELECT ...)
|
|
||||||
// enables warnings (in THD::sp_eval_expr) for the whole val_xxx/store pair,
|
|
||||||
// while the intention is to warn only for store(). Until this is
|
|
||||||
// fixed let's avoid data truncation warnings in I_S->fill_table()
|
|
||||||
if (thd->count_cuted_fields == CHECK_FIELD_IGNORE)
|
|
||||||
{
|
|
||||||
|
|
||||||
uchar *cur= table->field[0]->ptr;
|
uchar *cur= table->field[0]->ptr;
|
||||||
/* first recinfo could be a NULL bitmap, not an actual Field */
|
/* first recinfo could be a NULL bitmap, not an actual Field */
|
||||||
from_recinfo= to_recinfo= p->start_recinfo + (cur != table->record[0]);
|
from_recinfo= to_recinfo= p->start_recinfo + (cur != table->record[0]);
|
||||||
@ -8533,7 +8520,6 @@ static int optimize_schema_tables_memory_usage(TABLE_LIST *table_list)
|
|||||||
to_recinfo++;
|
to_recinfo++;
|
||||||
}
|
}
|
||||||
p->recinfo= to_recinfo;
|
p->recinfo= to_recinfo;
|
||||||
} // XXX end of HACK HACK HACK
|
|
||||||
|
|
||||||
// TODO switch from Aria to Memory if all blobs were optimized away?
|
// TODO switch from Aria to Memory if all blobs were optimized away?
|
||||||
if (instantiate_tmp_table(table, p->keyinfo, p->start_recinfo, &p->recinfo,
|
if (instantiate_tmp_table(table, p->keyinfo, p->start_recinfo, &p->recinfo,
|
||||||
@ -8696,6 +8682,7 @@ bool get_schema_tables_result(JOIN *join,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Switch_to_definer_security_ctx backup_ctx(thd, table_list);
|
Switch_to_definer_security_ctx backup_ctx(thd, table_list);
|
||||||
|
Check_level_instant_set check_level_save(thd, CHECK_FIELD_IGNORE);
|
||||||
if (table_list->schema_table->fill_table(thd, table_list, cond))
|
if (table_list->schema_table->fill_table(thd, table_list, cond))
|
||||||
{
|
{
|
||||||
result= 1;
|
result= 1;
|
||||||
|
@ -2899,7 +2899,6 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
|
|||||||
Field **field_ptr;
|
Field **field_ptr;
|
||||||
KEY *key_info, *key_info_end;
|
KEY *key_info, *key_info_end;
|
||||||
TABLE_SHARE *table_share= table->s;
|
TABLE_SHARE *table_share= table->s;
|
||||||
enum_check_fields old_check_level= thd->count_cuted_fields;
|
|
||||||
|
|
||||||
DBUG_ENTER("read_statistics_for_table");
|
DBUG_ENTER("read_statistics_for_table");
|
||||||
DEBUG_SYNC(thd, "statistics_mem_alloc_start1");
|
DEBUG_SYNC(thd, "statistics_mem_alloc_start1");
|
||||||
@ -2915,7 +2914,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Don't write warnings for internal field conversions */
|
/* Don't write warnings for internal field conversions */
|
||||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
Check_level_instant_set check_level_save(thd, CHECK_FIELD_IGNORE);
|
||||||
|
|
||||||
/* Read statistics from the statistical table table_stats */
|
/* Read statistics from the statistical table table_stats */
|
||||||
Table_statistics *read_stats= table_share->stats_cb.table_stats;
|
Table_statistics *read_stats= table_share->stats_cb.table_stats;
|
||||||
@ -2997,7 +2996,6 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->count_cuted_fields= old_check_level;
|
|
||||||
table_share->stats_cb.end_stats_load();
|
table_share->stats_cb.end_stats_load();
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
@ -10636,16 +10636,14 @@ do_continue:;
|
|||||||
if (use_inplace)
|
if (use_inplace)
|
||||||
{
|
{
|
||||||
table->s->frm_image= &frm;
|
table->s->frm_image= &frm;
|
||||||
enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
|
|
||||||
/*
|
/*
|
||||||
Set the truncated column values of thd as warning
|
Set the truncated column values of thd as warning
|
||||||
for alter table.
|
for alter table.
|
||||||
*/
|
*/
|
||||||
thd->count_cuted_fields = CHECK_FIELD_WARN;
|
Check_level_instant_set check_level_save(thd, CHECK_FIELD_WARN);
|
||||||
int res= mysql_inplace_alter_table(thd, table_list, table, &altered_table,
|
int res= mysql_inplace_alter_table(thd, table_list, table, &altered_table,
|
||||||
&ha_alter_info,
|
&ha_alter_info,
|
||||||
&target_mdl_request, &alter_ctx);
|
&target_mdl_request, &alter_ctx);
|
||||||
thd->count_cuted_fields= save_count_cuted_fields;
|
|
||||||
my_free(const_cast<uchar*>(frm.str));
|
my_free(const_cast<uchar*>(frm.str));
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2017, MariaDB
|
/* Copyright (c) 2017, 2020, MariaDB
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -861,7 +861,8 @@ static bool cmp_row_types(Item* item1, Item* item2)
|
|||||||
Item *inner= item1->element_index(i);
|
Item *inner= item1->element_index(i);
|
||||||
Item *outer= item2->element_index(i);
|
Item *outer= item2->element_index(i);
|
||||||
if (!inner->type_handler()->subquery_type_allows_materialization(inner,
|
if (!inner->type_handler()->subquery_type_allows_materialization(inner,
|
||||||
outer))
|
outer,
|
||||||
|
true))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -942,7 +943,7 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmp_row_types(args[0], args[i]))
|
if (cmp_row_types(args[i], args[0]))
|
||||||
{
|
{
|
||||||
trace_conv.add("done", false);
|
trace_conv.add("done", false);
|
||||||
trace_conv.add("reason", "type mismatch");
|
trace_conv.add("reason", "type mismatch");
|
||||||
@ -1027,6 +1028,7 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
|
|||||||
if (!(in_subs=
|
if (!(in_subs=
|
||||||
new (thd->mem_root) Item_in_subselect(thd, args[0], sq_select)))
|
new (thd->mem_root) Item_in_subselect(thd, args[0], sq_select)))
|
||||||
goto err;
|
goto err;
|
||||||
|
in_subs->converted_from_in_predicate= TRUE;
|
||||||
sq= in_subs;
|
sq= in_subs;
|
||||||
if (negated)
|
if (negated)
|
||||||
sq= negate_expression(thd, in_subs);
|
sq= negate_expression(thd, in_subs);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "sql_const.h"
|
#include "sql_const.h"
|
||||||
#include "sql_class.h"
|
#include "sql_class.h"
|
||||||
#include "sql_time.h"
|
#include "sql_time.h"
|
||||||
|
#include "sql_string.h"
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "tztime.h"
|
#include "tztime.h"
|
||||||
@ -7077,7 +7078,8 @@ uint Type_handler_timestamp_common::Item_decimal_precision(const Item *item) con
|
|||||||
|
|
||||||
bool Type_handler_real_result::
|
bool Type_handler_real_result::
|
||||||
subquery_type_allows_materialization(const Item *inner,
|
subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const
|
const Item *outer,
|
||||||
|
bool is_in_predicate) const
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(inner->cmp_type() == REAL_RESULT);
|
DBUG_ASSERT(inner->cmp_type() == REAL_RESULT);
|
||||||
return outer->cmp_type() == REAL_RESULT;
|
return outer->cmp_type() == REAL_RESULT;
|
||||||
@ -7086,7 +7088,8 @@ bool Type_handler_real_result::
|
|||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
subquery_type_allows_materialization(const Item *inner,
|
subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const
|
const Item *outer,
|
||||||
|
bool is_in_predicate) const
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(inner->cmp_type() == INT_RESULT);
|
DBUG_ASSERT(inner->cmp_type() == INT_RESULT);
|
||||||
return outer->cmp_type() == INT_RESULT;
|
return outer->cmp_type() == INT_RESULT;
|
||||||
@ -7095,7 +7098,8 @@ bool Type_handler_int_result::
|
|||||||
|
|
||||||
bool Type_handler_decimal_result::
|
bool Type_handler_decimal_result::
|
||||||
subquery_type_allows_materialization(const Item *inner,
|
subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const
|
const Item *outer,
|
||||||
|
bool is_in_predicate) const
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(inner->cmp_type() == DECIMAL_RESULT);
|
DBUG_ASSERT(inner->cmp_type() == DECIMAL_RESULT);
|
||||||
return outer->cmp_type() == DECIMAL_RESULT;
|
return outer->cmp_type() == DECIMAL_RESULT;
|
||||||
@ -7104,23 +7108,37 @@ bool Type_handler_decimal_result::
|
|||||||
|
|
||||||
bool Type_handler_string_result::
|
bool Type_handler_string_result::
|
||||||
subquery_type_allows_materialization(const Item *inner,
|
subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const
|
const Item *outer,
|
||||||
|
bool is_in_predicate) const
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(inner->cmp_type() == STRING_RESULT);
|
DBUG_ASSERT(inner->cmp_type() == STRING_RESULT);
|
||||||
return outer->cmp_type() == STRING_RESULT &&
|
if (outer->cmp_type() == STRING_RESULT &&
|
||||||
outer->collation.collation == inner->collation.collation &&
|
/*
|
||||||
/*
|
Materialization also is unable to work when create_tmp_table() will
|
||||||
Materialization also is unable to work when create_tmp_table() will
|
create a blob column because item->max_length is too big.
|
||||||
create a blob column because item->max_length is too big.
|
The following test is copied from varstring_type_handler().
|
||||||
The following test is copied from varstring_type_handler().
|
*/
|
||||||
*/
|
!inner->too_big_for_varchar())
|
||||||
!inner->too_big_for_varchar();
|
{
|
||||||
|
if (outer->collation.collation == inner->collation.collation)
|
||||||
|
return true;
|
||||||
|
if (is_in_predicate)
|
||||||
|
{
|
||||||
|
Charset inner_col(inner->collation.collation);
|
||||||
|
if (inner_col.encoding_allows_reinterpret_as(outer->
|
||||||
|
collation.collation) &&
|
||||||
|
inner_col.eq_collation_specific_names(outer->collation.collation))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_temporal_result::
|
bool Type_handler_temporal_result::
|
||||||
subquery_type_allows_materialization(const Item *inner,
|
subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const
|
const Item *outer,
|
||||||
|
bool is_in_predicate) const
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(inner->cmp_type() == TIME_RESULT);
|
DBUG_ASSERT(inner->cmp_type() == TIME_RESULT);
|
||||||
return mysql_timestamp_type() ==
|
return mysql_timestamp_type() ==
|
||||||
|
@ -4049,9 +4049,21 @@ public:
|
|||||||
Item *target_expr, Item *target_value,
|
Item *target_expr, Item *target_value,
|
||||||
Item_bool_func2 *source,
|
Item_bool_func2 *source,
|
||||||
Item *source_expr, Item *source_const) const= 0;
|
Item *source_expr, Item *source_const) const= 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@brief
|
||||||
|
Check if an IN subquery allows materialization or not
|
||||||
|
@param
|
||||||
|
inner expression on the inner side of the IN subquery
|
||||||
|
outer expression on the outer side of the IN subquery
|
||||||
|
is_in_predicate SET to true if IN subquery was converted from an
|
||||||
|
IN predicate or we are checking if materialization
|
||||||
|
strategy can be used for an IN predicate
|
||||||
|
*/
|
||||||
virtual bool
|
virtual bool
|
||||||
subquery_type_allows_materialization(const Item *inner,
|
subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const= 0;
|
const Item *outer,
|
||||||
|
bool is_in_predicate) const= 0;
|
||||||
/**
|
/**
|
||||||
Make a simple constant replacement item for a constant "src",
|
Make a simple constant replacement item for a constant "src",
|
||||||
so the new item can futher be used for comparison with "cmp", e.g.:
|
so the new item can futher be used for comparison with "cmp", e.g.:
|
||||||
@ -4311,8 +4323,8 @@ public:
|
|||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
bool subquery_type_allows_materialization(const Item *inner,
|
bool subquery_type_allows_materialization(const Item *, const Item *,
|
||||||
const Item *outer) const override
|
bool) const override
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
return false;
|
return false;
|
||||||
@ -4714,7 +4726,8 @@ public:
|
|||||||
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
|
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
|
||||||
const override;
|
const override;
|
||||||
bool subquery_type_allows_materialization(const Item *inner,
|
bool subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer)
|
const Item *outer,
|
||||||
|
bool is_in_predicate)
|
||||||
const override;
|
const override;
|
||||||
void make_sort_key_part(uchar *to, Item *item,
|
void make_sort_key_part(uchar *to, Item *item,
|
||||||
const SORT_FIELD_ATTR *sort_field,
|
const SORT_FIELD_ATTR *sort_field,
|
||||||
@ -4819,7 +4832,9 @@ public:
|
|||||||
return item_val.is_null() ? 0 : my_decimal(field).cmp(item_val.ptr());
|
return item_val.is_null() ? 0 : my_decimal(field).cmp(item_val.ptr());
|
||||||
}
|
}
|
||||||
bool subquery_type_allows_materialization(const Item *inner,
|
bool subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const override;
|
const Item *outer,
|
||||||
|
bool is_in_predicate)
|
||||||
|
const override;
|
||||||
Field *make_schema_field(MEM_ROOT *root,
|
Field *make_schema_field(MEM_ROOT *root,
|
||||||
TABLE *table,
|
TABLE *table,
|
||||||
const Record_addr &addr,
|
const Record_addr &addr,
|
||||||
@ -5073,7 +5088,9 @@ public:
|
|||||||
const Type_handler *type_handler_for_comparison() const override;
|
const Type_handler *type_handler_for_comparison() const override;
|
||||||
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override;
|
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override;
|
||||||
bool subquery_type_allows_materialization(const Item *inner,
|
bool subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const override;
|
const Item *outer,
|
||||||
|
bool is_in_predicate)
|
||||||
|
const override;
|
||||||
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override;
|
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override;
|
||||||
Field *make_table_field(MEM_ROOT *root,
|
Field *make_table_field(MEM_ROOT *root,
|
||||||
const LEX_CSTRING *name,
|
const LEX_CSTRING *name,
|
||||||
@ -5214,7 +5231,9 @@ public:
|
|||||||
Item *source_expr, Item *source_const)
|
Item *source_expr, Item *source_const)
|
||||||
const override;
|
const override;
|
||||||
bool subquery_type_allows_materialization(const Item *inner,
|
bool subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const override;
|
const Item *outer,
|
||||||
|
bool is_in_predicate)
|
||||||
|
const override;
|
||||||
bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
|
bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
|
||||||
Item **items, uint nitems)
|
Item **items, uint nitems)
|
||||||
const override;
|
const override;
|
||||||
@ -5352,7 +5371,9 @@ public:
|
|||||||
Item *source_expr, Item *source_const) const
|
Item *source_expr, Item *source_const) const
|
||||||
override;
|
override;
|
||||||
bool subquery_type_allows_materialization(const Item *inner,
|
bool subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const override;
|
const Item *outer,
|
||||||
|
bool is_in_predicate)
|
||||||
|
const override;
|
||||||
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
|
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
|
||||||
override;
|
override;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
|
||||||
@ -6983,8 +7004,8 @@ public:
|
|||||||
{
|
{
|
||||||
return blob_type_handler(item);
|
return blob_type_handler(item);
|
||||||
}
|
}
|
||||||
bool subquery_type_allows_materialization(const Item *inner,
|
bool subquery_type_allows_materialization(const Item *, const Item *, bool)
|
||||||
const Item *outer) const override
|
const override
|
||||||
{
|
{
|
||||||
return false; // Materialization does not work with BLOB columns
|
return false; // Materialization does not work with BLOB columns
|
||||||
}
|
}
|
||||||
@ -7114,7 +7135,7 @@ public:
|
|||||||
{
|
{
|
||||||
return MYSQL_TYPE_BLOB_COMPRESSED;
|
return MYSQL_TYPE_BLOB_COMPRESSED;
|
||||||
}
|
}
|
||||||
ulong KEY_pack_flags(uint column_nr) const override
|
ulong KEY_pack_flags(uint) const override
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
return 0;
|
return 0;
|
||||||
@ -7125,7 +7146,7 @@ public:
|
|||||||
Field *make_conversion_table_field(MEM_ROOT *root,
|
Field *make_conversion_table_field(MEM_ROOT *root,
|
||||||
TABLE *table, uint metadata,
|
TABLE *table, uint metadata,
|
||||||
const Field *target) const override;
|
const Field *target) const override;
|
||||||
enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
|
enum_dynamic_column_type dyncol_type(const Type_all_attributes *)
|
||||||
const override
|
const override
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
|
@ -67,8 +67,8 @@ public:
|
|||||||
geometry_type() == th->geometry_type();
|
geometry_type() == th->geometry_type();
|
||||||
}
|
}
|
||||||
bool type_can_have_key_part() const override { return true; }
|
bool type_can_have_key_part() const override { return true; }
|
||||||
bool subquery_type_allows_materialization(const Item *inner,
|
bool subquery_type_allows_materialization(const Item *, const Item *, bool)
|
||||||
const Item *outer) const override
|
const override
|
||||||
{
|
{
|
||||||
return false; // Materialization does not work with GEOMETRY columns
|
return false; // Materialization does not work with GEOMETRY columns
|
||||||
}
|
}
|
||||||
|
@ -2747,6 +2747,7 @@ bool st_select_lex::cleanup()
|
|||||||
delete join;
|
delete join;
|
||||||
join= 0;
|
join= 0;
|
||||||
}
|
}
|
||||||
|
leaf_tables.empty();
|
||||||
for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
|
for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
|
||||||
lex_unit= lex_unit->next_unit())
|
lex_unit= lex_unit->next_unit())
|
||||||
{
|
{
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user