From 1cfaafafee1d3e25470508c0479210c615fa3f18 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 5 Oct 2017 13:41:16 +0400 Subject: [PATCH 01/34] MDEV-13242 Wrong results for queries with row constructors and information_schema --- mysql-test/r/information_schema.result | 32 ++++++++++++++++++++++++++ mysql-test/t/information_schema.test | 26 +++++++++++++++++++++ sql/item.h | 2 ++ sql/sql_show.cc | 14 +++++++++++ 4 files changed, 74 insertions(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index cee4797617f..2b5a536308a 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -2069,3 +2069,35 @@ Opened_tables 3 drop database mysqltest; drop database db1; set global sql_mode=default; +USE test; +# +# End of 10.0 tests +# +# +# Start of 10.1 tests +# +# +# MDEV-13242 Wrong results for queries with row constructors and information_schema +# +CREATE TABLE tt1(c1 INT); +CREATE TABLE tt2(c2 INT); +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name, column_name) IN (('tt1', 'c1')); +count(*) +1 +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name, column_name) IN (('tt2', 'c2')); +count(*) +1 +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name, column_name) IN (('tt1','c1'),('tt2', 'c2')); +count(*) +2 +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name, column_name) IN (SELECT 'tt1','c1' FROM dual UNION SELECT 'tt2', 'c2' FROM dual); +count(*) +2 +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name='tt1' AND column_name='c1') OR (table_name='tt2' AND column_name='c2'); +count(*) +2 +SELECT column_name FROM information_schema.columns WHERE (table_name, column_name) IN (('tt1','c1'),('tt2', 'c2')) ORDER BY column_name; +column_name +c1 +c2 +DROP TABLE tt1, tt2; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 5b0e2910889..5b3fa7b653c 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1910,3 +1910,29 @@ disconnect con1; --source include/wait_until_count_sessions.inc set global sql_mode=default; + +USE test; + +--echo # +--echo # End of 10.0 tests +--echo # + + +--echo # +--echo # Start of 10.1 tests +--echo # + + +--echo # +--echo # MDEV-13242 Wrong results for queries with row constructors and information_schema +--echo # + +CREATE TABLE tt1(c1 INT); +CREATE TABLE tt2(c2 INT); +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name, column_name) IN (('tt1', 'c1')); +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name, column_name) IN (('tt2', 'c2')); +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name, column_name) IN (('tt1','c1'),('tt2', 'c2')); +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name, column_name) IN (SELECT 'tt1','c1' FROM dual UNION SELECT 'tt2', 'c2' FROM dual); +SELECT count(*) FROM information_schema.columns WHERE table_schema='test' AND (table_name='tt1' AND column_name='c1') OR (table_name='tt2' AND column_name='c2'); +SELECT column_name FROM information_schema.columns WHERE (table_name, column_name) IN (('tt1','c1'),('tt2', 'c2')) ORDER BY column_name; +DROP TABLE tt1, tt2; diff --git a/sql/item.h b/sql/item.h index c338b14e340..0ca2eaae97c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4131,6 +4131,8 @@ public: bool fix_fields(THD *thd, Item **it); void cleanup(); + Item *get_orig_item() const { return orig_item; } + /* Methods of getting value which should be cached in the cache */ void save_val(Field *to); double val_real(); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 953842e29d1..1fdab201158 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3640,6 +3640,15 @@ bool uses_only_table_name_fields(Item *item, TABLE_LIST *table) return 0; } } + else if (item->type() == Item::ROW_ITEM) + { + Item_row *item_row= static_cast(item); + for (uint i= 0; i < item_row->cols(); i++) + { + if (!uses_only_table_name_fields(item_row->element_index(i), table)) + return 0; + } + } else if (item->type() == Item::FIELD_ITEM) { Item_field *item_field= (Item_field*)item; @@ -3659,6 +3668,11 @@ bool uses_only_table_name_fields(Item *item, TABLE_LIST *table) strlen(item_field->field_name), 0))) return 0; } + else if (item->type() == Item::EXPR_CACHE_ITEM) + { + Item_cache_wrapper *tmp= static_cast(item); + return uses_only_table_name_fields(tmp->get_orig_item(), table); + } else if (item->type() == Item::REF_ITEM) return uses_only_table_name_fields(item->real_item(), table); From 0373e05a59afd14444337dfc9f9d3bc98a815e18 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 5 Oct 2017 18:38:29 +0000 Subject: [PATCH 02/34] Refactor os_file_set_size() so it can be used to extend existing file, not just for creating new files. Use os_file_set_size() in fil_space_extend_must_retry() --- storage/xtradb/fil/fil0fil.cc | 166 ++++------------------------------ storage/xtradb/os/os0file.cc | 20 +++- 2 files changed, 35 insertions(+), 151 deletions(-) diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index 0cd67f5b19d..abaffc48135 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -1045,156 +1045,26 @@ fil_space_extend_must_retry( page_size = UNIV_PAGE_SIZE; } -#ifdef _WIN32 - const ulint io_completion_type = OS_FILE_READ; - /* Logically or physically extend the file with zero bytes, - depending on whether it is sparse. */ + /* fil_read_first_page() expects UNIV_PAGE_SIZE bytes. + fil_node_open_file() expects at least 4 * UNIV_PAGE_SIZE bytes.*/ - /* FIXME: Call DeviceIoControl(node->handle, FSCTL_SET_SPARSE, ...) - when opening a file when FSP_FLAGS_HAS_PAGE_COMPRESSION(). */ - { - FILE_END_OF_FILE_INFO feof; - /* fil_read_first_page() expects UNIV_PAGE_SIZE bytes. - fil_node_open_file() expects at least 4 * UNIV_PAGE_SIZE bytes. - Do not shrink short ROW_FORMAT=COMPRESSED files. */ - feof.EndOfFile.QuadPart = std::max( - os_offset_t(size - file_start_page_no) * page_size, - os_offset_t(FIL_IBD_FILE_INITIAL_SIZE - * UNIV_PAGE_SIZE)); - *success = SetFileInformationByHandle(node->handle, - FileEndOfFileInfo, - &feof, sizeof feof); - if (!*success) { - ib_logf(IB_LOG_LEVEL_ERROR, "extending file %s" - " from " INT64PF - " to " INT64PF " bytes failed with %u", - node->name, - os_offset_t(node->size) * page_size, - feof.EndOfFile.QuadPart, GetLastError()); - } else { - start_page_no = size; - } + os_offset_t new_size = std::max( + os_offset_t(size - file_start_page_no) * page_size, + os_offset_t(FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE)); + + *success = os_file_set_size(node->name, node->handle, new_size, + FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags)); + + + DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", + *success = FALSE; + os_has_said_disk_full = TRUE;); + + if (*success) { + os_has_said_disk_full = FALSE; + start_page_no = size; } -#else - /* We will logically extend the file with ftruncate() if - page_compression is enabled, because the file is expected to - be sparse in that case. Make sure that ftruncate() can deal - with large files. */ - const bool is_sparse = sizeof(off_t) >= 8 - && FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags); -# ifdef HAVE_POSIX_FALLOCATE - /* We must complete the I/O request after invoking - posix_fallocate() to avoid an assertion failure at shutdown. - Because no actual writes were dispatched, a read operation - will suffice. */ - const ulint io_completion_type = srv_use_posix_fallocate - || is_sparse ? OS_FILE_READ : OS_FILE_WRITE; - - if (srv_use_posix_fallocate && !is_sparse) { - const os_offset_t start_offset - = os_offset_t(start_page_no - file_start_page_no) - * page_size; - const ulint n_pages = size - start_page_no; - const os_offset_t len = os_offset_t(n_pages) * page_size; - - int err; - do { - err = posix_fallocate(node->handle, start_offset, len); - } while (err == EINTR - && srv_shutdown_state == SRV_SHUTDOWN_NONE); - - *success = !err; - if (!*success) { - ib_logf(IB_LOG_LEVEL_ERROR, "extending file %s" - " from " INT64PF " to " INT64PF " bytes" - " failed with error %d", - node->name, start_offset, len + start_offset, - err); - } - - DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", - *success = FALSE; - os_has_said_disk_full = TRUE;); - - if (*success) { - os_has_said_disk_full = FALSE; - start_page_no = size; - } - } else -# else - const ulint io_completion_type = is_sparse - ? OS_FILE_READ : OS_FILE_WRITE; -# endif - if (is_sparse) { - /* fil_read_first_page() expects UNIV_PAGE_SIZE bytes. - fil_node_open_file() expects at least 4 * UNIV_PAGE_SIZE bytes. - Do not shrink short ROW_FORMAT=COMPRESSED files. */ - off_t s = std::max(off_t(size - file_start_page_no) - * off_t(page_size), - off_t(FIL_IBD_FILE_INITIAL_SIZE - * UNIV_PAGE_SIZE)); - *success = !ftruncate(node->handle, s); - if (!*success) { - ib_logf(IB_LOG_LEVEL_ERROR, "ftruncate of file %s" - " from " INT64PF " to " INT64PF " bytes" - " failed with error %d", - node->name, - os_offset_t(start_page_no - file_start_page_no) - * page_size, os_offset_t(s), errno); - } else { - start_page_no = size; - } - } else { - /* Extend at most 64 pages at a time */ - ulint buf_size = ut_min(64, size - start_page_no) - * page_size; - byte* buf2 = static_cast( - calloc(1, buf_size + page_size)); - *success = buf2 != NULL; - if (!buf2) { - ib_logf(IB_LOG_LEVEL_ERROR, "Cannot allocate " ULINTPF - " bytes to extend file", - buf_size + page_size); - } - byte* const buf = static_cast( - ut_align(buf2, page_size)); - - while (*success && start_page_no < size) { - ulint n_pages - = ut_min(buf_size / page_size, - size - start_page_no); - - os_offset_t offset = static_cast( - start_page_no - file_start_page_no) - * page_size; - - *success = os_aio(OS_FILE_WRITE, 0, OS_AIO_SYNC, - node->name, node->handle, buf, - offset, page_size * n_pages, - page_size, node, NULL, - space->id, NULL, 0); - - DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", - *success = FALSE; - os_has_said_disk_full = TRUE;); - - if (*success) { - os_has_said_disk_full = FALSE; - } - /* Let us measure the size of the file - to determine how much we were able to - extend it */ - os_offset_t fsize = os_file_get_size(node->handle); - ut_a(fsize != os_offset_t(-1)); - - start_page_no = ulint(fsize / page_size) - + file_start_page_no; - } - - free(buf2); - } -#endif mutex_enter(&fil_system->mutex); ut_a(node->being_extended); @@ -1204,7 +1074,7 @@ fil_space_extend_must_retry( space->size += file_size - node->size; node->size = file_size; - fil_node_complete_io(node, fil_system, io_completion_type); + fil_node_complete_io(node, fil_system, OS_FILE_READ); node->being_extended = FALSE; diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index f3c72576501..a3f1e860657 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -2575,7 +2575,16 @@ os_file_get_size( #endif /* __WIN__ */ } -/** Set the size of a newly created file. +/** Extend a file. + +On Windows, extending a file allocates blocks for the file, +unless the file is sparse. + +On Unix, we will extend the file with ftruncate(), if +file needs to be sparse. Otherwise posix_fallocate() is used +when available, and if not, binary zeroes are added to the end +of file. + @param[in] name file name @param[in] file file handle @param[in] size desired file size @@ -2626,15 +2635,20 @@ os_file_set_size( "file %s failed with error %d", size, name, err); } + /* Set errno because posix_fallocate() does not do it.*/ return(!err); } # endif + os_offset_t current_size = os_file_get_size(file); + + if (current_size >= size) { + return true; + } + /* Write up to 1 megabyte at a time. */ ulint buf_size = ut_min(64, (ulint) (size / UNIV_PAGE_SIZE)) * UNIV_PAGE_SIZE; - os_offset_t current_size = 0; - byte* buf2 = static_cast(calloc(1, buf_size + UNIV_PAGE_SIZE)); if (!buf2) { From f9b50c065718a237cb3474dda45062e4c7926240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 6 Oct 2017 17:51:29 +0300 Subject: [PATCH 03/34] MDEV-13512 buf_flush_update_zip_checksum() corrupts SPATIAL INDEX in ROW_FORMAT=COMPRESSED tables In MariaDB Server 10.1, this problem manifests itself only as a debug assertion failure in page_zip_decompress() when an insert requires a page to be decompressed. In MariaDB 10.1, the encryption of InnoDB data files repurposes the previously unused field FILE_FLUSH_LSN for an encryption key version. This field was only used in the first page of each file of the system tablespace. For ROW_FORMAT=COMPRESSED tables, the field was always written as 0 until encryption was implemented. There is no bug in the encryption, because the buffer pool blocks will not be written to files. Instead, copies of the blocks will be encrypted. In these encrypted copies, the key version field will be updated before the buffer is written to the file. The field in the buffer pool is basically garbage that does not really matter. Already in MariaDB 10.0, the memset() calls to reset this unused field in buf_flush_update_zip_checksum() and buf_flush_write_block_low() are unnecessary, because fsp_init_file_page_low() would guarantee that the field is always 0 in the buffer pool (unless 10.1 encryption is used). Removing the unnecessary memset() calls makes page_zip_decompress() happy and will prevent a SPATIAL INDEX corruption bug in MariaDB Server 10.2. In MySQL 5.7.5, as part of WL#6968, the same field was repurposed for an R-tree split sequence number (SSN) and these memset() were removed. (Because of the repurposing, MariaDB encryption is not available for tables that contain SPATIAL INDEX.) --- storage/innobase/buf/buf0flu.cc | 3 --- storage/xtradb/buf/buf0flu.cc | 3 --- 2 files changed, 6 deletions(-) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 31feb322826..dacddfca385 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -715,7 +715,6 @@ buf_flush_update_zip_checksum( srv_checksum_algorithm))); mach_write_to_8(page + FIL_PAGE_LSN, lsn); - memset(page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8); mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, checksum); } @@ -894,8 +893,6 @@ buf_flush_write_block_low( bpage->newest_modification); ut_a(page_zip_verify_checksum(frame, zip_size)); - - memset(frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8); break; case BUF_BLOCK_FILE_PAGE: frame = bpage->zip.data; diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc index b1a0f2daa21..abbcd5141cf 100644 --- a/storage/xtradb/buf/buf0flu.cc +++ b/storage/xtradb/buf/buf0flu.cc @@ -757,7 +757,6 @@ buf_flush_update_zip_checksum( srv_checksum_algorithm))); mach_write_to_8(page + FIL_PAGE_LSN, lsn); - memset(page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8); mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, checksum); } @@ -935,8 +934,6 @@ buf_flush_write_block_low( bpage->newest_modification); ut_a(page_zip_verify_checksum(frame, zip_size)); - - memset(frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8); break; case BUF_BLOCK_FILE_PAGE: frame = bpage->zip.data; From 420798a81ac9a81d20629535fac3032e025e7733 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 6 Oct 2017 16:36:40 +0000 Subject: [PATCH 04/34] Refactor os_file_set_size to extend already existing files. Change fil_space_extend_must_retry() to use this function. --- storage/innobase/fil/fil0fil.cc | 165 ++++---------------------------- storage/innobase/os/os0file.cc | 21 +++- storage/xtradb/fil/fil0fil.cc | 2 - storage/xtradb/os/os0file.cc | 1 + 4 files changed, 37 insertions(+), 152 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 7200c3c32e2..b2576f6bd81 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1037,155 +1037,26 @@ fil_space_extend_must_retry( page_size = UNIV_PAGE_SIZE; } -#ifdef _WIN32 - const ulint io_completion_type = OS_FILE_READ; - /* Logically or physically extend the file with zero bytes, - depending on whether it is sparse. */ + /* fil_read_first_page() expects UNIV_PAGE_SIZE bytes. + fil_node_open_file() expects at least 4 * UNIV_PAGE_SIZE bytes.*/ - /* FIXME: Call DeviceIoControl(node->handle, FSCTL_SET_SPARSE, ...) - when opening a file when FSP_FLAGS_HAS_PAGE_COMPRESSION(). */ - { - FILE_END_OF_FILE_INFO feof; - /* fil_read_first_page() expects UNIV_PAGE_SIZE bytes. - fil_node_open_file() expects at least 4 * UNIV_PAGE_SIZE bytes. - Do not shrink short ROW_FORMAT=COMPRESSED files. */ - feof.EndOfFile.QuadPart = std::max( - os_offset_t(size - file_start_page_no) * page_size, - os_offset_t(FIL_IBD_FILE_INITIAL_SIZE - * UNIV_PAGE_SIZE)); - *success = SetFileInformationByHandle(node->handle, - FileEndOfFileInfo, - &feof, sizeof feof); - if (!*success) { - ib_logf(IB_LOG_LEVEL_ERROR, "extending file %s" - " from " INT64PF - " to " INT64PF " bytes failed with %u", - node->name, - os_offset_t(node->size) * page_size, - feof.EndOfFile.QuadPart, GetLastError()); - } else { - start_page_no = size; - } + os_offset_t new_size = std::max( + os_offset_t(size - file_start_page_no) * page_size, + os_offset_t(FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE)); + + *success = os_file_set_size(node->name, node->handle, new_size, + FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags)); + + + DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", + *success = FALSE; + os_has_said_disk_full = TRUE;); + + if (*success) { + os_has_said_disk_full = FALSE; + start_page_no = size; } -#else - /* We will logically extend the file with ftruncate() if - page_compression is enabled, because the file is expected to - be sparse in that case. Make sure that ftruncate() can deal - with large files. */ - const bool is_sparse = sizeof(off_t) >= 8 - && FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags); -# ifdef HAVE_POSIX_FALLOCATE - /* We must complete the I/O request after invoking - posix_fallocate() to avoid an assertion failure at shutdown. - Because no actual writes were dispatched, a read operation - will suffice. */ - const ulint io_completion_type = srv_use_posix_fallocate - || is_sparse ? OS_FILE_READ : OS_FILE_WRITE; - - if (srv_use_posix_fallocate && !is_sparse) { - const os_offset_t start_offset - = os_offset_t(start_page_no - file_start_page_no) - * page_size; - const ulint n_pages = size - start_page_no; - const os_offset_t len = os_offset_t(n_pages) * page_size; - - int err; - do { - err = posix_fallocate(node->handle, start_offset, len); - } while (err == EINTR - && srv_shutdown_state == SRV_SHUTDOWN_NONE); - - *success = !err; - if (!*success) { - ib_logf(IB_LOG_LEVEL_ERROR, "extending file %s" - " from " INT64PF " to " INT64PF " bytes" - " failed with error %d", - node->name, start_offset, len + start_offset, - err); - } - - DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", - *success = FALSE; - os_has_said_disk_full = TRUE;); - - if (*success) { - os_has_said_disk_full = FALSE; - start_page_no = size; - } - } else -# else - const ulint io_completion_type = is_sparse - ? OS_FILE_READ : OS_FILE_WRITE; -# endif - if (is_sparse) { - /* fil_read_first_page() expects UNIV_PAGE_SIZE bytes. - fil_node_open_file() expects at least 4 * UNIV_PAGE_SIZE bytes. - Do not shrink short ROW_FORMAT=COMPRESSED files. */ - off_t s = std::max(off_t(size - file_start_page_no) - * off_t(page_size), - off_t(FIL_IBD_FILE_INITIAL_SIZE - * UNIV_PAGE_SIZE)); - *success = !ftruncate(node->handle, s); - if (!*success) { - ib_logf(IB_LOG_LEVEL_ERROR, "ftruncate of file %s" - " from " INT64PF " to " INT64PF " bytes" - " failed with error %d", - node->name, - os_offset_t(start_page_no - file_start_page_no) - * page_size, os_offset_t(s), errno); - } else { - start_page_no = size; - } - } else { - /* Extend at most 64 pages at a time */ - ulint buf_size = ut_min(64, size - start_page_no) - * page_size; - byte* buf2 = static_cast( - calloc(1, buf_size + page_size)); - *success = buf2 != NULL; - if (!buf2) { - ib_logf(IB_LOG_LEVEL_ERROR, "Cannot allocate " ULINTPF - " bytes to extend file", - buf_size + page_size); - } - byte* const buf = static_cast( - ut_align(buf2, page_size)); - - while (*success && start_page_no < size) { - ulint n_pages - = ut_min(buf_size / page_size, - size - start_page_no); - - os_offset_t offset = static_cast( - start_page_no - file_start_page_no) - * page_size; - - *success = os_aio(OS_FILE_WRITE, 0, OS_AIO_SYNC, - node->name, node->handle, buf, - offset, page_size * n_pages, - page_size, node, NULL, 0); - - DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", - *success = FALSE; - os_has_said_disk_full = TRUE;); - - if (*success) { - os_has_said_disk_full = FALSE; - } - /* Let us measure the size of the file - to determine how much we were able to - extend it */ - os_offset_t fsize = os_file_get_size(node->handle); - ut_a(fsize != os_offset_t(-1)); - - start_page_no = ulint(fsize / page_size) - + file_start_page_no; - } - - free(buf2); - } -#endif mutex_enter(&fil_system->mutex); ut_a(node->being_extended); @@ -1195,7 +1066,7 @@ fil_space_extend_must_retry( space->size += file_size - node->size; node->size = file_size; - fil_node_complete_io(node, fil_system, io_completion_type); + fil_node_complete_io(node, fil_system, OS_FILE_READ); node->being_extended = FALSE; diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 44093935bc7..2a13746516f 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -2340,7 +2340,16 @@ os_file_get_size( #endif /* __WIN__ */ } -/** Set the size of a newly created file. +/** Extend a file. + +On Windows, extending a file allocates blocks for the file, +unless the file is sparse. + +On Unix, we will extend the file with ftruncate(), if +file needs to be sparse. Otherwise posix_fallocate() is used +when available, and if not, binary zeroes are added to the end +of file. + @param[in] name file name @param[in] file file handle @param[in] size desired file size @@ -2391,15 +2400,21 @@ os_file_set_size( "file %s failed with error %d", size, name, err); } + /* Set errno because posix_fallocate() does not do it.*/ + errno = err; return(!err); } # endif + os_offset_t current_size = os_file_get_size(file); + + if (current_size >= size) { + return true; + } + /* Write up to 1 megabyte at a time. */ ulint buf_size = ut_min(64, (ulint) (size / UNIV_PAGE_SIZE)) * UNIV_PAGE_SIZE; - os_offset_t current_size = 0; - byte* buf2 = static_cast(calloc(1, buf_size + UNIV_PAGE_SIZE)); if (!buf2) { diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index abaffc48135..38cfc13383c 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -1047,7 +1047,6 @@ fil_space_extend_must_retry( /* fil_read_first_page() expects UNIV_PAGE_SIZE bytes. fil_node_open_file() expects at least 4 * UNIV_PAGE_SIZE bytes.*/ - os_offset_t new_size = std::max( os_offset_t(size - file_start_page_no) * page_size, os_offset_t(FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE)); @@ -1064,7 +1063,6 @@ fil_space_extend_must_retry( os_has_said_disk_full = FALSE; start_page_no = size; } - mutex_enter(&fil_system->mutex); ut_a(node->being_extended); diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index a3f1e860657..183f65bcbd8 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -2636,6 +2636,7 @@ os_file_set_size( size, name, err); } /* Set errno because posix_fallocate() does not do it.*/ + errno = err; return(!err); } # endif From 0f8295d7d5ec3ea1ff2076dc1966e23c5a880f80 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 6 Oct 2017 22:34:51 +0000 Subject: [PATCH 05/34] MDEV-13822 mariabackup incremental prepare incorrectly sets file size. Fix incremental prepare to change file size while applying delta file, if delta file contains page 0 with the new size. --- extra/mariabackup/xtrabackup.cc | 63 ++++++--------------------------- 1 file changed, 11 insertions(+), 52 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index f07b1c6d3e3..02c19379961 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4953,12 +4953,17 @@ xtrabackup_apply_delta( if (offset_on_page == 0xFFFFFFFFUL) break; - success = os_file_write(dst_path, dst_file, - incremental_buffer + - page_in_buffer * page_size, - (offset_on_page << - page_size_shift), - page_size); + uchar *buf = incremental_buffer + page_in_buffer * page_size; + const os_offset_t off = os_offset_t(offset_on_page)*page_size; + + if (off == 0) { + /* Fix tablespace size. */ + os_offset_t n_pages = fsp_get_size_low(static_cast(buf)); + if (!os_file_set_size(dst_path, dst_file, n_pages*page_size)) + goto error; + } + + success = os_file_write(dst_path, dst_file, buf, off, page_size); if (!success) { goto error; } @@ -5790,52 +5795,6 @@ skip_check: if(innodb_init()) goto error_cleanup; - if (xtrabackup_incremental) { - - it = datafiles_iter_new(fil_system); - if (it == NULL) { - msg("xtrabackup: Error: datafiles_iter_new() failed.\n"); - exit(EXIT_FAILURE); - } - - while ((node = datafiles_iter_next(it)) != NULL) { - byte *header; - ulint size; - ulint actual_size; - mtr_t mtr; - buf_block_t *block; - ulint flags; - - space = node->space; - - /* Align space sizes along with fsp header. We want to process - each space once, so skip all nodes except the first one in a - multi-node space. */ - if (UT_LIST_GET_PREV(chain, node) != NULL) { - continue; - } - - mtr_start(&mtr); - - mtr_s_lock(fil_space_get_latch(space->id, &flags), &mtr); - - block = buf_page_get(space->id, - dict_tf_get_zip_size(flags), - 0, RW_S_LATCH, &mtr); - header = FSP_HEADER_OFFSET + buf_block_get_frame(block); - - size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, - &mtr); - - mtr_commit(&mtr); - - fil_extend_space_to_desired_size(&actual_size, space->id, size); - } - - datafiles_iter_free(it); - - } /* if (xtrabackup_incremental) */ - if (xtrabackup_export) { msg("xtrabackup: export option is specified.\n"); pfs_os_file_t info_file; From 8d1fb47e1d7403f1e6b61c2400399666f51067c2 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 6 Oct 2017 22:40:28 +0000 Subject: [PATCH 06/34] MDEV-13798 - fix incorrect alignment of the buffer in incremental backup This incorrect alignment can later lead to memcpy over buffer boundaries, and to a crash. --- extra/mariabackup/write_filt.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/mariabackup/write_filt.cc b/extra/mariabackup/write_filt.cc index cf7753bf380..97529fb1726 100644 --- a/extra/mariabackup/write_filt.cc +++ b/extra/mariabackup/write_filt.cc @@ -79,7 +79,7 @@ wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name, cp->delta_buf_base = static_cast(ut_malloc(buf_size)); memset(cp->delta_buf_base, 0, buf_size); cp->delta_buf = static_cast - (ut_align(cp->delta_buf_base, UNIV_PAGE_SIZE_MAX)); + (ut_align(cp->delta_buf_base, cursor->page_size)); /* write delta meta info */ snprintf(meta_name, sizeof(meta_name), "%s%s", dst_name, From bb3f4fbb59c89f985f3649f276bdb3122886a5d9 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 7 Oct 2017 07:36:17 +0000 Subject: [PATCH 07/34] MDEV-13310 Preparing an incremental backup twice can corrupt data Remove .delta file after it was successfully applied --- extra/mariabackup/xtrabackup.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 02c19379961..14d7c5821c7 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4974,8 +4974,11 @@ xtrabackup_apply_delta( if (incremental_buffer_base) ut_free(incremental_buffer_base); - if (src_file != XB_FILE_UNDEFINED) + if (src_file != XB_FILE_UNDEFINED) { os_file_close(src_file); + /* Remove .delta file after it was successfully applied.*/ + os_file_delete(0,src_path); + } if (dst_file != XB_FILE_UNDEFINED) os_file_close(dst_file); return TRUE; From ea4e8bab327806bdfcaa8e92dd2d1436476a8cef Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sat, 7 Oct 2017 14:17:45 +0400 Subject: [PATCH 08/34] MDEV-12705 10.1.18-MariaDB-1~jessie - mysqld got signal 11. Space for the next operation wasn't reserved in Item_func_spatial_relate::val_str() --- mysql-test/r/gis-precise.result | 19 +++++++++++++++++++ mysql-test/t/gis-precise.test | 19 +++++++++++++++++++ sql/item_geofunc.cc | 10 ++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 3824ba6afbb..89e5c237413 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -486,6 +486,25 @@ ST_Touches(ST_PolygonFromText('POLYGON((0 0,0 5,5 5,5 0,0 0))'),ST_PointFromText select ST_Touches(ST_PointFromText('POINT(0 0)'),ST_PointFromText('POINT(0 0)')); ST_Touches(ST_PointFromText('POINT(0 0)'),ST_PointFromText('POINT(0 0)')) 0 +SELECT ST_RELATE( +ST_DIFFERENCE( +GEOMETRYFROMTEXT(' + MULTILINESTRING( + ( 12841 36140, 8005 31007, 26555 31075, 52765 41191, + 28978 6548, 45720 32057, 53345 3221 ), + ( 8304 59107, 25233 31592, 40502 25303, 8205 42940 ), + ( 7829 7305, 58841 56759, 64115 8512, 37562 54145, 2210 14701 ), + ( 20379 2805, 40807 27770, 28147 14883, 26439 29383, 55663 5086 ), + ( 35944 64702, 14433 23728, 49317 26241, 790 16941 ) + ) + '), +GEOMETRYFROMTEXT('POINT(46061 13545)') +), +GEOMETRYFROMTEXT('POINT(4599 60359)'), +'F*FFFF**F' + ) as relate_res; +relate_res +0 DROP TABLE IF EXISTS p1; CREATE PROCEDURE p1(dist DOUBLE, geom TEXT) BEGIN diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 5e57569a912..7391b2114f3 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -362,5 +362,24 @@ select ST_Touches(ST_LineFromText('LINESTRING(0 0,5 5)'),ST_PointFromText('POINT select ST_Touches(ST_PolygonFromText('POLYGON((0 0,0 5,5 5,5 0,0 0))'),ST_PointFromText('POINT(0 0)')); select ST_Touches(ST_PointFromText('POINT(0 0)'),ST_PointFromText('POINT(0 0)')); +# MDEV-12705 10.1.18-MariaDB-1~jessie - mysqld got signal 11. +SELECT ST_RELATE( + ST_DIFFERENCE( + GEOMETRYFROMTEXT(' + MULTILINESTRING( + ( 12841 36140, 8005 31007, 26555 31075, 52765 41191, + 28978 6548, 45720 32057, 53345 3221 ), + ( 8304 59107, 25233 31592, 40502 25303, 8205 42940 ), + ( 7829 7305, 58841 56759, 64115 8512, 37562 54145, 2210 14701 ), + ( 20379 2805, 40807 27770, 28147 14883, 26439 29383, 55663 5086 ), + ( 35944 64702, 14433 23728, 49317 26241, 790 16941 ) + ) + '), + GEOMETRYFROMTEXT('POINT(46061 13545)') + ), + GEOMETRYFROMTEXT('POINT(4599 60359)'), + 'F*FFFF**F' + ) as relate_res; + --source include/gis_debug.inc diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 3f0efbfa871..a271e481814 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1332,6 +1332,8 @@ static int setup_relate_func(Geometry *g1, Geometry *g2, } else func->repeat_expression(shape_a); + if (func->reserve_op_buffer(1)) + return 1; func->add_operation(op_matrix(nc%3), 1); if (do_store_shapes) { @@ -1502,11 +1504,13 @@ longlong Item_func_spatial_precise_rel::val_int() Gcalc_function::op_intersection, 2); func.add_operation(Gcalc_function::op_internals, 1); shape_a= func.get_next_expression_pos(); - if ((null_value= g1.store_shapes(&trn))) + if ((null_value= g1.store_shapes(&trn)) || + func.reserve_op_buffer(1)) break; func.add_operation(Gcalc_function::op_internals, 1); shape_b= func.get_next_expression_pos(); - if ((null_value= g2.store_shapes(&trn))) + if ((null_value= g2.store_shapes(&trn)) || + func.reserve_op_buffer(1)) break; func.add_operation(Gcalc_function::v_find_t | Gcalc_function::op_intersection, 2); @@ -1741,6 +1745,8 @@ int Item_func_buffer::Transporter::single_point(double x, double y) { if (buffer_op == Gcalc_function::op_difference) { + if (m_fn->reserve_op_buffer(1)) + return 1; m_fn->add_operation(Gcalc_function::op_false, 0); return 0; } From 3edd007ceae7b557ca36364f1051c78f8a5bed94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 9 Oct 2017 14:08:46 +0300 Subject: [PATCH 09/34] btr_free_root(): Relax a too strict debug assertion When btr_create() invokes btr_free_root() after running out of space, fseg_create() would have acquired an SX-latch on the root page, not an X-latch. Relax the debug assertion in btr_free_root() accordingly. (In this case, SX-latch and X-latch are equivalent. During the CREATE operation there should be MDL_EXCLUSIVE and dict_operation_lock X-latch preventing concurrent access to the index. Normally the purpose of the SX-latch is to allow concurrent reads of the root page while certain fields in the root page are updated in place.) --- storage/innobase/btr/btr0btr.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 3e9f26ad125..bf4a123c2ee 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -1041,7 +1041,8 @@ btr_free_root( { fseg_header_t* header; - ut_ad(mtr_memo_contains_flagged(mtr, block, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr_memo_contains_flagged(mtr, block, MTR_MEMO_PAGE_X_FIX + | MTR_MEMO_PAGE_SX_FIX)); ut_ad(mtr->is_named_space(block->page.id.space())); btr_search_drop_page_hash_index(block); From e1d9a237978432082d50f8078838b28261917c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 9 Oct 2017 15:05:17 +0300 Subject: [PATCH 10/34] MDEV-14023 10.1 InnoDB tables with virtual columns cannot be accessed in 10.2 MariaDB 10.1 introduced non-indexed virtual columns for InnoDB tables. When MySQL 5.7 introduced virtual columns in InnoDB tables, it also introduced the table SYS_VIRTUAL that stores metadata on virtual columns. This table does not initially exist in data files that were imported from 10.1. So, we do not always have virtual column metadata inside InnoDB. dict_index_contains_col_or_prefix(): In the clustered index records, all non-virtual columns are present and no virtual columns are present. ha_innobase::build_template(): In the clustered index, do not include virtual columns in the query template. The SQL layer is supposed to compute the virtual column values when needed. --- storage/innobase/dict/dict0dict.cc | 3 +-- storage/innobase/handler/ha_innodb.cc | 11 +++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 54e0115070d..b95592d43d4 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -912,8 +912,7 @@ dict_index_contains_col_or_prefix( ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); if (dict_index_is_clust(index)) { - - return(TRUE); + return(!is_virtual); } if (is_virtual) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 0e9708eb151..3374f46fb24 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8204,13 +8204,16 @@ no_icp: } else { ibool contain; - if (innobase_is_v_fld(table->field[i])) { - contain = dict_index_contains_col_or_prefix( - index, num_v, true); - } else { + if (!innobase_is_v_fld(table->field[i])) { contain = dict_index_contains_col_or_prefix( index, i - num_v, false); + } else if (dict_index_is_clust(index)) { + num_v++; + continue; + } else { + contain = dict_index_contains_col_or_prefix( + index, num_v, true); } field = build_template_needs_field( From 1841ef1c5458634a88ef4faad5883552d9f354b2 Mon Sep 17 00:00:00 2001 From: sjaakola Date: Tue, 3 Oct 2017 23:37:02 +0300 Subject: [PATCH 11/34] MW-416 Moved TOI replication to happen after ACL checking for commands: SQLCOM_CREATE_EVENT SQLCOM_ALTER_EVENT SQLCOM_DROP_EVENT SQLCOM_CREATE_VIEW SQLCOM_CREATE_TRIGGER SQLCOM_DROP_TRIGGER SQLCOM_INSTALL_PLUGIN SQLCOM_UNINSTALL_PLUGIN --- sql/events.cc | 18 ++++++++++++++++++ sql/sql_parse.cc | 7 ------- sql/sql_plugin.cc | 20 ++++++++++++++++---- sql/sql_trigger.cc | 5 +++++ sql/sql_view.cc | 5 +++++ 5 files changed, 44 insertions(+), 11 deletions(-) diff --git a/sql/events.cc b/sql/events.cc index 11d54894d1d..ad2f13fc35c 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -334,6 +334,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data) if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0)) DBUG_RETURN(TRUE); + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (lock_object_name(thd, MDL_key::EVENT, parse_data->dbname.str, parse_data->name.str)) @@ -416,6 +417,10 @@ Events::create_event(THD *thd, Event_parse_data *parse_data) thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(ret); +#ifdef WITH_WSREP + error: + DBUG_RETURN(true); +#endif /* WITH_WSREP */ } @@ -456,6 +461,9 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0)) DBUG_RETURN(TRUE); + + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + if (lock_object_name(thd, MDL_key::EVENT, parse_data->dbname.str, parse_data->name.str)) DBUG_RETURN(TRUE); @@ -540,6 +548,10 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(ret); +#ifdef WITH_WSREP +error: + DBUG_RETURN(TRUE); +#endif /* WITH_WSREP */ } @@ -580,6 +592,8 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0)) DBUG_RETURN(TRUE); + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + /* Turn off row binlogging of this statement and use statement-based so that all supporting tables are updated for DROP EVENT command. @@ -601,6 +615,10 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(ret); +#ifdef WITH_WSREP +error: + DBUG_RETURN(TRUE); +#endif } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ecd7d845635..7662cc404a7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5072,7 +5072,6 @@ end_with_restore_list: if (res) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) switch (lex->sql_command) { case SQLCOM_CREATE_EVENT: { @@ -5106,7 +5105,6 @@ end_with_restore_list: lex->spname->m_name); break; case SQLCOM_DROP_EVENT: - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res= Events::drop_event(thd, lex->spname->m_db, lex->spname->m_name, lex->if_exists()))) @@ -6019,7 +6017,6 @@ end_with_restore_list: Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands as specified through the thd->lex->create_view_mode flag. */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_create_view(thd, first_table, thd->lex->create_view_mode); break; } @@ -6035,7 +6032,6 @@ end_with_restore_list: case SQLCOM_CREATE_TRIGGER: { /* Conditionally writes to binlog. */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_create_or_drop_trigger(thd, all_tables, 1); break; @@ -6043,7 +6039,6 @@ end_with_restore_list: case SQLCOM_DROP_TRIGGER: { /* Conditionally writes to binlog. */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) res= mysql_create_or_drop_trigger(thd, all_tables, 0); break; } @@ -6108,13 +6103,11 @@ end_with_restore_list: my_ok(thd); break; case SQLCOM_INSTALL_PLUGIN: - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (! (res= mysql_install_plugin(thd, &thd->lex->comment, &thd->lex->ident))) my_ok(thd); break; case SQLCOM_UNINSTALL_PLUGIN: - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment, &thd->lex->ident))) my_ok(thd); diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 6fe01519380..17b68750bc6 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -2122,12 +2122,16 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, bool error; int argc=orig_argc; char **argv=orig_argv; + unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] = + { MYSQL_AUDIT_GENERAL_CLASSMASK }; DBUG_ENTER("mysql_install_plugin"); tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE); if (!opt_noacl && check_table_access(thd, INSERT_ACL, &tables, FALSE, 1, FALSE)) DBUG_RETURN(TRUE); + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + /* need to open before acquiring LOCK_plugin or it will deadlock */ if (! (table = open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) @@ -2160,8 +2164,6 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, See also mysql_uninstall_plugin() and initialize_audit_plugin() */ - unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] = - { MYSQL_AUDIT_GENERAL_CLASSMASK }; if (mysql_audit_general_enabled()) mysql_audit_acquire_plugins(thd, event_class_mask); @@ -2193,6 +2195,10 @@ err: if (argv) free_defaults(argv); DBUG_RETURN(error); +#ifdef WITH_WSREP +error: + DBUG_RETURN(TRUE); +#endif /* WITH_WSREP */ } @@ -2259,6 +2265,8 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name, TABLE_LIST tables; LEX_STRING dl= *dl_arg; bool error= false; + unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] = + { MYSQL_AUDIT_GENERAL_CLASSMASK }; DBUG_ENTER("mysql_uninstall_plugin"); tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE); @@ -2266,6 +2274,8 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name, if (!opt_noacl && check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE)) DBUG_RETURN(TRUE); + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + /* need to open before acquiring LOCK_plugin or it will deadlock */ if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(TRUE); @@ -2291,8 +2301,6 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name, See also mysql_install_plugin() and initialize_audit_plugin() */ - unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] = - { MYSQL_AUDIT_GENERAL_CLASSMASK }; if (mysql_audit_general_enabled()) mysql_audit_acquire_plugins(thd, event_class_mask); @@ -2323,6 +2331,10 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name, mysql_mutex_unlock(&LOCK_plugin); DBUG_RETURN(error); +#ifdef WITH_WSREP +error: + DBUG_RETURN(TRUE); +#endif /* WITH_WSREP */ } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index ca9b1431785..21a79967244 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -452,6 +452,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); DBUG_RETURN(TRUE); } + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!create) { @@ -615,6 +616,10 @@ end: my_ok(thd); DBUG_RETURN(result); +#ifdef WITH_WSREP + error: + DBUG_RETURN(true); +#endif /* WITH_WSREP */ } /** diff --git a/sql/sql_view.cc b/sql/sql_view.cc index d39dc739893..6e58564262c 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -426,6 +426,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, if ((res= create_view_precheck(thd, tables, view, mode))) goto err; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) lex->link_first_table_back(view, link_to_local); view->open_type= OT_BASE_ONLY; @@ -702,6 +703,10 @@ err: lex->link_first_table_back(view, link_to_local); unit->cleanup(); DBUG_RETURN(res || thd->is_error()); +#ifdef WITH_WSREP + error: + DBUG_RETURN(true); +#endif /* WITH_WSREP */ } From 70c23321de0769b4fdb92e6df250fd0dc056df20 Mon Sep 17 00:00:00 2001 From: sjaakola Date: Wed, 4 Oct 2017 22:47:59 +0300 Subject: [PATCH 12/34] MW-416 Changed return code for replicatio error to TRUE. This is aligned with native mysql convention to return TRUE (defined to 1) or FALSE (defined to 0) from a bool function. This is wrong, but follows the mysql conventiosn, at least... --- sql/events.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/events.cc b/sql/events.cc index ad2f13fc35c..1f2501646cb 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -419,7 +419,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data) DBUG_RETURN(ret); #ifdef WITH_WSREP error: - DBUG_RETURN(true); + DBUG_RETURN(TRUE); #endif /* WITH_WSREP */ } From 0b5a5258abbeaf8a0c3a18c7e753699787fdf46e Mon Sep 17 00:00:00 2001 From: sjaakola Date: Fri, 6 Oct 2017 09:49:42 +0300 Subject: [PATCH 13/34] MW-416 DDL replication moved after acl checking galera_events test shows a regression with the original fix for MW-416 Reason was that Events::drop_event() can be called also from inside event execution, and there we have a speacial treatment for event, which executes "DROP EVENT" statement, and runs TOI replication inside the event processing body. This resulted in executing WSREP_TO_ISOLATION two times for such DROP EVENT statement. Fix is to call WSREP_TO_ISOLATION_BEGIN only in Events::drop_event() --- sql/event_data_objects.cc | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index e494b4a429b..90e839debb5 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1472,19 +1472,33 @@ end: bool save_tx_read_only= thd->tx_read_only; thd->tx_read_only= false; - if (WSREP(thd)) - { + /* + This code is processing event execution and does not have client + connection. Here, event execution will now execute a prepared + DROP EVENT statement, but thd->lex->sql_command is set to + SQLCOM_CREATE_PROCEDURE + DROP EVENT will be logged in binlog, and we have to + replicate it to make all nodes have consistent event definitions + Wsrep DDL replication is triggered inside Events::drop_event(), + and here we need to prepare the THD so that DDL replication is + possible, essentially it requires setting sql_command to + SQLCOMM_DROP_EVENT, we will switch sql_command for the duration + of DDL replication only. + */ + const enum_sql_command sql_command_save= thd->lex->sql_command; + const bool sql_command_set= WSREP(thd); + + if (sql_command_set) thd->lex->sql_command = SQLCOM_DROP_EVENT; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); - } ret= Events::drop_event(thd, dbname, name, FALSE); - WSREP_TO_ISOLATION_END; + if (sql_command_set) + { + WSREP_TO_ISOLATION_END; + thd->lex->sql_command = sql_command_save; + } -#ifdef WITH_WSREP - error: -#endif thd->tx_read_only= save_tx_read_only; thd->security_ctx->master_access= saved_master_access; } From b731a5bcf2a0c86b6e31e4a99e3c632bb39a9c53 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 8 Oct 2017 00:13:05 +0000 Subject: [PATCH 14/34] Innodb : Refactor os_file_set_size() to be compatible 10.1 The last parameter to this function is now,"bool is_sparse", like in 10.1 rather than the unused/useless "bool is_readonly", merged from MySQL 5.7 Like in 10.1, this function now supports sparse files, and efficient platform specific mechanisms for file extension os_file_set_size() is now consistenly used in all places where innodb files are extended. --- extra/mariabackup/xtrabackup.cc | 3 +- storage/innobase/fil/fil0fil.cc | 226 ++++----------------------- storage/innobase/fsp/fsp0sysspace.cc | 3 +- storage/innobase/include/os0file.h | 24 ++- storage/innobase/os/os0file.cc | 54 +++++-- storage/innobase/srv/srv0start.cc | 6 +- 6 files changed, 95 insertions(+), 221 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index f4c0af45cd7..7daead2ceaf 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4022,8 +4022,7 @@ xb_space_create_file( } ret = os_file_set_size(path, *file, - FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE, - false); + FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE); if (!ret) { msg("xtrabackup: cannot set size for file %s\n", path); os_file_close(*file); diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 2897d5f9be8..b8387f64861 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1061,139 +1061,28 @@ fil_space_extend_must_retry( const page_size_t pageSize(space->flags); const ulint page_size = pageSize.physical(); -#ifdef _WIN32 - os_offset_t new_file_size = - std::max( - os_offset_t(size - file_start_page_no) * page_size, - os_offset_t(FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE)); + /* fil_read_first_page() expects UNIV_PAGE_SIZE bytes. + fil_node_open_file() expects at least 4 * UNIV_PAGE_SIZE bytes.*/ + os_offset_t new_size = std::max( + os_offset_t(size - file_start_page_no) * page_size, + os_offset_t(FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE)); - /* os_file_change_size_win32() handles both compressed(sparse) - and normal files correctly. - It allocates physical storage for normal files and "virtual" - storage for sparse ones.*/ - *success = os_file_change_size_win32(node->name, - node->handle, new_file_size); + *success = os_file_set_size(node->name, node->handle, new_size, + FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags)); + os_has_said_disk_full = *success; if (*success) { last_page_no = size; } else { - ib::error() << "extending file '" << node->name - << " to size " << new_file_size << " failed"; + /* Let us measure the size of the file + to determine how much we were able to + extend it */ + os_offset_t fsize = os_file_get_size(node->handle); + ut_a(fsize != os_offset_t(-1)); + + last_page_no = ulint(fsize / page_size) + + file_start_page_no; } -#else - /* We will logically extend the file with ftruncate() if - page_compression is enabled, because the file is expected to - be sparse in that case. Make sure that ftruncate() can deal - with large files. */ - const bool is_sparse = sizeof(off_t) >= 8 - && FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags); - - if (is_sparse) { - /* fil_read_first_page() expects UNIV_PAGE_SIZE bytes. - fil_node_open_file() expects at least 4 * UNIV_PAGE_SIZE bytes. - Do not shrink short ROW_FORMAT=COMPRESSED files. */ - off_t s = std::max(off_t(size - file_start_page_no) - * off_t(page_size), - off_t(FIL_IBD_FILE_INITIAL_SIZE - * UNIV_PAGE_SIZE)); - *success = !ftruncate(node->handle, s); - if (!*success) { - ib::error() << "ftruncate of file '" << node->name - << "' from " - << os_offset_t(last_page_no - - file_start_page_no) - * page_size << " to " << os_offset_t(s) - << " bytes failed with " << errno; - } else { - last_page_no = size; - } - } else { - const os_offset_t start_offset - = os_offset_t(last_page_no - file_start_page_no) - * page_size; - const ulint n_pages = size - last_page_no; - const os_offset_t len = os_offset_t(n_pages) * page_size; -# ifdef HAVE_POSIX_FALLOCATE - int err; - do { - err = posix_fallocate(node->handle, start_offset, len); - } while (err == EINTR - && srv_shutdown_state == SRV_SHUTDOWN_NONE); - - if (err != EINVAL) { - - *success = !err; - if (!*success) { - ib::error() << "extending file '" << node->name - << "' from " - << start_offset - << " to " << len + start_offset - << " bytes failed with: " << err; - } - } else -# endif /* HAVE_POSIX_FALLOCATE */ - { - /* Extend at most 1 megabyte pages at a time */ - ulint n_bytes = std::min(ulint(1) << 20, n_pages) - * page_size; - byte* buf2 = static_cast( - calloc(1, n_bytes + page_size)); - *success = buf2 != NULL; - if (!buf2) { - ib::error() << "Cannot allocate " - << n_bytes + page_size - << " bytes to extend file"; - } - byte* const buf = static_cast( - ut_align(buf2, page_size)); - IORequest request(IORequest::WRITE); - - - os_offset_t offset = start_offset; - const os_offset_t end = start_offset + len; - const bool read_only_mode = space->purpose - == FIL_TYPE_TEMPORARY && srv_read_only_mode; - - while (*success && offset < end) { - dberr_t err = os_aio( - request, OS_AIO_SYNC, node->name, - node->handle, buf, offset, n_bytes, - read_only_mode, NULL, NULL); - - if (err != DB_SUCCESS) { - *success = false; - ib::error() << "writing zeroes to file '" - << node->name << "' from " - << offset << " to " << offset + n_bytes - << " bytes failed with: " - << ut_strerr(err); - break; - } - - offset += n_bytes; - - n_bytes = std::min(n_bytes, - static_cast(end - offset)); - } - - free(buf2); - } - - os_has_said_disk_full = *success; - if (*success) { - last_page_no = size; - } else { - /* Let us measure the size of the file - to determine how much we were able to - extend it */ - os_offset_t fsize = os_file_get_size(node->handle); - ut_a(fsize != os_offset_t(-1)); - - last_page_no = ulint(fsize / page_size) - + file_start_page_no; - } - } -#endif mutex_enter(&fil_system->mutex); ut_a(node->being_extended); @@ -1206,11 +1095,7 @@ fil_space_extend_must_retry( const ulint pages_in_MiB = node->size & ~((1 << (20 - UNIV_PAGE_SIZE_SHIFT)) - 1); - fil_node_complete_io(node, -#ifndef _WIN32 - !is_sparse ? IORequestWrite : -#endif /* _WIN32 */ - IORequestRead); + fil_node_complete_io(node,IORequestRead); /* Keep the last data file size info up to date, rounded to full megabytes */ @@ -3237,10 +3122,11 @@ fil_truncate_tablespace( bool success = os_file_truncate(node->name, node->handle, 0); if (success) { - os_offset_t size = size_in_pages * UNIV_PAGE_SIZE; + os_offset_t size = os_offset_t(size_in_pages) * UNIV_PAGE_SIZE; success = os_file_set_size( - node->name, node->handle, size, srv_read_only_mode); + node->name, node->handle, size, + FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags)); if (success) { space->stop_new_ops = false; @@ -3835,72 +3721,18 @@ fil_ibd_create( return(DB_ERROR); } - bool punch_hole = false; + bool is_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(flags); #ifdef _WIN32 - - if (FSP_FLAGS_HAS_PAGE_COMPRESSION(flags)) { - punch_hole = os_file_set_sparse_win32(file); - } - - success = os_file_change_size_win32(path, file, size * UNIV_PAGE_SIZE); - -#else - - success= false; -#ifdef HAVE_POSIX_FALLOCATE - /* - Extend the file using posix_fallocate(). This is required by - FusionIO HW/Firmware but should also be the prefered way to extend - a file. - */ - int ret; - do { - ret = posix_fallocate(file, 0, size * UNIV_PAGE_SIZE); - } while (ret == EINTR - && srv_shutdown_state == SRV_SHUTDOWN_NONE); - - if (ret == 0) { - success = true; - } else if (ret != EINVAL) { - ib::error() << - "posix_fallocate(): Failed to preallocate" - " data for file " << path - << ", desired size " - << size * UNIV_PAGE_SIZE - << " Operating system error number " << ret - << ". Check" - " that the disk is not full or a disk quota" - " exceeded. Some operating system error" - " numbers are described at " REFMAN - "operating-system-error-codes.html"; - } -#endif /* HAVE_POSIX_FALLOCATE */ - - if (!success) { - success = os_file_set_size( - path, file, size * UNIV_PAGE_SIZE, srv_read_only_mode); - } - - /* Note: We are actually punching a hole, previous contents will - be lost after this call, if it succeeds. In this case the file - should be full of NULs. */ - - punch_hole = os_is_sparse_file_supported(file); - - if (punch_hole) { - - dberr_t punch_err; - - punch_err = os_file_punch_hole(file, 0, size * UNIV_PAGE_SIZE); - - if (punch_err != DB_SUCCESS) { - punch_hole = false; - } + if (is_compressed) { + os_file_set_sparse_win32(file); } #endif - ulint block_size = os_file_get_block_size(file, path); + success = os_file_set_size(path, file, + os_offset_t(size)*UNIV_PAGE_SIZE, + FSP_FLAGS_HAS_PAGE_COMPRESSION(flags)); + if (!success) { os_file_close(file); @@ -3908,6 +3740,10 @@ fil_ibd_create( return(DB_OUT_OF_FILE_SPACE); } + bool punch_hole = os_is_sparse_file_supported(file); + + ulint block_size = os_file_get_block_size(file, path); + /* We have to write the space id to the file immediately and flush the file to disk. This is because in crash recovery we must be aware what tablespaces exist and what are their space id's, so that we can apply diff --git a/storage/innobase/fsp/fsp0sysspace.cc b/storage/innobase/fsp/fsp0sysspace.cc index cc156a5353a..c459c8296e0 100644 --- a/storage/innobase/fsp/fsp0sysspace.cc +++ b/storage/innobase/fsp/fsp0sysspace.cc @@ -410,8 +410,7 @@ SysTablespace::set_size( bool success = os_file_set_size( file.m_filepath, file.m_handle, - static_cast(file.m_size << UNIV_PAGE_SIZE_SHIFT), - m_ignore_read_only ? false : srv_read_only_mode); + static_cast(file.m_size) << UNIV_PAGE_SIZE_SHIFT); if (success) { ib::info() << "File '" << file.filepath() << "' size is now " diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 1b90ea8d7e7..e872d6f1df7 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -1232,19 +1232,27 @@ os_file_get_size( os_file_t file) MY_ATTRIBUTE((warn_unused_result)); -/** Write the specified number of zeros to a newly created file. -@param[in] name name of the file or path as a null-terminated - string -@param[in] file handle to a file -@param[in] size file size -@param[in] read_only Enable read-only checks if true -@return true if success */ +/** Extend a file. + +On Windows, extending a file allocates blocks for the file, +unless the file is sparse. + +On Unix, we will extend the file with ftruncate(), if +file needs to be sparse. Otherwise posix_fallocate() is used +when available, and if not, binary zeroes are added to the end +of file. + +@param[in] name file name +@param[in] file file handle +@param[in] size desired file size +@param[in] sparse whether to create a sparse file (no preallocating) +@return whether the operation succeeded */ bool os_file_set_size( const char* name, os_file_t file, os_offset_t size, - bool read_only) + bool is_sparse = false) MY_ATTRIBUTE((warn_unused_result)); /** Truncates a file at its current position. diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index c894a3c15ab..b664cf82c16 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -5319,23 +5319,56 @@ short_warning: #endif /* _WIN32 */ -/** Write the specified number of zeros to a newly created file. -@param[in] name name of the file or path as a null-terminated - string -@param[in] file handle to a file -@param[in] size file size -@param[in] read_only Enable read-only checks if true -@return true if success */ +/** Extend a file. + +On Windows, extending a file allocates blocks for the file, +unless the file is sparse. + +On Unix, we will extend the file with ftruncate(), if +file needs to be sparse. Otherwise posix_fallocate() is used +when available, and if not, binary zeroes are added to the end +of file. + +@param[in] name file name +@param[in] file file handle +@param[in] size desired file size +@param[in] sparse whether to create a sparse file (no preallocating) +@return whether the operation succeeded */ bool os_file_set_size( const char* name, os_file_t file, os_offset_t size, - bool read_only) + bool is_sparse) { #ifdef _WIN32 return os_file_change_size_win32(name, file, size); -#endif +#else + if (is_sparse) { + bool success = !ftruncate(file, size); + if (!success) { + ib::error() << "ftruncate of file " << name << + " to " << size << " bytes failed with error " << errno; + } + return(success); + } + +# ifdef HAVE_POSIX_FALLOCATE + int err; + do { + err = posix_fallocate(file, 0, size); + } while (err == EINTR + && srv_shutdown_state == SRV_SHUTDOWN_NONE); + + if (err) { + ib::error() << + "preallocating " << size << " bytes for" << + "file " << name << "failed with error " << err; + } + errno = err; + return(!err); +# endif /* HAVE_POSIX_ALLOCATE */ + /* Write up to 1 megabyte at a time. */ ulint buf_size = ut_min( static_cast(64), @@ -5358,7 +5391,7 @@ os_file_set_size( ib::info() << "Progress in MB:"; } - os_offset_t current_size = 0; + os_offset_t current_size = os_file_get_size(file); while (current_size < size) { ulint n_bytes; @@ -5401,6 +5434,7 @@ os_file_set_size( ut_free(buf2); return(os_file_flush(file)); +#endif /* !WIN32 */ } /** Truncates a file to a specified size in bytes. diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index d7e1e062d7a..1002cc566fb 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -378,8 +378,7 @@ create_log_file( ib::info() << "Setting log file " << name << " size to " << srv_log_file_size << " bytes"; - ret = os_file_set_size(name, *file, srv_log_file_size, - srv_read_only_mode); + ret = os_file_set_size(name, *file, srv_log_file_size); if (!ret) { ib::error() << "Cannot set log file " << name << " size to " << srv_log_file_size << " bytes"; @@ -658,8 +657,7 @@ srv_undo_tablespace_create( << "wait..."; ret = os_file_set_size( - name, fh, size << UNIV_PAGE_SIZE_SHIFT, - srv_read_only_mode); + name, fh, os_offset_t(size) << UNIV_PAGE_SIZE_SHIFT); if (!ret) { ib::info() << "Error in creating " << name From fe18e6b064a794f3dd84ead92cff3e831d185fdc Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 8 Oct 2017 22:05:54 +0000 Subject: [PATCH 15/34] MDEV-13822 mariabackup incremental prepare incorrectly sets file size. MDEV-13310 Preparing an incremental backup twice can corrupt data --- extra/mariabackup/xtrabackup.cc | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 7daead2ceaf..40736709a39 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4413,13 +4413,20 @@ xtrabackup_apply_delta( if (offset_on_page == 0xFFFFFFFFUL) break; + uchar *buf = incremental_buffer + page_in_buffer * page_size; + const os_offset_t off = os_offset_t(offset_on_page)*page_size; + + if (off == 0) { + /* Read tablespace size from page 0, + and extend the file to specified size.*/ + os_offset_t n_pages = mach_read_from_4(buf + FSP_HEADER_OFFSET + FSP_SIZE); + success = os_file_set_size(dst_path, dst_file, n_pages*page_size); + if (!success) + goto error; + } + success = os_file_write(IORequestWrite, - dst_path, dst_file, - incremental_buffer + - page_in_buffer * page_size, - (offset_on_page << - page_size_shift), - page_size); + dst_path, dst_file, buf, off, page_size); if (!success) { goto error; } @@ -4429,8 +4436,10 @@ xtrabackup_apply_delta( } free(incremental_buffer_base); - if (src_file != OS_FILE_CLOSED) + if (src_file != OS_FILE_CLOSED) { os_file_close(src_file); + os_file_delete(0,src_path); + } if (dst_file != OS_FILE_CLOSED) os_file_close(dst_file); return TRUE; From ff2d9e125f7f2a70f67bc4e7ad40990139a1cf66 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 9 Oct 2017 12:13:05 +0000 Subject: [PATCH 16/34] MDEV-13941 followup. Try to fix fragmentation (unsparse files), for pre-existing installations. Unsparse the innodb file, when it needs to be extended, unless compression is used. For Win7/2008R2 unsparse does not work (as documented in MSDN), therefore for sparse files in older Windows, file extension will be done via writing zeroes at the end of file. --- storage/innobase/include/os0file.h | 4 ++- storage/innobase/os/os0file.cc | 47 +++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index e872d6f1df7..c0806ad2977 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -1583,8 +1583,10 @@ os_file_set_umask(ulint umask); Make file sparse, on Windows. @param[in] file file handle +@param[in] is_sparse if true, make file sparse, + otherwise "unsparse" the file @return true on success, false on error */ -bool os_file_set_sparse_win32(os_file_t file); +bool os_file_set_sparse_win32(os_file_t file, bool is_sparse = true); /** Changes file size on Windows diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index b664cf82c16..2ef1940fdcd 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -4743,11 +4743,20 @@ Sets a sparse flag on Windows file. @param[in] file file handle @return true on success, false on error */ -bool os_file_set_sparse_win32(os_file_t file) +#include +bool os_file_set_sparse_win32(os_file_t file, bool is_sparse) { - + if (!is_sparse && !IsWindows8OrGreater()) { + /* Cannot unset sparse flag on older Windows. + Until Windows8 it is documented to produce unpredictable results, + if there are unallocated ranges in file.*/ + return false; + } DWORD temp; - return os_win32_device_io_control(file, FSCTL_SET_SPARSE, 0, 0, 0, 0,&temp); + FILE_SET_SPARSE_BUFFER sparse_buffer; + sparse_buffer.SetSparse = is_sparse; + return os_win32_device_io_control(file, + FSCTL_SET_SPARSE, &sparse_buffer, sizeof(sparse_buffer), 0, 0,&temp); } @@ -5342,7 +5351,23 @@ os_file_set_size( bool is_sparse) { #ifdef _WIN32 + /* On Windows, changing file size works well and as expected for both + sparse and normal files. + + However, 10.2 up until 10.2.9 made every file sparse in innodb, + causing NTFS fragmentation issues(MDEV-13941). We try to undo + the damage, and unsparse the file.*/ + + if (!is_sparse && os_is_sparse_file_supported(file)) { + if (!os_file_set_sparse_win32(file, false)) + /* Unsparsing file failed. Fallback to writing binary + zeros, to avoid even higher fragmentation.*/ + goto fallback; + } + return os_file_change_size_win32(name, file, size); + +fallback: #else if (is_sparse) { bool success = !ftruncate(file, size); @@ -5368,6 +5393,7 @@ os_file_set_size( errno = err; return(!err); # endif /* HAVE_POSIX_ALLOCATE */ +#endif /* _WIN32*/ /* Write up to 1 megabyte at a time. */ ulint buf_size = ut_min( @@ -5386,13 +5412,14 @@ os_file_set_size( /* Write buffer full of zeros */ memset(buf, 0, buf_size); - if (size >= (os_offset_t) 100 << 20) { + os_offset_t current_size = os_file_get_size(file); + bool write_progress_info = + (size - current_size >= (os_offset_t) 100 << 20); + if (write_progress_info) { ib::info() << "Progress in MB:"; } - os_offset_t current_size = os_file_get_size(file); - while (current_size < size) { ulint n_bytes; @@ -5415,8 +5442,9 @@ os_file_set_size( } /* Print about progress for each 100 MB written */ - if ((current_size + n_bytes) / (100 << 20) - != current_size / (100 << 20)) { + if (write_progress_info && + ((current_size + n_bytes) / (100 << 20) + != current_size / (100 << 20))) { fprintf(stderr, " %lu00", (ulong) ((current_size + n_bytes) @@ -5426,7 +5454,7 @@ os_file_set_size( current_size += n_bytes; } - if (size >= (os_offset_t) 100 << 20) { + if (write_progress_info) { fprintf(stderr, "\n"); } @@ -5434,7 +5462,6 @@ os_file_set_size( ut_free(buf2); return(os_file_flush(file)); -#endif /* !WIN32 */ } /** Truncates a file to a specified size in bytes. From fa7a1a57d9d73c0b834c86c9f366dab66b16a908 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 9 Oct 2017 17:41:20 +0000 Subject: [PATCH 17/34] Windows : small optimization in os_is_sparse_file_supported() Use GetFileInformationByHandleEx with FileAttributeTagInfo to query whether the file is sparse. This saves 1 syscall, as GetFileInformationByHandle() would additionally query volume info. --- storage/innobase/os/os0file.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 2ef1940fdcd..b5c6381537e 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -5639,10 +5639,11 @@ os_is_sparse_file_supported(os_file_t fh) ); #ifdef _WIN32 - BY_HANDLE_FILE_INFORMATION info; - if (GetFileInformationByHandle(fh,&info)) { - if (info.dwFileAttributes != INVALID_FILE_ATTRIBUTES) { - return (info.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0; + FILE_ATTRIBUTE_TAG_INFO info; + if (GetFileInformationByHandleEx(fh, FileAttributeTagInfo, + &info, (DWORD)sizeof(info))) { + if (info.FileAttributes != INVALID_FILE_ATTRIBUTES) { + return (info.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0; } } return false; From dc93ce8dea9136889f96659bbee15f9f265d6389 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 9 Oct 2017 19:53:27 +0000 Subject: [PATCH 18/34] Windows : Fix truncation warnings in sql/ --- sql/item_sum.cc | 2 +- sql/item_xmlfunc.cc | 24 ++++++++--------- sql/log_event.cc | 20 +++++++------- sql/mysqld.cc | 4 +-- sql/opt_range.cc | 40 +++++++++++++-------------- sql/opt_range_mrr.cc | 12 ++++----- sql/opt_sum.cc | 4 +-- sql/opt_table_elimination.cc | 8 +++--- sql/parse_file.cc | 2 +- sql/partition_info.cc | 2 +- sql/rpl_record.cc | 6 ++--- sql/rpl_record_old.cc | 6 ++--- sql/spatial.cc | 2 +- sql/sql_acl.cc | 2 +- sql/sql_base.cc | 2 +- sql/sql_cache.cc | 4 +-- sql/sql_db.cc | 4 +-- sql/sql_join_cache.cc | 6 ++--- sql/sql_repl.cc | 6 ++--- sql/sql_select.cc | 52 ++++++++++++++++++------------------ sql/sql_show.cc | 6 ++--- sql/sql_statistics.cc | 20 +++++++------- sql/sql_table.cc | 18 ++++++------- sql/sql_test.cc | 2 +- sql/sql_time.cc | 2 +- sql/sql_update.cc | 2 +- sql/sql_yacc.yy | 16 +++++------ sql/strfunc.cc | 2 +- sql/sys_vars.cc | 2 +- sql/table.cc | 6 ++--- 30 files changed, 142 insertions(+), 142 deletions(-) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 92f18d7402f..df09beeb274 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3657,7 +3657,7 @@ bool Item_func_group_concat::setup(THD *thd) syntax of this function). If there is no ORDER BY clause, we don't create this tree. */ - init_tree(tree, (uint) MY_MIN(thd->variables.max_heap_table_size, + init_tree(tree, (size_t)MY_MIN(thd->variables.max_heap_table_size, thd->variables.sortbuff_size/16), 0, tree_key_length, group_concat_key_cmp_with_order, NULL, (void*) this, diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 10dda8f20e8..57b1807d78c 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -176,7 +176,7 @@ public: { nodebeg= (MY_XML_NODE*) pxml->ptr(); nodeend= (MY_XML_NODE*) (pxml->ptr() + pxml->length()); - numnodes= nodeend - nodebeg; + numnodes= (uint)(nodeend - nodebeg); } void prepare(String *nodeset) { @@ -615,7 +615,7 @@ public: if ((node->parent == flt->num) && (node->type == MY_XML_NODE_TEXT)) { - fake->set_value(node->beg, node->end - node->beg, + fake->set_value(node->beg, (uint)(node->end - node->beg), collation.collation); if (args[1]->val_int()) return 1; @@ -817,7 +817,7 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str) Item_func *comp_func= (Item_func*)args[1]; uint pos= 0, size; prepare(str); - size= fltend - fltbeg; + size= (uint)(fltend - fltbeg); for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++) { nodeset_func->context_cache.length(0); @@ -836,7 +836,7 @@ String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset) Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0]; prepare(nodeset); MY_XPATH_FLT *flt; - uint pos, size= fltend - fltbeg; + uint pos, size= (uint)(fltend - fltbeg); for (pos= 0, flt= fltbeg; flt < fltend; flt++) { nodeset_func->context_cache.length(0); @@ -995,7 +995,7 @@ static Item *create_comparator(MY_XPATH *xpath, else if (a->type() == Item::XPATH_NODESET && b->type() == Item::XPATH_NODESET) { - uint len= xpath->query.end - context->beg; + uint len= (uint)(xpath->query.end - context->beg); set_if_smaller(len, 32); my_printf_error(ER_UNKNOWN_ERROR, "XPATH error: " @@ -1399,7 +1399,7 @@ MY_XPATH_FUNC * my_xpath_function(const char *beg, const char *end) { MY_XPATH_FUNC *k, *function_names; - uint length= end-beg; + uint length= (uint)(end-beg); switch (length) { case 1: return 0; @@ -1961,7 +1961,7 @@ static int my_xpath_parse_PrimaryExpr_literal(MY_XPATH *xpath) return 0; xpath->item= new (xpath->thd->mem_root) Item_string(xpath->thd, xpath->prevtok.beg + 1, - xpath->prevtok.end - xpath->prevtok.beg - 2, + (uint)(xpath->prevtok.end - xpath->prevtok.beg - 2), xpath->cs); return 1; } @@ -2499,13 +2499,13 @@ static int my_xpath_parse_Number(MY_XPATH *xpath) if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOT)) { xpath->item= new (thd->mem_root) Item_int(thd, xpath->prevtok.beg, - xpath->prevtok.end - xpath->prevtok.beg); + (uint)(xpath->prevtok.end - xpath->prevtok.beg)); return 1; } my_xpath_parse_term(xpath, MY_XPATH_LEX_DIGITS); xpath->item= new (thd->mem_root) Item_float(thd, beg, - xpath->prevtok.end - beg); + (uint)(xpath->prevtok.end - beg)); return 1; } @@ -2632,7 +2632,7 @@ my_xpath_parse_VariableReference(MY_XPATH *xpath) { xpath->item= NULL; DBUG_ASSERT(xpath->query.end > dollar_pos); - uint len= xpath->query.end - dollar_pos; + uint len= (uint)(xpath->query.end - dollar_pos); set_if_smaller(len, 32); my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.*s'", MYF(0), len, dollar_pos); @@ -2660,7 +2660,7 @@ my_xpath_parse_NodeTest_QName(MY_XPATH *xpath) if (!my_xpath_parse_QName(xpath)) return 0; DBUG_ASSERT(xpath->context); - uint len= xpath->prevtok.end - xpath->prevtok.beg; + uint len= (uint)(xpath->prevtok.end - xpath->prevtok.beg); xpath->context= nametestfunc(xpath, xpath->axis, xpath->context, xpath->prevtok.beg, len); return 1; @@ -2759,7 +2759,7 @@ bool Item_xml_str_func::fix_fields(THD *thd, Item **ref) if (!rc) { - uint clen= xpath.query.end - xpath.lasttok.beg; + uint clen= (uint)(xpath.query.end - xpath.lasttok.beg); set_if_smaller(clen, 32); my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.*s'", MYF(0), clen, xpath.lasttok.beg); diff --git a/sql/log_event.cc b/sql/log_event.cc index 81cf7d8c250..8932d0f261d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1131,7 +1131,7 @@ int append_query_string(CHARSET_INFO *csinfo, String *to, *ptr++= '\''; } - to->length(orig_len + ptr - beg); + to->length((uint32)(orig_len + ptr - beg)); return 0; } #endif @@ -10034,7 +10034,7 @@ Execute_load_query_log_event::do_apply_event(rpl_group_info *rgi) p= strmake(p, STRING_WITH_LEN(" INTO ")); p= strmake(p, query+fn_pos_end, q_len-fn_pos_end); - error= Query_log_event::do_apply_event(rgi, buf, p-buf); + error= Query_log_event::do_apply_event(rgi, buf, (uint32)(p-buf)); /* Forging file name for deletion in same buffer */ *fname_end= 0; @@ -10486,7 +10486,7 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length) if (static_cast(m_rows_end - m_rows_cur) <= length) { size_t const block_size= 1024; - ulong cur_size= m_rows_cur - m_rows_buf; + size_t cur_size= m_rows_cur - m_rows_buf; DBUG_EXECUTE_IF("simulate_too_big_row_case1", cur_size= UINT_MAX32 - (block_size * 10); length= UINT_MAX32 - (block_size * 10);); @@ -10499,21 +10499,21 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length) DBUG_EXECUTE_IF("simulate_too_big_row_case4", cur_size= UINT_MAX32 - (block_size * 10); length= (block_size * 10) - block_size + 1;); - ulong remaining_space= UINT_MAX32 - cur_size; + size_t remaining_space= UINT_MAX32 - cur_size; /* Check that the new data fits within remaining space and we can add block_size without wrapping. */ - if (length > remaining_space || + if (cur_size > UINT_MAX32 || length > remaining_space || ((length + block_size) > remaining_space)) { sql_print_error("The row data is greater than 4GB, which is too big to " "write to the binary log."); DBUG_RETURN(ER_BINLOG_ROW_LOGGING_FAILED); } - ulong const new_alloc= + size_t const new_alloc= block_size * ((cur_size + length + block_size - 1) / block_size); - uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, (uint) new_alloc, + uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, new_alloc, MYF(MY_ALLOW_ZERO_PTR|MY_WME)); if (unlikely(!new_buf)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); @@ -11246,11 +11246,11 @@ bool Rows_log_event::write_compressed() uchar *m_rows_cur_tmp = m_rows_cur; bool ret = true; uint32 comlen, alloc_size; - comlen= alloc_size= binlog_get_compress_len(m_rows_cur_tmp - m_rows_buf_tmp); + comlen= alloc_size= binlog_get_compress_len((uint32)(m_rows_cur_tmp - m_rows_buf_tmp)); m_rows_buf = (uchar *)my_safe_alloca(alloc_size); if(m_rows_buf && !binlog_buf_compress((const char *)m_rows_buf_tmp, (char *)m_rows_buf, - m_rows_cur_tmp - m_rows_buf_tmp, &comlen)) + (uint32)(m_rows_cur_tmp - m_rows_buf_tmp), &comlen)) { m_rows_cur= comlen + m_rows_buf; ret= Log_event::write(); @@ -12477,7 +12477,7 @@ Rows_log_event::write_row(rpl_group_info *rgi, the size of the first row and use that value to initialize storage engine for bulk insertion */ DBUG_ASSERT(!(m_curr_row > m_curr_row_end)); - ulong estimated_rows= 0; + ha_rows estimated_rows= 0; if (m_curr_row < m_curr_row_end) estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row); else if (m_curr_row == m_curr_row_end) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c784fb23898..0e1543ecd2f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8799,8 +8799,8 @@ static int mysql_init_variables(void) /* Set directory paths */ mysql_real_data_home_len= - strmake_buf(mysql_real_data_home, - get_relative_path(MYSQL_DATADIR)) - mysql_real_data_home; + (uint)(strmake_buf(mysql_real_data_home, + get_relative_path(MYSQL_DATADIR)) - mysql_real_data_home); /* Replication parameters */ master_info_file= (char*) "master.info", relay_log_info_file= (char*) "relay-log.info"; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d4dfc5a65af..415b76a28bb 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -499,9 +499,9 @@ int SEL_IMERGE::or_sel_tree(RANGE_OPT_PARAM *param, SEL_TREE *tree) if (trees_next == trees_end) { const int realloc_ratio= 2; /* Double size for next round */ - uint old_elements= (trees_end - trees); - uint old_size= sizeof(SEL_TREE**) * old_elements; - uint new_size= old_size * realloc_ratio; + size_t old_elements= (trees_end - trees); + size_t old_size= sizeof(SEL_TREE**) * old_elements; + size_t new_size= old_size * realloc_ratio; SEL_TREE **new_trees; if (!(new_trees= (SEL_TREE**)alloc_root(param->mem_root, new_size))) return -1; @@ -846,10 +846,10 @@ SEL_TREE::SEL_TREE(SEL_TREE *arg, bool without_merges, SEL_IMERGE::SEL_IMERGE(SEL_IMERGE *arg, uint cnt, RANGE_OPT_PARAM *param) : Sql_alloc() { - uint elements= (arg->trees_end - arg->trees); + size_t elements= (arg->trees_end - arg->trees); if (elements > PREALLOCED_TREES) { - uint size= elements * sizeof (SEL_TREE **); + size_t size= elements * sizeof (SEL_TREE **); if (!(trees= (SEL_TREE **)alloc_root(param->mem_root, size))) goto mem_err; } @@ -951,7 +951,7 @@ int imerge_list_or_list(RANGE_OPT_PARAM *param, uint rc; bool is_last_check_pass= FALSE; SEL_IMERGE *imerge= im1->head(); - uint elems= imerge->trees_next-imerge->trees; + uint elems= (uint)(imerge->trees_next-imerge->trees); MEM_ROOT *mem_root= current_thd->mem_root; im1->empty(); @@ -1051,7 +1051,7 @@ int imerge_list_or_tree(RANGE_OPT_PARAM *param, SEL_TREE *or_tree= new (mem_root) SEL_TREE (tree, FALSE, param); if (or_tree) { - uint elems= imerge->trees_next-imerge->trees; + uint elems= (uint)(imerge->trees_next-imerge->trees); rc= imerge->or_sel_tree_with_checks(param, elems, or_tree, TRUE, &is_last_check_pass); if (!is_last_check_pass) @@ -2897,7 +2897,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) uint keynr; uint max_quick_key_parts= 0; MY_BITMAP *used_fields= &table->cond_set; - double table_records= table->stat_records(); + double table_records= (double)table->stat_records(); DBUG_ENTER("calculate_cond_selectivity_for_table"); table->cond_selectivity= 1.0; @@ -3994,8 +3994,8 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) store_length_array, range_par->min_key, range_par->max_key, - tmp_min_key - range_par->min_key, - tmp_max_key - range_par->max_key, + (uint)(tmp_min_key - range_par->min_key), + (uint)(tmp_max_key - range_par->max_key), flag, &ppar->part_iter); if (!res) @@ -4659,7 +4659,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, } } - uint n_child_scans= imerge->trees_next - imerge->trees; + size_t n_child_scans= imerge->trees_next - imerge->trees; if (!n_child_scans) DBUG_RETURN(NULL); @@ -5203,7 +5203,7 @@ bool prepare_search_best_index_intersect(PARAM *param, INDEX_SCAN_INFO **scan_ptr; INDEX_SCAN_INFO *cpk_scan= NULL; TABLE *table= param->table; - uint n_index_scans= tree->index_scans_end - tree->index_scans; + uint n_index_scans= (uint)(tree->index_scans_end - tree->index_scans); if (!n_index_scans) return 1; @@ -5846,7 +5846,7 @@ TRP_INDEX_INTERSECT *get_best_index_intersect(PARAM *param, SEL_TREE *tree, } } - count= tree->index_scans_end - tree->index_scans; + count= (uint)(tree->index_scans_end - tree->index_scans); for (i= 0; i < count; i++) { index_scan= tree->index_scans[i]; @@ -6506,7 +6506,7 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, intersect_scans_best);); *are_all_covering= intersect->is_covering; - uint best_num= intersect_scans_best - intersect_scans; + uint best_num= (uint)(intersect_scans_best - intersect_scans); ror_intersect_cpy(intersect, intersect_best); /* @@ -6688,7 +6688,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, TRP_ROR_INTERSECT *trp; if (!(trp= new (param->mem_root) TRP_ROR_INTERSECT)) DBUG_RETURN(trp); - uint best_num= (ror_scan_mark - tree->ror_scans); + uint best_num= (uint)(ror_scan_mark - tree->ror_scans); if (!(trp->first_scan= (ROR_SCAN_INFO**)alloc_root(param->mem_root, sizeof(ROR_SCAN_INFO*)* best_num))) @@ -11454,7 +11454,7 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, DBUG_RETURN(0); } - uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); + uint count= ranges.elements - (uint)(cur_range - (QUICK_RANGE**) ranges.buffer); if (count == 0) { /* Ranges have already been used up before. None is left for read. */ @@ -11499,7 +11499,7 @@ int QUICK_RANGE_SELECT_GEOM::get_next() DBUG_RETURN(result); } - uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); + uint count= ranges.elements - (uint)(cur_range - (QUICK_RANGE**) ranges.buffer); if (count == 0) { /* Ranges have already been used up before. None is left for read. */ @@ -11953,7 +11953,7 @@ void QUICK_SELECT_I::add_key_and_length(String *key_names, bool *first) { char buf[64]; - uint length; + size_t length; KEY *key_info= head->key_info + index; if (*first) @@ -12507,7 +12507,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) { cur_group_prefix_len+= cur_part->store_length; ++cur_group_key_parts; - max_key_part= cur_part - cur_index_info->key_part + 1; + max_key_part= (uint)(cur_part - cur_index_info->key_part) + 1; used_key_parts_map.set_bit(max_key_part); } else @@ -13230,7 +13230,7 @@ get_field_keypart(KEY *index, Field *field) part < end; part++) { if (field->eq(part->field)) - return part - index->key_part + 1; + return (uint)(part - index->key_part + 1); } return 0; } diff --git a/sql/opt_range_mrr.cc b/sql/opt_range_mrr.cc index b3350191d13..ace6208fd77 100644 --- a/sql/opt_range_mrr.cc +++ b/sql/opt_range_mrr.cc @@ -199,9 +199,9 @@ walk_right_n_up: { { RANGE_SEQ_ENTRY *cur= &seq->stack[seq->i]; - uint min_key_length= cur->min_key - seq->param->min_key; - uint max_key_length= cur->max_key - seq->param->max_key; - uint len= cur->min_key - cur[-1].min_key; + size_t min_key_length= cur->min_key - seq->param->min_key; + size_t max_key_length= cur->max_key - seq->param->max_key; + size_t len= cur->min_key - cur[-1].min_key; if (!(min_key_length == max_key_length && !memcmp(cur[-1].min_key, cur[-1].max_key, len) && !key_tree->min_flag && !key_tree->max_flag)) @@ -238,7 +238,7 @@ walk_up_n_right: /* Ok got a tuple */ RANGE_SEQ_ENTRY *cur= &seq->stack[seq->i]; - uint min_key_length= cur->min_key - seq->param->min_key; + uint min_key_length= (uint)(cur->min_key - seq->param->min_key); range->ptr= (char*)(intptr)(key_tree->part); if (cur->min_key_flag & GEOM_FLAG) @@ -256,13 +256,13 @@ walk_up_n_right: range->range_flag= cur->min_key_flag | cur->max_key_flag; range->start_key.key= seq->param->min_key; - range->start_key.length= cur->min_key - seq->param->min_key; + range->start_key.length= (uint)(cur->min_key - seq->param->min_key); range->start_key.keypart_map= make_prev_keypart_map(cur->min_key_parts); range->start_key.flag= (cur->min_key_flag & NEAR_MIN ? HA_READ_AFTER_KEY : HA_READ_KEY_EXACT); range->end_key.key= seq->param->max_key; - range->end_key.length= cur->max_key - seq->param->max_key; + range->end_key.length= (uint)(cur->max_key - seq->param->max_key); range->end_key.flag= (cur->max_key_flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); range->end_key.keypart_map= make_prev_keypart_map(cur->max_key_parts); diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index ab587b8b279..8a75aaed8d6 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -768,12 +768,12 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, key_part_map org_key_part_used= *key_part_used; if (eq_type || between || max_fl == less_fl) { - uint length= (key_ptr-ref->key_buff)+part->store_length; + uint length= (uint)(key_ptr-ref->key_buff)+part->store_length; if (ref->key_length < length) { /* Ultimately ref->key_length will contain the length of the search key */ ref->key_length= length; - ref->key_parts= (part - keyinfo->key_part) + 1; + ref->key_parts= (uint)(part - keyinfo->key_part) + 1; } if (!*prefix_len && part+1 == field_part) *prefix_len= length; diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc index b7010d1f8ed..a480a1659e9 100644 --- a/sql/opt_table_elimination.cc +++ b/sql/opt_table_elimination.cc @@ -848,7 +848,7 @@ bool check_func_dependency(JOIN *join, */ uint and_level=0; build_eq_mods_for_cond(join->thd, &dac, &last_eq_mod, &and_level, cond); - if (!(dac.n_equality_mods= last_eq_mod - dac.equality_mods)) + if (!(dac.n_equality_mods= (uint)(last_eq_mod - dac.equality_mods))) return FALSE; /* No useful conditions */ List bound_modules; @@ -1061,7 +1061,7 @@ bool Dep_analysis_context::setup_equality_modules_deps(List eq_mod < equality_mods + n_equality_mods; eq_mod++) { - deps_recorder.expr_offset= eq_mod - equality_mods; + deps_recorder.expr_offset= (uint)(eq_mod - equality_mods); deps_recorder.visited_other_tables= FALSE; eq_mod->unbound_args= 0; @@ -1079,7 +1079,7 @@ bool Dep_analysis_context::setup_equality_modules_deps(List Dep_value_field* field_val; while ((field_val= it++)) { - uint offs= field_val->bitmap_offset + eq_mod - equality_mods; + uint offs= (uint)(field_val->bitmap_offset + eq_mod - equality_mods); bitmap_set_bit(&expr_deps, offs); } } @@ -1158,7 +1158,7 @@ void build_eq_mods_for_cond(THD *thd, Dep_analysis_context *ctx, if (cond->type() == Item_func::COND_ITEM) { List_iterator_fast li(*((Item_cond*) cond)->argument_list()); - uint orig_offset= *eq_mod - ctx->equality_mods; + size_t orig_offset= *eq_mod - ctx->equality_mods; /* AND/OR */ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 0c44f6a9820..2aad3f38761 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -255,7 +255,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, File handler; IO_CACHE file; char path[FN_REFLEN+1]; // +1 to put temporary file name for sure - int path_end; + size_t path_end; File_option *param; DBUG_ENTER("sql_create_definition_file"); DBUG_PRINT("enter", ("Dir: %s, file: %s, base %p", diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 535ed4612e0..c2bc530117f 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1673,7 +1673,7 @@ void partition_info::print_no_partition_found(TABLE *table_arg, myf errflag) bool partition_info::set_part_expr(THD *thd, char *start_token, Item *item_ptr, char *end_token, bool is_subpart) { - uint expr_len= end_token - start_token; + size_t expr_len= end_token - start_token; char *func_string= (char*) thd->memdup(start_token, expr_len); if (!func_string) diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 3147baf7d73..dd4c952fa30 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -80,7 +80,7 @@ pack_row(TABLE *table, MY_BITMAP const* cols, unsigned int null_mask= 1U; for ( ; (field= *p_field) ; p_field++) { - if (bitmap_is_set(cols, p_field - table->field)) + if (bitmap_is_set(cols, (uint)(p_field - table->field))) { my_ptrdiff_t offset; if (field->is_null(rec_offset)) @@ -262,7 +262,7 @@ unpack_row(rpl_group_info *rgi, No need to bother about columns that does not exist: they have gotten default values when being emptied above. */ - if (bitmap_is_set(cols, field_ptr - begin_ptr)) + if (bitmap_is_set(cols, (uint)(field_ptr - begin_ptr))) { if ((null_mask & 0xFF) == 0) { @@ -434,7 +434,7 @@ unpack_row(rpl_group_info *rgi, if (master_reclength) { if (*field_ptr) - *master_reclength = (*field_ptr)->ptr - table->record[0]; + *master_reclength = (ulong)((*field_ptr)->ptr - table->record[0]); else *master_reclength = table->s->reclength; } diff --git a/sql/rpl_record_old.cc b/sql/rpl_record_old.cc index 5b876373b9c..8e21c4a94a5 100644 --- a/sql/rpl_record_old.cc +++ b/sql/rpl_record_old.cc @@ -134,7 +134,7 @@ unpack_row_old(rpl_group_info *rgi, { Field *const f= *field_ptr; - if (bitmap_is_set(cols, field_ptr - begin_ptr)) + if (bitmap_is_set(cols, (uint)(field_ptr - begin_ptr))) { f->move_field_offset(offset); ptr= f->unpack(f->ptr, ptr, row_buffer_end, 0); @@ -149,14 +149,14 @@ unpack_row_old(rpl_group_info *rgi, } } else - bitmap_clear_bit(rw_set, field_ptr - begin_ptr); + bitmap_clear_bit(rw_set, (uint)(field_ptr - begin_ptr)); } *row_end = ptr; if (master_reclength) { if (*field_ptr) - *master_reclength = (*field_ptr)->ptr - table->record[0]; + *master_reclength = (ulong)((*field_ptr)->ptr - table->record[0]); else *master_reclength = table->s->reclength; } diff --git a/sql/spatial.cc b/sql/spatial.cc index 8817e82d6c4..357e311543f 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -2565,7 +2565,7 @@ uint Gis_multi_polygon::init_from_opresult(String *bin, n_poly++; } bin->write_at_position(np_pos, n_poly); - return opres - opres_orig; + return (uint)(opres - opres_orig); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 819bdb8200a..af49eefa2a5 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -12341,7 +12341,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length) char *end= user + packet_length; /* Safe because there is always a trailing \0 at the end of the packet */ char *passwd= strend(user) + 1; - uint user_len= passwd - user - 1; + uint user_len= (uint)(passwd - user - 1); char *db= passwd; char db_buff[SAFE_NAME_LEN + 1]; // buffer to store db in utf8 char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 9c752b4f882..ea57e1d19c9 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5444,7 +5444,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, if (field_ptr && *field_ptr) { - *cached_field_index_ptr= field_ptr - table->field; + *cached_field_index_ptr= (uint)(field_ptr - table->field); field= *field_ptr; } else diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 9077af58d31..6727be69d07 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -4286,7 +4286,7 @@ my_bool Query_cache::move_by_type(uchar **border, *pprev = block->pprev, *pnext = block->pnext, *new_block =(Query_cache_block *) *border; - uint tablename_offset = block->table()->table() - block->table()->db(); + size_t tablename_offset = block->table()->table() - block->table()->db(); char *data = (char*) block->data(); uchar *key; size_t key_length; @@ -4595,7 +4595,7 @@ uint Query_cache::filename_2_table_key (char *key, const char *path, filename= tablename + dirname_length(tablename + 2) + 2; /* Find start of databasename */ for (dbname= filename - 2 ; dbname[-1] != FN_LIBCHAR ; dbname--) ; - *db_length= (filename - dbname) - 1; + *db_length= (uint32)(filename - dbname) - 1; DBUG_PRINT("qcache", ("table '%-.*s.%s'", *db_length, dbname, filename)); DBUG_RETURN((uint) (strmake(strmake(key, dbname, diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 813a17cdfdb..073e351d895 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1018,7 +1018,7 @@ update_binlog: These DDL methods and logging are protected with the exclusive metadata lock on the schema. */ - if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len)) + if (write_to_binlog(thd, query, (uint)(query_pos -1 - query), db, db_len)) { error= true; goto exit; @@ -1036,7 +1036,7 @@ update_binlog: These DDL methods and logging are protected with the exclusive metadata lock on the schema. */ - if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len)) + if (write_to_binlog(thd, query, (uint)(query_pos -1 - query), db, db_len)) { error= true; goto exit; diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index 41741f3dcc7..e6ef8a4be9f 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -406,7 +406,7 @@ void JOIN_CACHE::create_flag_fields() } /* Theoretically the new value of flag_fields can be less than the old one */ - flag_fields= copy-field_descr; + flag_fields= (uint)(copy-field_descr); } @@ -1374,7 +1374,7 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full) } /* Save the offset of the field to put it later at the end of the record */ if (copy->referenced_field_no) - copy->offset= cp-curr_rec_pos; + copy->offset= (uint)(cp-curr_rec_pos); switch (copy->type) { case CACHE_BLOB: @@ -1778,7 +1778,7 @@ uint JOIN_CACHE::read_flag_fields() memcpy(copy->str, pos, copy->length); pos+= copy->length; } - return (pos-init_pos); + return (uint)(pos-init_pos); } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index e3a082b680d..848dce6d4ca 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2681,7 +2681,7 @@ static int send_events(binlog_send_info *info, IO_CACHE* log, LOG_INFO* linfo, Gtid_list_log_event glev(&info->until_binlog_state, 0); if (reset_transmit_packet(info, info->flags, &ev_offset, &info->errmsg) || - fake_gtid_list_event(info, &glev, &info->errmsg, my_b_tell(log))) + fake_gtid_list_event(info, &glev, &info->errmsg, (uint32)my_b_tell(log))) { info->error= ER_UNKNOWN_ERROR; return 1; @@ -2691,7 +2691,7 @@ static int send_events(binlog_send_info *info, IO_CACHE* log, LOG_INFO* linfo, if (info->until_gtid_state && is_until_reached(info, &ev_offset, event_type, &info->errmsg, - my_b_tell(log))) + (uint32)my_b_tell(log))) { if (info->errmsg) { @@ -2746,7 +2746,7 @@ static int send_one_binlog_file(binlog_send_info *info, if (end_pos <= 1) { /** end of file or error */ - return end_pos; + return (int)end_pos; } /** diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0ce7ff958db..f4f0e46afed 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6077,7 +6077,7 @@ double matching_candidates_in_table(JOIN_TAB *s, bool with_found_constraint, { TABLE *table= s->table; double sel= table->cond_selectivity; - double table_records= table->stat_records(); + double table_records= (double)table->stat_records(); dbl_records= table_records * sel; return dbl_records; } @@ -6103,7 +6103,7 @@ double matching_candidates_in_table(JOIN_TAB *s, bool with_found_constraint, if (s->table->quick_condition_rows != s->found_records) records= s->table->quick_condition_rows; - dbl_records= records; + dbl_records= (double)records; return dbl_records; } @@ -6794,7 +6794,7 @@ static void choose_initial_table_order(JOIN *join) if ((emb_subq= get_emb_subq(*tab))) break; } - uint n_subquery_tabs= tabs_end - tab; + uint n_subquery_tabs= (uint)(tabs_end - tab); if (!n_subquery_tabs) DBUG_VOID_RETURN; @@ -6822,7 +6822,7 @@ static void choose_initial_table_order(JOIN *join) last_tab_for_subq < subq_tabs_end && get_emb_subq(*last_tab_for_subq) == cur_subq_nest; last_tab_for_subq++) {} - uint n_subquery_tables= last_tab_for_subq - subq_tab; + uint n_subquery_tables= (uint)(last_tab_for_subq - subq_tab); /* Walk the original array and find where this subquery would have been @@ -6840,7 +6840,7 @@ static void choose_initial_table_order(JOIN *join) if (!need_tables) { /* Move away the top-level tables that are after top_level_tab */ - uint top_tail_len= last_top_level_tab - top_level_tab - 1; + size_t top_tail_len= last_top_level_tab - top_level_tab - 1; memmove(top_level_tab + 1 + n_subquery_tables, top_level_tab + 1, sizeof(JOIN_TAB*)*top_tail_len); last_top_level_tab += n_subquery_tables; @@ -7586,7 +7586,7 @@ double JOIN::get_examined_rows() JOIN_TAB *tab= first_breadth_first_tab(); JOIN_TAB *prev_tab= tab; - examined_rows= tab->get_examined_rows(); + examined_rows= (double)tab->get_examined_rows(); while ((tab= next_breadth_first_tab(first_breadth_first_tab(), top_join_tab_count, tab))) @@ -7884,7 +7884,7 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, } if (keyparts > 1) { - ref_keyuse_steps[keyparts-2]= keyuse - prev_ref_keyuse; + ref_keyuse_steps[keyparts-2]= (uint16)(keyuse - prev_ref_keyuse); prev_ref_keyuse= keyuse; } } @@ -8984,8 +8984,8 @@ bool JOIN::get_best_combination() j= j->bush_root_tab; } - top_join_tab_count= join_tab_ranges.head()->end - - join_tab_ranges.head()->start; + top_join_tab_count= (uint)(join_tab_ranges.head()->end - + join_tab_ranges.head()->start); update_depend_map(this); DBUG_RETURN(0); @@ -10561,7 +10561,7 @@ static uint make_join_orderinfo(JOIN *join) if (join->need_tmp) return join->table_count; tab= join->get_sort_by_join_tab(); - return tab ? tab-join->join_tab : join->table_count; + return tab ? (uint)(tab-join->join_tab) : join->table_count; } /* @@ -11578,8 +11578,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) str.append(" final_pushdown_cond"); print_where(tab->select_cond, str.c_ptr_safe(), QT_ORDINARY);); } - uint n_top_tables= join->join_tab_ranges.head()->end - - join->join_tab_ranges.head()->start; + uint n_top_tables= (uint)(join->join_tab_ranges.head()->end - + join->join_tab_ranges.head()->start); join->join_tab[n_top_tables - 1].next_select=0; /* Set by do_select */ @@ -11803,7 +11803,7 @@ ha_rows JOIN_TAB::get_examined_rows() SQL_SELECT *sel= filesort? filesort->select : this->select; if (sel && sel->quick && use_quick != 2) - examined_rows= sel->quick->records; + examined_rows= (double)sel->quick->records; else if (type == JT_NEXT || type == JT_ALL || type == JT_HASH || type ==JT_HASH_NEXT) { @@ -11813,19 +11813,19 @@ ha_rows JOIN_TAB::get_examined_rows() @todo This estimate is wrong, a LIMIT query may examine much more rows than the LIMIT itself. */ - examined_rows= limit; + examined_rows= (double)limit; } else { if (table->is_filled_at_execution()) - examined_rows= records; + examined_rows= (double)records; else { /* handler->info(HA_STATUS_VARIABLE) has been called in make_join_statistics() */ - examined_rows= table->stat_records(); + examined_rows= (double)table->stat_records(); } } } @@ -13624,7 +13624,7 @@ static int compare_fields_by_table_order(Item *field1, tab2= tab2->bush_root_tab; } - cmp= tab1 - tab2; + cmp= (int)(tab1 - tab2); if (!cmp) { @@ -16845,7 +16845,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, share->default_values= table->record[1]+alloc_length; } copy_func[0]=0; // End marker - param->func_count= copy_func - param->items_to_copy; + param->func_count= (uint)(copy_func - param->items_to_copy); setup_tmp_table_column_bitmaps(table, bitmaps); @@ -17529,7 +17529,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, Emulate behaviour by making column not-nullable when creating the table. */ - uint cols= (*recinfo-start_recinfo); + uint cols= (uint)(*recinfo-start_recinfo); start_recinfo[cols-1].null_bit= 0; } } @@ -20747,7 +20747,7 @@ static int test_if_order_by_key(JOIN *join, (1) this is an extended key (2) we've reached its end */ - key_parts= (key_part - table->key_info[idx].key_part); + key_parts= (uint)(key_part - table->key_info[idx].key_part); if (have_pk_suffix && reverse == 0 && // all were =const so far key_parts == table->key_info[idx].ext_key_parts && @@ -24386,7 +24386,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, } else { - double examined_rows= get_examined_rows(); + double examined_rows= (double)get_examined_rows(); eta->rows_set= true; eta->rows= (ha_rows) examined_rows; @@ -25757,8 +25757,8 @@ static bool get_range_limit_read_cost(const JOIN_TAB *tab, Start from quick select's rows and cost. These are always cheaper than full index scan/cost. */ - double best_rows= table->quick_rows[keynr]; - double best_cost= table->quick_costs[keynr]; + double best_rows= (double)table->quick_rows[keynr]; + double best_cost= (double)table->quick_costs[keynr]; /* Check if ref(const) access was possible on this index. @@ -25792,7 +25792,7 @@ static bool get_range_limit_read_cost(const JOIN_TAB *tab, if (ref_rows > 0) { - double tmp= ref_rows; + double tmp= (double)ref_rows; /* Reuse the cost formula from best_access_path: */ set_if_smaller(tmp, (double) tab->join->thd->variables.max_seeks_for_key); if (table->covering_keys.is_set(keynr)) @@ -25803,7 +25803,7 @@ static bool get_range_limit_read_cost(const JOIN_TAB *tab, if (tmp < best_cost) { best_cost= tmp; - best_rows= ref_rows; + best_rows= (double)ref_rows; } } } @@ -25916,7 +25916,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, if (join) { - uint tablenr= tab - join->join_tab; + uint tablenr= (uint)(tab - join->join_tab); read_time= join->best_positions[tablenr].read_time; for (uint i= tablenr+1; i < join->table_count; i++) fanout*= join->best_positions[i].records_read; // fanout is always >= 1 diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1ed1201489e..579cbcd878e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3369,7 +3369,7 @@ static bool show_status_array(THD *thd, const char *wild, prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1); if (*prefix) *prefix_end++= '_'; - len=name_buffer + sizeof(name_buffer) - prefix_end; + len=(int)(name_buffer + sizeof(name_buffer) - prefix_end); #ifdef WITH_WSREP bool is_wsrep_var= FALSE; @@ -5363,7 +5363,7 @@ static void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs, */ tmp_buff= strchr(column_type.c_ptr_safe(), ' '); table->field[offset]->store(column_type.ptr(), - (tmp_buff ? tmp_buff - column_type.ptr() : + (tmp_buff ? (uint)(tmp_buff - column_type.ptr()) : column_type.length()), cs); is_blob= (field->type() == MYSQL_TYPE_BLOB); @@ -6345,7 +6345,7 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, table->field[5]->store(STRING_WITH_LEN("NO"), cs); } - definer_len= (strxmov(definer, tables->definer.user.str, "@", + definer_len= (uint)(strxmov(definer, tables->definer.user.str, "@", tables->definer.host.str, NullS) - definer); table->field[6]->store(definer, definer_len, cs); if (tables->view_suid) diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 9c84729e1c2..5a9bf08d99b 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -843,7 +843,7 @@ public: else { stat_field->set_notnull(); - stat_field->store(table->collected_stats->cardinality); + stat_field->store(table->collected_stats->cardinality,true); } } @@ -1055,7 +1055,7 @@ public: switch (i) { case COLUMN_STAT_MIN_VALUE: if (table_field->type() == MYSQL_TYPE_BIT) - stat_field->store(table_field->collected_stats->min_value->val_int()); + stat_field->store(table_field->collected_stats->min_value->val_int(),true); else { table_field->collected_stats->min_value->val_str(&val); @@ -1064,7 +1064,7 @@ public: break; case COLUMN_STAT_MAX_VALUE: if (table_field->type() == MYSQL_TYPE_BIT) - stat_field->store(table_field->collected_stats->max_value->val_int()); + stat_field->store(table_field->collected_stats->max_value->val_int(),true); else { table_field->collected_stats->max_value->val_str(&val); @@ -1631,7 +1631,7 @@ public: of the parameters to be passed to the constructor of the Unique object. */ - Count_distinct_field(Field *field, uint max_heap_table_size) + Count_distinct_field(Field *field, size_t max_heap_table_size) { table_field= field; tree_key_length= field->pack_length(); @@ -1729,7 +1729,7 @@ class Count_distinct_field_bit: public Count_distinct_field { public: - Count_distinct_field_bit(Field *field, uint max_heap_table_size) + Count_distinct_field_bit(Field *field, size_t max_heap_table_size) { table_field= field; tree_key_length= sizeof(ulonglong); @@ -1825,7 +1825,7 @@ public: if ((calc_state= (Prefix_calc_state *) thd->alloc(sizeof(Prefix_calc_state)*key_parts))) { - uint keyno= key_info-table->key_info; + uint keyno= (uint)(key_info-table->key_info); for (i= 0, state= calc_state; i < key_parts; i++, state++) { /* @@ -2439,7 +2439,7 @@ int alloc_histograms_for_table_share(THD* thd, TABLE_SHARE *table_share, inline void Column_statistics_collected::init(THD *thd, Field *table_field) { - uint max_heap_table_size= thd->variables.max_heap_table_size; + size_t max_heap_table_size= (size_t)thd->variables.max_heap_table_size; TABLE *table= table_field->table; uint pk= table->s->primary_key; @@ -3720,14 +3720,14 @@ double get_column_avg_frequency(Field * field) */ if (!table->s->field) { - res= table->stat_records(); + res= (double)table->stat_records(); return res; } Column_statistics *col_stats= field->read_stats; if (!col_stats) - res= table->stat_records(); + res= (double)table->stat_records(); else res= col_stats->get_avg_frequency(); return res; @@ -3766,7 +3766,7 @@ double get_column_range_cardinality(Field *field, double res; TABLE *table= field->table; Column_statistics *col_stats= field->read_stats; - double tab_records= table->stat_records(); + double tab_records= (double)table->stat_records(); if (!col_stats) return tab_records; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index de367eda992..db9340d7977 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -231,7 +231,7 @@ uint explain_filename(THD* thd, { db_name= table_name; /* calculate the length */ - db_name_len= tmp_p - db_name; + db_name_len= (int)(tmp_p - db_name); tmp_p++; table_name= tmp_p; } @@ -253,7 +253,7 @@ uint explain_filename(THD* thd, case 's': if ((tmp_p[1] == 'P' || tmp_p[1] == 'p') && tmp_p[2] == '#') { - part_name_len= tmp_p - part_name - 1; + part_name_len= (int)(tmp_p - part_name - 1); subpart_name= tmp_p + 3; tmp_p+= 3; } @@ -285,7 +285,7 @@ uint explain_filename(THD* thd, } if (part_name) { - table_name_len= part_name - table_name - 3; + table_name_len= (int)(part_name - table_name - 3); if (subpart_name) subpart_name_len= strlen(subpart_name); else @@ -358,7 +358,7 @@ uint explain_filename(THD* thd, to_p= strnmov(to_p, " */", end_p - to_p); } DBUG_PRINT("exit", ("to '%s'", to)); - DBUG_RETURN(to_p - to); + DBUG_RETURN((uint)(to_p - to)); } @@ -554,7 +554,7 @@ uint build_table_filename(char *buff, size_t bufflen, const char *db, pos= strxnmov(pos, end - pos, tbbuff, ext, NullS); DBUG_PRINT("exit", ("buff: '%s'", buff)); - DBUG_RETURN(pos - buff); + DBUG_RETURN((uint)(pos - buff)); } @@ -2133,7 +2133,7 @@ static uint32 comment_length(THD *thd, uint32 comment_pos, for (query+= 3; query < query_end; query++) { if (query[-1] == '*' && query[0] == '/') - return (char*) query - *comment_start + 1; + return (uint32)((char*) query - *comment_start + 1); } return 0; } @@ -2711,7 +2711,7 @@ bool quick_rm_table(THD *thd, handlerton *base, const char *db, bool error= 0; DBUG_ENTER("quick_rm_table"); - uint path_length= table_path ? + size_t path_length= table_path ? (strxnmov(path, sizeof(path) - 1, table_path, reg_ext, NullS) - path) : build_table_filename(path, sizeof(path)-1, db, table_name, reg_ext, flags); if (mysql_file_delete(key_file_frm, path, MYF(0))) @@ -6690,7 +6690,7 @@ static bool fill_alter_inplace_info(THD *thd, table_key; ha_alter_info->index_add_buffer [ha_alter_info->index_add_count++]= - new_key - ha_alter_info->key_info_buffer; + (uint)(new_key - ha_alter_info->key_info_buffer); /* Mark all old fields which are used in newly created index. */ DBUG_PRINT("info", ("index changed: '%s'", table_key->name)); } @@ -6714,7 +6714,7 @@ static bool fill_alter_inplace_info(THD *thd, /* Key not found. Add the offset of the key to the add buffer. */ ha_alter_info->index_add_buffer [ha_alter_info->index_add_count++]= - new_key - ha_alter_info->key_info_buffer; + (uint)(new_key - ha_alter_info->key_info_buffer); DBUG_PRINT("info", ("index added: '%s'", new_key->name)); } else diff --git a/sql/sql_test.cc b/sql/sql_test.cc index feb99861c48..d16edf5b5d5 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -171,7 +171,7 @@ TEST_join(JOIN *join) in order not to garble the tabular output below. */ String ref_key_parts[MAX_TABLES]; - int tables_in_range= jt_range->end - jt_range->start; + int tables_in_range= (int)(jt_range->end - jt_range->start); for (i= 0; i < tables_in_range; i++) { JOIN_TAB *tab= jt_range->start + i; diff --git a/sql/sql_time.cc b/sql/sql_time.cc index cad4bae03e8..18ea4e8760b 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -274,7 +274,7 @@ to_ascii(CHARSET_INFO *cs, *dst++= static_cast(wc); } *dst= '\0'; - return dst - dst0; + return (uint)(dst - dst0); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4488435491e..b1069efbbc8 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -80,7 +80,7 @@ bool compare_record(const TABLE *table) { if (field->real_maybe_null()) { - uchar null_byte_index= field->null_ptr - table->record[0]; + uchar null_byte_index= (uchar)(field->null_ptr - table->record[0]); if (((table->record[0][null_byte_index]) & field->null_bit) != ((table->record[1][null_byte_index]) & field->null_bit)) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e994ec5f2a5..ded0332bc53 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -565,8 +565,8 @@ create_item_for_sp_var(THD *thd, LEX_STRING name, sp_variable *spvar, DBUG_ASSERT(spc && spvar); /* Position and length of the SP variable name in the query. */ - pos_in_q= start_in_q - lex->sphead->m_tmp_query; - len_in_q= end_in_q - start_in_q; + pos_in_q= (uint)(start_in_q - lex->sphead->m_tmp_query); + len_in_q= (uint)(end_in_q - start_in_q); item= new (thd->mem_root) Item_splocal(thd, name, spvar->offset, spvar->sql_type(), @@ -11836,8 +11836,8 @@ limit_option: { splocal= new (thd->mem_root) Item_splocal(thd, $1, spv->offset, spv->sql_type(), - lip->get_tok_start() - lex->sphead->m_tmp_query, - lip->get_ptr() - lip->get_tok_start()); + (uint)(lip->get_tok_start() - lex->sphead->m_tmp_query), + (uint)(lip->get_ptr() - lip->get_tok_start())); if (splocal == NULL) MYSQL_YYABORT; #ifndef DBUG_OFF @@ -13834,8 +13834,8 @@ param_marker: my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); const char *query_start= lex->sphead ? lex->sphead->m_tmp_query : thd->query(); - item= new (thd->mem_root) Item_param(thd, lip->get_tok_start() - - query_start); + item= new (thd->mem_root) Item_param(thd, (uint)(lip->get_tok_start() - + query_start)); if (!($$= item) || lex->param_list.push_back(item, thd->mem_root)) my_yyabort_error((ER_OUT_OF_RESOURCES, MYF(0))); } @@ -14130,8 +14130,8 @@ simple_ident: Item_splocal *splocal; splocal= new (thd->mem_root) Item_splocal(thd, $1, spv->offset, spv->sql_type(), - lip->get_tok_start_prev() - lex->sphead->m_tmp_query, - lip->get_tok_end() - lip->get_tok_start_prev()); + (uint)(lip->get_tok_start_prev() - lex->sphead->m_tmp_query), + (uint)(lip->get_tok_end() - lip->get_tok_start_prev())); if (splocal == NULL) MYSQL_YYABORT; #ifndef DBUG_OFF diff --git a/sql/strfunc.cc b/sql/strfunc.cc index 4928e939e27..e1b4dc8227f 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -339,7 +339,7 @@ int find_string_in_array(LEX_STRING * const haystack, LEX_STRING * const needle, if (!cs->coll->strnncollsp(cs, (uchar *) pos->str, pos->length, (uchar *) needle->str, needle->length)) { - return (pos - haystack); + return (int)(pos - haystack); } return -1; } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 9f5dfa2d3a9..2bbd0c14f55 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1469,7 +1469,7 @@ static Sys_var_ulonglong Sys_max_heap_table_size( "max_heap_table_size", "Don't allow creation of heap tables bigger than this", SESSION_VAR(max_heap_table_size), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(16384, (ulonglong)~(intptr)0), DEFAULT(16*1024*1024), + VALID_RANGE(16384, SIZE_T_MAX), DEFAULT(16*1024*1024), BLOCK_SIZE(1024)); static ulong mdl_locks_cache_size; diff --git a/sql/table.cc b/sql/table.cc index 2f403de9888..352c6c77691 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2505,7 +2505,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, the correct null_bytes can now be set, since bitfields have been taken into account */ - share->null_bytes= (null_pos - (uchar*) null_flags + + share->null_bytes= (uint)(null_pos - (uchar*) null_flags + (null_bit_pos + 7) / 8); share->last_null_bit_pos= null_bit_pos; share->null_bytes_for_compare= null_bits_are_used ? share->null_bytes : 0; @@ -6001,8 +6001,8 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, TABLE_LIST *parent_ /* The field belongs to a merge view or information schema table. */ Field_translator *translated_field= view_field_it.field_translator(); nj_col= new Natural_join_column(translated_field, table_ref); - field_count= table_ref->field_translation_end - - table_ref->field_translation; + field_count= (uint)(table_ref->field_translation_end - + table_ref->field_translation); } else { From 1b478a7abab63aa10dc56b4f4fc7e8a5a8916fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 10 Oct 2017 10:28:54 +0300 Subject: [PATCH 19/34] MDEV-13311 Presence of old logs in 10.2.7 will corrupt restored instance (change in behavior) Mariabackup 10.2.7 would delete the redo log files after a successful --prepare operation. If the user is manually copying the prepared files instead of using the --copy-back option, it could happen that some old redo log file would be preserved in the restored location. These old redo log files could cause corruption of the restored data files when the server is started up. We prevent this scenario by creating a "poisoned" redo log file ib_logfile0 at the end of the --prepare step. The poisoning consists of simply truncating the file to an empty file. InnoDB will refuse to start up on an empty redo log file. copy_back(): Delete all redo log files in the target if the source file ib_logfile0 is empty. (Previously we did this if the source file is missing.) SRV_OPERATION_RESTORE_EXPORT: A new variant of SRV_OPERATION_RESTORE when the --export option is specified. In this mode, we will keep deleting all redo log files, instead of truncating the first one. delete_log_files(): Add a parameter for the first file to delete, to be passed as 0 or 1. innobase_start_or_create_for_mysql(): In mariabackup --prepare, tolerate an empty ib_logfile0 file. Otherwise, require the first redo log file to be longer than 4 blocks (2048 bytes). Unless --export was specified, truncate the first log file at the end of --prepare. --- extra/mariabackup/backup_copy.cc | 3 +- extra/mariabackup/xtrabackup.cc | 3 +- .../suite/innodb/r/log_file_size.result | 8 +++ mysql-test/suite/innodb/t/log_file_size.test | 25 ++++++-- .../mariabackup/xb_file_key_management.result | 1 + .../mariabackup/xb_file_key_management.test | 1 + storage/innobase/include/srv0srv.h | 6 +- storage/innobase/log/log0recv.cc | 12 ++-- storage/innobase/srv/srv0start.cc | 57 ++++++++++++++++--- storage/innobase/trx/trx0trx.cc | 1 + 10 files changed, 96 insertions(+), 21 deletions(-) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index 19cb768cd01..dfe482963a6 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -1707,7 +1707,8 @@ copy_back() if it exists. */ ds_data = ds_create(dst_dir, DS_TYPE_LOCAL); - if (!file_exists("ib_logfile0")) { + MY_STAT stat_arg; + if (!my_stat("ib_logfile0", &stat_arg, MYF(0)) || !stat_arg.st_size) { /* After completed --prepare, redo log files are redundant. We must delete any redo logs at the destination, so that the database will not jump to a different log sequence number diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 40736709a39..4b6d0d2cc55 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4793,7 +4793,8 @@ xtrabackup_prepare_func(char** argv) if (!ok) goto error_cleanup; } - srv_operation = SRV_OPERATION_RESTORE; + srv_operation = xtrabackup_export + ? SRV_OPERATION_RESTORE_EXPORT : SRV_OPERATION_RESTORE; if (innodb_init_param()) { goto error_cleanup; diff --git a/mysql-test/suite/innodb/r/log_file_size.result b/mysql-test/suite/innodb/r/log_file_size.result index b576061e74b..e049b34ad81 100644 --- a/mysql-test/suite/innodb/r/log_file_size.result +++ b/mysql-test/suite/innodb/r/log_file_size.result @@ -1,4 +1,12 @@ CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; +SELECT * FROM INFORMATION_SCHEMA.ENGINES +WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); +ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS +FOUND 1 /InnoDB: Log file .*ib_logfile0 size 0 is too small/ in mysqld.1.err +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK BEGIN; INSERT INTO t1 VALUES (42); SELECT * FROM t1; diff --git a/mysql-test/suite/innodb/t/log_file_size.test b/mysql-test/suite/innodb/t/log_file_size.test index 206444115fc..140198de4ab 100644 --- a/mysql-test/suite/innodb/t/log_file_size.test +++ b/mysql-test/suite/innodb/t/log_file_size.test @@ -23,14 +23,33 @@ call mtr.add_suppression("InnoDB: Log file .*ib_logfile[01].* size"); call mtr.add_suppression("InnoDB: Unable to open .*ib_logfile0. to check native AIO read support"); FLUSH TABLES; --enable_query_log +let MYSQLD_DATADIR= `select @@datadir`; +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; + +--source include/shutdown_mysqld.inc +--move_file $MYSQLD_DATADIR/ib_logfile0 $MYSQLD_DATADIR/ib_logfile.old +write_file $MYSQLD_DATADIR/ib_logfile0; +EOF +let $check_no_innodb=SELECT * FROM INFORMATION_SCHEMA.ENGINES +WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); --let $restart_parameters= --innodb-thread-concurrency=1 --innodb-log-file-size=1m --innodb-log-files-in-group=2 ---source include/restart_mysqld.inc +--source include/start_mysqld.inc + +eval $check_no_innodb; +--remove_file $MYSQLD_DATADIR/ib_logfile0 +--move_file $MYSQLD_DATADIR/ib_logfile.old $MYSQLD_DATADIR/ib_logfile.0 +--source include/shutdown_mysqld.inc +let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err; +let SEARCH_PATTERN= InnoDB: Log file .*ib_logfile0 size 0 is too small; +--source include/search_pattern_in_file.inc +--source include/start_mysqld.inc +CHECK TABLE t1; --let $restart_parameters= --innodb-thread-concurrency=100 --innodb-log-file-size=10M --innodb-log-files-in-group=2 --source include/restart_mysqld.inc -CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; BEGIN; INSERT INTO t1 VALUES (42); @@ -52,9 +71,7 @@ SELECT * FROM t1; INSERT INTO t1 VALUES (0),(123); -let MYSQLD_DATADIR= `select @@datadir`; let SEARCH_ABORT = NOT FOUND; -let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err; BEGIN; DELETE FROM t1 WHERE a>0; diff --git a/mysql-test/suite/mariabackup/xb_file_key_management.result b/mysql-test/suite/mariabackup/xb_file_key_management.result index 8972da32f8b..721d10a9d91 100644 --- a/mysql-test/suite/mariabackup/xb_file_key_management.result +++ b/mysql-test/suite/mariabackup/xb_file_key_management.result @@ -9,6 +9,7 @@ INSERT INTO t VALUES('foobar2'); # remove datadir # xtrabackup move back # restart server +ib_logfile0 SELECT * FROM t; c foobar1 diff --git a/mysql-test/suite/mariabackup/xb_file_key_management.test b/mysql-test/suite/mariabackup/xb_file_key_management.test index 3887a889aaa..2a176952053 100644 --- a/mysql-test/suite/mariabackup/xb_file_key_management.test +++ b/mysql-test/suite/mariabackup/xb_file_key_management.test @@ -24,6 +24,7 @@ exec $XTRABACKUP --prepare --target-dir=$targetdir; --enable_result_log --list_files $targetdir ib_logfile* +--cat_file $targetdir/ib_logfile0 SELECT * FROM t; DROP TABLE t; diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index a51520e881c..e24aa89f046 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -508,10 +508,12 @@ enum srv_operation_mode { SRV_OPERATION_NORMAL, /** Mariabackup taking a backup */ SRV_OPERATION_BACKUP, - /** Mariabackup restoring a backup */ + /** Mariabackup restoring a backup for subsequent --copy-back */ SRV_OPERATION_RESTORE, /** Mariabackup restoring the incremental part of a backup */ - SRV_OPERATION_RESTORE_DELTA + SRV_OPERATION_RESTORE_DELTA, + /** Mariabackup restoring a backup for subsequent --export */ + SRV_OPERATION_RESTORE_EXPORT }; /** Current mode of operation */ diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index fd0940b08df..a91b62d11d9 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1922,7 +1922,8 @@ void recv_apply_hashed_log_recs(bool last_batch) { ut_ad(srv_operation == SRV_OPERATION_NORMAL - || srv_operation == SRV_OPERATION_RESTORE); + || srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT); mutex_enter(&recv_sys->mutex); @@ -1941,7 +1942,8 @@ recv_apply_hashed_log_recs(bool last_batch) ut_ad(!last_batch == log_mutex_own()); recv_no_ibuf_operations = !last_batch - || srv_operation == SRV_OPERATION_RESTORE; + || srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT; ut_d(recv_no_log_write = recv_no_ibuf_operations); @@ -2960,7 +2962,8 @@ static dberr_t recv_init_missing_space(dberr_t err, const recv_spaces_t::const_iterator& i) { - if (srv_operation == SRV_OPERATION_RESTORE) { + if (srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT) { ib::warn() << "Tablespace " << i->first << " was not" " found at " << i->second.name << " when" " restoring a (partial?) backup. All redo log" @@ -3118,7 +3121,8 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) dberr_t err = DB_SUCCESS; ut_ad(srv_operation == SRV_OPERATION_NORMAL - || srv_operation == SRV_OPERATION_RESTORE); + || srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT); /* Initialize red-black tree for fast insertions into the flush_list during recovery process. */ diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 1002cc566fb..d6dd5805186 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -397,13 +397,14 @@ create_log_file( /** Delete all log files. @param[in,out] logfilename buffer for log file name @param[in] dirnamelen length of the directory path -@param[in] n_files number of files to delete */ +@param[in] n_files number of files to delete +@param[in] i first file to delete */ static void -delete_log_files(char* logfilename, size_t dirnamelen, unsigned n_files) +delete_log_files(char* logfilename, size_t dirnamelen, uint n_files, uint i=0) { /* Remove any old log files. */ - for (unsigned i = 0; i < n_files; i++) { + for (; i < n_files; i++) { sprintf(logfilename + dirnamelen, "ib_logfile%u", i); /* Ignore errors about non-existent files or files @@ -911,6 +912,7 @@ srv_undo_tablespaces_init(bool create_new_db) } /* fall through */ case SRV_OPERATION_RESTORE: + case SRV_OPERATION_RESTORE_EXPORT: ut_ad(!create_new_db); /* Check if any of the UNDO tablespace needs fix-up because @@ -1321,6 +1323,7 @@ srv_shutdown_all_bg_threads() break; case SRV_OPERATION_NORMAL: case SRV_OPERATION_RESTORE: + case SRV_OPERATION_RESTORE_EXPORT: if (!buf_page_cleaner_is_active && os_aio_all_slots_free()) { os_aio_wake_all_threads_at_shutdown(); @@ -1492,7 +1495,8 @@ innobase_start_or_create_for_mysql() unsigned i = 0; ut_ad(srv_operation == SRV_OPERATION_NORMAL - || srv_operation == SRV_OPERATION_RESTORE); + || srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT); if (srv_force_recovery == SRV_FORCE_NO_LOG_REDO) { srv_read_only_mode = true; @@ -1982,7 +1986,9 @@ innobase_start_or_create_for_mysql() if (err == DB_NOT_FOUND) { if (i == 0) { if (srv_operation - == SRV_OPERATION_RESTORE) { + == SRV_OPERATION_RESTORE + || srv_operation + == SRV_OPERATION_RESTORE_EXPORT) { return(DB_SUCCESS); } if (flushed_lsn @@ -2046,6 +2052,26 @@ innobase_start_or_create_for_mysql() } if (i == 0) { + if (size == 0 + && (srv_operation + == SRV_OPERATION_RESTORE + || srv_operation + == SRV_OPERATION_RESTORE_EXPORT)) { + /* Tolerate an empty ib_logfile0 + from a previous run of + mariabackup --prepare. */ + return(DB_SUCCESS); + } + /* The first log file must consist of + at least the following 512-byte pages: + header, checkpoint page 1, empty, + checkpoint page 2, redo log page(s) */ + if (size <= OS_FILE_LOG_BLOCK_SIZE * 4) { + ib::error() << "Log file " + << logfilename << " size " + << size << " is too small"; + return(srv_init_abort(DB_ERROR)); + } srv_log_file_size = size; } else if (size != srv_log_file_size) { @@ -2312,11 +2338,13 @@ files_checked: recv_recovery_from_checkpoint_finish(); - if (srv_operation == SRV_OPERATION_RESTORE) { + if (srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT) { /* After applying the redo log from SRV_OPERATION_BACKUP, flush the changes - to the data files and delete the log file. - No further change to InnoDB files is needed. */ + to the data files and truncate or delete the log. + Unless --export is specified, no further change to + InnoDB files is needed. */ ut_ad(!srv_force_recovery); ut_ad(srv_n_log_files_found <= 1); ut_ad(recv_no_log_write); @@ -2326,8 +2354,18 @@ files_checked: fil_close_log_files(true); log_group_close_all(); if (err == DB_SUCCESS) { + bool trunc = srv_operation + == SRV_OPERATION_RESTORE; + /* Delete subsequent log files. */ delete_log_files(logfilename, dirnamelen, - srv_n_log_files_found); + srv_n_log_files_found, trunc); + if (trunc) { + /* Truncate the first log file. */ + strcpy(logfilename + dirnamelen, + "ib_logfile0"); + FILE* f = fopen(logfilename, "w"); + fclose(f); + } } return(err); } @@ -2792,6 +2830,7 @@ innodb_shutdown() case SRV_OPERATION_BACKUP: case SRV_OPERATION_RESTORE: case SRV_OPERATION_RESTORE_DELTA: + case SRV_OPERATION_RESTORE_EXPORT: fil_close_all_files(); break; case SRV_OPERATION_NORMAL: diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 2408e4bdaf4..ffba8f314fb 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -620,6 +620,7 @@ trx_free_prepared( && trx->is_recovered && (!srv_was_started || srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT || srv_read_only_mode || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO))); ut_a(trx->magic_n == TRX_MAGIC_N); From f2a0fa8685a5bab0a13d5ac720a68eecf3541dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 10 Oct 2017 16:53:15 +0300 Subject: [PATCH 20/34] Fix test failure on galera.view caused by incorrect location of WSREP_TO_ISOLATION_BEGIN. --- sql/sql_view.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 6e58564262c..cdb65a79660 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -426,11 +426,12 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, if ((res= create_view_precheck(thd, tables, view, mode))) goto err; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) lex->link_first_table_back(view, link_to_local); view->open_type= OT_BASE_ONLY; + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + if (check_dependencies_in_with_clauses(lex->with_clauses_list)) { res= TRUE; From ac2ae901e8c50a0a8029f317a3cc63648e38a0fd Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Tue, 10 Oct 2017 23:56:13 +0530 Subject: [PATCH 21/34] MDEV-13974: Build failure in rocksdb/rdb_datadic.cc Added cstdlib librabry to rdb_datadic.h --- storage/rocksdb/rdb_datadic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/rocksdb/rdb_datadic.h b/storage/rocksdb/rdb_datadic.h index 9c7cd956eb3..9751ac06424 100644 --- a/storage/rocksdb/rdb_datadic.h +++ b/storage/rocksdb/rdb_datadic.h @@ -16,6 +16,7 @@ #pragma once /* C++ standard header files */ +#include #include #include #include From 4de344a8d7aba975912984623ae26b57b65e251b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 10 Oct 2017 19:04:54 +0300 Subject: [PATCH 22/34] Reapply a MySQL 5.6.23/5.7.10 Oracle Bug#20029625 fix that was inadvertently reverted in MariaDB 10.2.2 The fix https://github.com/mysql/mysql-server/commit/716f97e2714e70f35d2dc01f0125ed833c62b408 was inadvertently reverted in commit 2e814d4702d71a04388386a9f591d14a35980bfe "Merge InnoDB 5.7 from mysql-5.7.9". Reapply the fix, because the test of the bug would fail after merging MDEV-13838, which replaced an earlier incorrect bug fix with a correct one. --- storage/innobase/dict/dict0mem.cc | 61 +++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 230706976dc..bcaa5ae4a15 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -439,6 +439,9 @@ dict_mem_table_col_rename_low( ut_ad(from_len <= NAME_LEN); ut_ad(to_len <= NAME_LEN); + char from[NAME_LEN]; + strncpy(from, s, NAME_LEN); + if (from_len == to_len) { /* The easy case: simply replace the column name in table->col_names. */ @@ -523,14 +526,54 @@ dict_mem_table_col_rename_low( foreign = *it; - for (unsigned f = 0; f < foreign->n_fields; f++) { - /* These can point straight to - table->col_names, because the foreign key - constraints will be freed at the same time - when the table object is freed. */ - foreign->foreign_col_names[f] - = dict_index_get_nth_field( - foreign->foreign_index, f)->name; + if (foreign->foreign_index == NULL) { + /* We may go here when we set foreign_key_checks to 0, + and then try to rename a column and modify the + corresponding foreign key constraint. The index + would have been dropped, we have to find an equivalent + one */ + for (unsigned f = 0; f < foreign->n_fields; f++) { + if (strcmp(foreign->foreign_col_names[f], from) + == 0) { + + char** rc = const_cast( + foreign->foreign_col_names + + f); + + if (to_len <= strlen(*rc)) { + memcpy(*rc, to, to_len + 1); + } else { + *rc = static_cast( + mem_heap_dup( + foreign->heap, + to, + to_len + 1)); + } + } + } + + dict_index_t* new_index = dict_foreign_find_index( + foreign->foreign_table, NULL, + foreign->foreign_col_names, + foreign->n_fields, NULL, true, false, + NULL, NULL, NULL); + /* There must be an equivalent index in this case. */ + ut_ad(new_index != NULL); + + foreign->foreign_index = new_index; + + } else { + + for (unsigned f = 0; f < foreign->n_fields; f++) { + /* These can point straight to + table->col_names, because the foreign key + constraints will be freed at the same time + when the table object is freed. */ + foreign->foreign_col_names[f] + = dict_index_get_nth_field( + foreign->foreign_index, + f)->name; + } } } @@ -540,6 +583,8 @@ dict_mem_table_col_rename_low( foreign = *it; + ut_ad(foreign->referenced_index != NULL); + for (unsigned f = 0; f < foreign->n_fields; f++) { /* foreign->referenced_col_names[] need to be copies, because the constraint may become From daabb4d055a59247d5294ddee364f5c265bc37cd Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 11 Oct 2017 08:36:04 +0200 Subject: [PATCH 23/34] Fix truncation warnings in connect --- storage/connect/csort.cpp | 16 ++++++++-------- storage/connect/domdoc.cpp | 3 ++- storage/connect/filamap.cpp | 12 ++++++------ storage/connect/filamgz.cpp | 8 ++++---- storage/connect/filamtxt.cpp | 9 +++++---- storage/connect/filamzip.cpp | 4 ++-- storage/connect/fmdlex.c | 8 ++++---- storage/connect/macutil.cpp | 4 ++-- storage/connect/myconn.cpp | 2 +- storage/connect/odbconn.cpp | 2 +- storage/connect/plgdbutl.cpp | 2 +- storage/connect/tabfmt.cpp | 6 +++--- storage/connect/tabmac.cpp | 4 ++-- storage/connect/value.cpp | 4 ++-- storage/connect/xobject.cpp | 4 ++-- 15 files changed, 45 insertions(+), 43 deletions(-) diff --git a/storage/connect/csort.cpp b/storage/connect/csort.cpp index 13f325d8f3f..670131b8fd2 100644 --- a/storage/connect/csort.cpp +++ b/storage/connect/csort.cpp @@ -351,7 +351,7 @@ void CSORT::Qstx(int *base, int *max) zlo = zhi = cnm = 0; // Avoid warning message - lo = max - base; // Number of elements as longs + lo = (int)(max - base); // Number of elements as longs if (Dup) cnm = Cmpnum(lo); @@ -472,7 +472,7 @@ void CSORT::Qstx(int *base, int *max) i = him + 1; if (Pof) - Pof[him - Pex] = Pof[mid - Pex] = i - j; + Pof[him - Pex] = Pof[mid - Pex] = (int)(i - j); /*******************************************************************/ /* Look at sizes of the two partitions, do the smaller one first */ @@ -481,8 +481,8 @@ void CSORT::Qstx(int *base, int *max) /* But only repeat (recursively or by branching) if the partition */ /* is of at least size THRESH. */ /*******************************************************************/ - lo = j - base; - hi = max - i; + lo = (int)(j - base); + hi = (int)(max - i); if (Dup) { // Update progress information zlo = Cmpnum(lo); @@ -726,7 +726,7 @@ void CSORT::Qstc(int *base, int *max) zlo = zhi = cnm = 0; // Avoid warning message - lo = max - base; // Number of elements as longs + lo = (int)(max - base); // Number of elements as longs if (Dup) cnm = Cmpnum(lo); @@ -853,7 +853,7 @@ void CSORT::Qstc(int *base, int *max) /* the offset array values indicating break point and block size. */ /*******************************************************************/ if (Pof) - Pof[lt - Pex] = Pof[(jj - 1) - Pex] = jj - lt; + Pof[lt - Pex] = Pof[(jj - 1) - Pex] = (int)(jj - lt); /*******************************************************************/ /* Look at sizes of the two partitions, do the smaller one first */ @@ -862,8 +862,8 @@ void CSORT::Qstc(int *base, int *max) /* But only repeat (recursively or by branching) if the partition */ /* is of at least size THRESH. */ /*******************************************************************/ - lo = lt - base; - hi = gt - Swix; + lo = (int)(lt - base); + hi = (int)(gt - Swix); if (Dup) { // Update progress information zlo = Cmpnum(lo); diff --git a/storage/connect/domdoc.cpp b/storage/connect/domdoc.cpp index e24e10835c1..ba8eb829abd 100644 --- a/storage/connect/domdoc.cpp +++ b/storage/connect/domdoc.cpp @@ -13,6 +13,7 @@ #elif defined(MSX4) #import "msxml4.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ?? #elif defined(MSX6) +#pragma warning(suppress : 4192) #import "msxml6.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ?? #else // MSX4 #error MSX? is not defined @@ -540,7 +541,7 @@ PXNODE DOMNODE::AddChildNode(PGLOBAL g, PCSZ name, PXNODE np) // If name has the format m[n] only m is taken as node name if ((p = strchr(name, '['))) - pn = BufAlloc(g, name, p - name); + pn = BufAlloc(g, name, (int)(p - name)); else pn = name; diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp index 84dff422db7..67481136d81 100644 --- a/storage/connect/filamap.cpp +++ b/storage/connect/filamap.cpp @@ -247,7 +247,7 @@ int MAPFAM::GetRowID(void) /***********************************************************************/ int MAPFAM::GetPos(void) { - return Fpos - Memory; + return (int)(Fpos - Memory); } // end of GetPos /***********************************************************************/ @@ -255,7 +255,7 @@ int MAPFAM::GetPos(void) /***********************************************************************/ int MAPFAM::GetNextPos(void) { - return Mempos - Memory; + return (int)(Mempos - Memory); } // end of GetNextPos /***********************************************************************/ @@ -368,7 +368,7 @@ int MAPFAM::ReadBuffer(PGLOBAL g) } // endif Mempos // Set caller line buffer - len = (Mempos - Fpos) - n; + len = (int)(Mempos - Fpos) - n; // Don't rely on ENDING setting if (len > 0 && *(Mempos - 2) == '\r') @@ -428,7 +428,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) /* not required here, just setting of future Spos and Tpos. */ /*******************************************************************/ Tpos = Spos = Fpos; - } else if ((n = Fpos - Spos) > 0) { + } else if ((n = (int)(Fpos - Spos)) > 0) { /*******************************************************************/ /* Non consecutive line to delete. Move intermediate lines. */ /*******************************************************************/ @@ -461,7 +461,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) /*****************************************************************/ /* Remove extra records. */ /*****************************************************************/ - n = Tpos - Memory; + n = (int)(Tpos - Memory); #if defined(__WIN__) DWORD drc = SetFilePointer(fp->Handle, n, NULL, FILE_BEGIN); @@ -627,7 +627,7 @@ int MBKFAM::ReadBuffer(PGLOBAL g) break; // Set caller line buffer - len = (Mempos - Fpos) - Ending; + len = (int)(Mempos - Fpos) - Ending; memcpy(Tdbp->GetLine(), Fpos, len); Tdbp->GetLine()[len] = '\0'; return RC_OK; diff --git a/storage/connect/filamgz.cpp b/storage/connect/filamgz.cpp index df366ef15f9..3078935e8a4 100644 --- a/storage/connect/filamgz.cpp +++ b/storage/connect/filamgz.cpp @@ -537,7 +537,7 @@ int ZBKFAM::ReadBuffer(PGLOBAL g) while (*NxtLine++ != '\n') ; // Set caller line buffer - n = NxtLine - CurLine - Ending; + n = (int)(NxtLine - CurLine - Ending); memcpy(Tdbp->GetLine(), CurLine, n); Tdbp->GetLine()[n] = '\0'; return RC_OK; @@ -588,7 +588,7 @@ int ZBKFAM::ReadBuffer(PGLOBAL g) for (NxtLine = CurLine; *NxtLine++ != '\n';) ; // Set caller line buffer - n = NxtLine - CurLine - Ending; + n = (int)(NxtLine - CurLine - Ending); memcpy(Tdbp->GetLine(), CurLine, n); Tdbp->GetLine()[n] = '\0'; Rbuf = (CurBlk == Block - 1) ? Last : Nrec; @@ -1087,7 +1087,7 @@ bool ZLBFAM::SetPos(PGLOBAL g, int pos __attribute__((unused))) /***********************************************************************/ int ZLBFAM::ReadBuffer(PGLOBAL g) { - int n; + size_t n; void *rdbuf; /*********************************************************************/ @@ -1299,7 +1299,7 @@ int ZLBFAM::WriteBuffer(PGLOBAL g) else NxtLine = CurLine + Lrecl; - BlkLen = NxtLine - To_Buf; + BlkLen = (int)(NxtLine - To_Buf); if (WriteCompressedBuffer(g)) { Closing = TRUE; // To tell CloseDB about a Write error diff --git a/storage/connect/filamtxt.cpp b/storage/connect/filamtxt.cpp index c456ee9e9b7..12727b66335 100644 --- a/storage/connect/filamtxt.cpp +++ b/storage/connect/filamtxt.cpp @@ -1351,7 +1351,7 @@ int BLKFAM::GetPos(void) /***********************************************************************/ int BLKFAM::GetNextPos(void) { - return Fpos + NxtLine - CurLine; + return (int)(Fpos + NxtLine - CurLine); } // end of GetNextPos /***********************************************************************/ @@ -1396,7 +1396,8 @@ int BLKFAM::SkipRecord(PGLOBAL, bool header) /***********************************************************************/ int BLKFAM::ReadBuffer(PGLOBAL g) { - int i, n, rc = RC_OK; + int i, rc = RC_OK; + size_t n; /*********************************************************************/ /* Sequential reading when Placed is not true. */ @@ -1497,7 +1498,7 @@ int BLKFAM::ReadBuffer(PGLOBAL g) fin: // Store the current record file position for Delete and Update - Fpos = BlkPos[CurBlk] + CurLine - To_Buf; + Fpos = (int)(BlkPos[CurBlk] + CurLine - To_Buf); return rc; } // end of ReadBuffer @@ -1524,7 +1525,7 @@ int BLKFAM::WriteBuffer(PGLOBAL g) // Now start the writing process. NxtLine = CurLine + strlen(CurLine); - BlkLen = NxtLine - To_Buf; + BlkLen = (int)(NxtLine - To_Buf); if (fwrite(To_Buf, 1, BlkLen, Stream) != (size_t)BlkLen) { sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno)); diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index dfd9343af76..f94362a3d87 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -748,7 +748,7 @@ UNZFAM::UNZFAM(PUNZFAM txfp) : MAPFAM(txfp) /***********************************************************************/ int UNZFAM::GetFileLength(PGLOBAL g) { - int len = (zutp && zutp->entryopen) ? Top - Memory + int len = (zutp && zutp->entryopen) ? (int)(Top - Memory) : TXTFAM::GetFileLength(g) * 3; if (trace) @@ -1088,7 +1088,7 @@ int ZIPFAM::WriteBuffer(PGLOBAL g) // Prepare to write the new line strcat(strcpy(To_Buf, Tdbp->GetLine()), (Bin) ? CrLf : "\n"); - len = strchr(To_Buf, '\n') - To_Buf + 1; + len = (int)(strchr(To_Buf, '\n') - To_Buf + 1); return zutp->writeEntry(g, To_Buf, len); } // end of WriteBuffer diff --git a/storage/connect/fmdlex.c b/storage/connect/fmdlex.c index ef4f7bfc65a..4bf075acf42 100644 --- a/storage/connect/fmdlex.c +++ b/storage/connect/fmdlex.c @@ -283,7 +283,7 @@ static void yy_fatal_error YY_PROTO(( const char msg[] )); */ #define YY_DO_BEFORE_ACTION \ yytext_ptr = yy_bp; \ - yyleng = yy_cp - yy_bp; \ + yyleng = (int)(yy_cp - yy_bp); \ yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yy_c_buf_p = yy_cp; @@ -695,7 +695,7 @@ case YY_STATE_EOF(dqt): case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = yy_cp - yytext_ptr - 1; + int yy_amount_of_matched_text = (int)(yy_cp - yytext_ptr - 1); /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yy_hold_char; @@ -862,7 +862,7 @@ static int yy_get_next_buffer() /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = yy_c_buf_p - yytext_ptr; + number_to_move = (int)(yy_c_buf_p - yytext_ptr); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); @@ -888,7 +888,7 @@ static int yy_get_next_buffer() /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = yy_current_buffer; - int yy_c_buf_p_offset = yy_c_buf_p - b->yy_ch_buf; + int yy_c_buf_p_offset = (int)(yy_c_buf_p - b->yy_ch_buf); b->yy_buf_size *= 2; b->yy_ch_buf = (char *) diff --git a/storage/connect/macutil.cpp b/storage/connect/macutil.cpp index b9600bdac2e..f95f3adcc6e 100644 --- a/storage/connect/macutil.cpp +++ b/storage/connect/macutil.cpp @@ -230,13 +230,13 @@ bool MACINFO::GetOneInfo(PGLOBAL g, int flag, void *v, int lv) case 11: // Description if ((p = strstr(Curp->Description, " - Packet Scheduler Miniport"))) { strncpy(buf, Curp->Description, p - Curp->Description); - i = p - Curp->Description; + i = (int)(p - Curp->Description); strncpy(buf, Curp->Description, i); buf[i] = 0; p = buf; } else if ((p = strstr(Curp->Description, " - Miniport d'ordonnancement de paquets"))) { - i = p - Curp->Description; + i = (int)(p - Curp->Description); strncpy(buf, Curp->Description, i); buf[i] = 0; p = buf; diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index 08bb24e14df..28e6f076e77 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -248,7 +248,7 @@ PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db, while (true) { p2 = strchr(p1, '\''); - len = MY_MAX(len, p2 - p1); + len = MY_MAX(len, (int)(p2 - p1)); if (*++p2 != ',') break; p1 = p2 + 2; } // endwhile diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index 70a0a6a1450..3b0cb562672 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -2427,7 +2427,7 @@ int ODBConn::GetCatInfo(CATPARM *cap) else if (vlen[n] == SQL_NULL_DATA) pval[n]->SetNull(true); else if (crp->Type == TYPE_STRING/* && vlen[n] != SQL_NULL_DATA*/) - pval[n]->SetValue_char(pbuf[n], vlen[n]); + pval[n]->SetValue_char(pbuf[n], (int)vlen[n]); else pval[n]->SetNull(false); diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 25da3162516..e46d260203e 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -540,7 +540,7 @@ bool EvalLikePattern(LPCSTR sp, LPCSTR tp) { LPSTR p; char c; - int n; + ssize_t n; bool b, t = false; if (trace) diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index 516601a5eb4..f616f24d16b 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -934,7 +934,7 @@ int TDBCSV::ReadBuffer(PGLOBAL g) if (p) { //len = p++ - p2; - len = p - p2 - 1;; + len = (int)(p - p2 - 1); // if (Sep != ' ') // for (; *p == ' '; p++) ; // Skip blanks @@ -978,7 +978,7 @@ int TDBCSV::ReadBuffer(PGLOBAL g) return RC_NF; } else if ((p = strchr(p2, Sep))) - len = p - p2; + len = (int)(p - p2); else if (i == Fields - 1) len = strlen(p2); else if (Accept && Maxerr == 0) { @@ -996,7 +996,7 @@ int TDBCSV::ReadBuffer(PGLOBAL g) } else len = 0; - Offset[i] = p2 - To_Line; + Offset[i] = (int)(p2 - To_Line); if (Mode != MODE_UPDATE) Fldlen[i] = len; diff --git a/storage/connect/tabmac.cpp b/storage/connect/tabmac.cpp index a28b5d7108c..8260ab65391 100644 --- a/storage/connect/tabmac.cpp +++ b/storage/connect/tabmac.cpp @@ -367,13 +367,13 @@ void MACCOL::ReadColumn(PGLOBAL g) case 11: // Description if ((p = strstr(adp->Description, " - Packet Scheduler Miniport"))) { strncpy(buf, adp->Description, p - adp->Description); - i = p - adp->Description; + i = (int)(p - adp->Description); strncpy(buf, adp->Description, i); buf[i] = 0; p = buf; } else if ((p = strstr(adp->Description, " - Miniport d'ordonnancement de paquets"))) { - i = p - adp->Description; + i = (int)(p - adp->Description); strncpy(buf, adp->Description, i); buf[i] = 0; p = buf; diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index a80da808548..eae72984ca6 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -1738,7 +1738,7 @@ DECVAL::DECVAL(PSZ s) : TYPVAL(s) if (s) { char *p = strchr(Strp, '.'); - Prec = (p) ? Len - (p - Strp) : 0; + Prec = (p) ? (int)(Len - (p - Strp)) : 0; } // endif s Type = TYPE_DECIM; @@ -2647,7 +2647,7 @@ bool DTVAL::SetValue_char(const char *p, int n) // Trim trailing blanks for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--); - if ((rc = (n = p2 - p + 1) > Len)) + if ((rc = (n = (int)(p2 - p + 1)) > Len)) n = Len; memcpy(Sdate, p, n); diff --git a/storage/connect/xobject.cpp b/storage/connect/xobject.cpp index 85af3779701..c595ce5d6c4 100644 --- a/storage/connect/xobject.cpp +++ b/storage/connect/xobject.cpp @@ -204,7 +204,7 @@ STRING::STRING(PGLOBAL g, uint n, PCSZ str) *Strp = 0; Next = GetNext(); - Size = Next - Strp; + Size = (int)(Next - Strp); Trc = false; } else { // This should normally never happen @@ -239,7 +239,7 @@ char *STRING::Realloc(uint len) p = Strp; Next = GetNext(); - Size = Next - p; + Size = (int)(Next - p); return p; } // end of Realloc From 93690b96e2eb8b9717222cea1e2097d625cb6f50 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 11 Oct 2017 08:44:24 +0200 Subject: [PATCH 24/34] Fix warnings in Win64 --- sql/sql_admin.cc | 3 ++- unittest/mysys/ma_dyncol-t.c | 2 +- unittest/mysys/my_getopt-t.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index fcbcd5d31bf..dd3c2694202 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -392,8 +392,9 @@ static bool open_only_one_table(THD* thd, TABLE_LIST* table, open_error= (thd->open_temporary_tables(table) || open_and_lock_tables(thd, table, TRUE, 0)); } - +#ifndef DBUG_OFF dbug_err: +#endif thd->prepare_derived_at_open= FALSE; diff --git a/unittest/mysys/ma_dyncol-t.c b/unittest/mysys/ma_dyncol-t.c index 3b43c10a6a8..124f16e15be 100644 --- a/unittest/mysys/ma_dyncol-t.c +++ b/unittest/mysys/ma_dyncol-t.c @@ -124,7 +124,7 @@ void test_value_single_double(double num, const char *name) if (mariadb_dyncol_get_num(&str, 1, &res)) goto err; rc= (res.type == DYN_COL_DOUBLE) && (res.x.double_value == num); - num= res.x.ulong_value; + num= res.x.double_value; err: ok(rc, "%s - %lf", name, num); /* cleanup */ diff --git a/unittest/mysys/my_getopt-t.c b/unittest/mysys/my_getopt-t.c index 39814d76690..3e16d79424e 100644 --- a/unittest/mysys/my_getopt-t.c +++ b/unittest/mysys/my_getopt-t.c @@ -72,7 +72,7 @@ void run(const char *arg, ...) arg= va_arg(ap, char*); } va_end(ap); - arg_c= arg_v - arg_s; + arg_c= (int)(arg_v - arg_s); arg_v= arg_s; res= handle_options(&arg_c, &arg_v, mopts_options, 0); } From dd85ec6f28b9b5f94188e4a1b907e3a17d6b647c Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 11 Oct 2017 08:45:59 +0200 Subject: [PATCH 25/34] Update AWS C++ SDK version This fixes some truncation warnings on Win64 --- plugin/aws_key_management/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt index 913bd8b16ed..aa93fc3aa03 100644 --- a/plugin/aws_key_management/CMakeLists.txt +++ b/plugin/aws_key_management/CMakeLists.txt @@ -117,7 +117,7 @@ ELSE() IF(CMAKE_VERSION LESS "3.0") SET(GIT_TAG "1.0.8") ELSE() - SET(GIT_TAG "1.1.27") + SET(GIT_TAG "1.2.11") ENDIF() SET(AWS_SDK_PATCH_COMMAND ) From fe0d2e1a2b8069b0d8f0560aacb2cc9543b3951b Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 11 Oct 2017 11:57:26 +0400 Subject: [PATCH 26/34] MDEV-13923 Assertion `!is_set() || (m_status == DA_OK_BULK && is_bulk_op())' failed upon altering table with geometry field. Check for the validity of the DEFAULT value for the geometry field. --- mysql-test/r/gis2.result | 24 ++++++++++++++++++++++++ mysql-test/t/gis2.test | 28 ++++++++++++++++++++++++++++ sql/item_geofunc.cc | 2 +- sql/unireg.cc | 7 ++++++- 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/gis2.result b/mysql-test/r/gis2.result index 214431e1d2d..2d5ae9abf73 100644 --- a/mysql-test/r/gis2.result +++ b/mysql-test/r/gis2.result @@ -12,3 +12,27 @@ WHERE ST_Contains(point_data, GeomFromText('Point(38.0248492 23.8512726)')); id 2 DROP TABLE t1; +create table t1 (p point default "qwer"); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +create table t1 (p point default 0); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +create table t1 (p point not null default st_geometryfromtext('point 0)')); +ERROR 42000: Invalid default value for 'p' +create table t1 (p point not null default st_geometryfromtext('point(0 0)')); +insert into t1 values(default); +select st_astext(p) from t1; +st_astext(p) +POINT(0 0) +drop table t1; +create table t1 (p point not null default if(unix_timestamp()>10,POINT(1,1),0)); +set timestamp=10; +insert into t1 values(default); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +drop table t1; +SET timestamp=default; +create table t1 (p point not null default if(unix_timestamp()>10,POINT(1,1),0)); +set timestamp=10; +alter table t1 add column i int; +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +drop table t1; +SET timestamp=default; diff --git a/mysql-test/t/gis2.test b/mysql-test/t/gis2.test index b734ab19ecd..8ec11d1dcfa 100644 --- a/mysql-test/t/gis2.test +++ b/mysql-test/t/gis2.test @@ -15,3 +15,31 @@ SELECT id FROM t1 WHERE ST_Contains(point_data, GeomFromText('Point(38.0248492 23.8512726)')); DROP TABLE t1; +# +# MDEV-13923 Assertion `!is_set() || (m_status == DA_OK_BULK && is_bulk_op())' failed upon altering table with geometry field +# +--error ER_CANT_CREATE_GEOMETRY_OBJECT +create table t1 (p point default "qwer"); +--error ER_CANT_CREATE_GEOMETRY_OBJECT +create table t1 (p point default 0); +--error ER_INVALID_DEFAULT +create table t1 (p point not null default st_geometryfromtext('point 0)')); +create table t1 (p point not null default st_geometryfromtext('point(0 0)')); +insert into t1 values(default); +select st_astext(p) from t1; +drop table t1; + +create table t1 (p point not null default if(unix_timestamp()>10,POINT(1,1),0)); +set timestamp=10; +--error ER_CANT_CREATE_GEOMETRY_OBJECT +insert into t1 values(default); +drop table t1; +SET timestamp=default; + +create table t1 (p point not null default if(unix_timestamp()>10,POINT(1,1),0)); +set timestamp=10; +--error ER_CANT_CREATE_GEOMETRY_OBJECT +alter table t1 add column i int; +drop table t1; +SET timestamp=default; + diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index a271e481814..1fa6b52cf96 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -75,9 +75,9 @@ String *Item_func_geometry_from_text::val_str(String *str) srid= (uint32)args[1]->val_int(); str->set_charset(&my_charset_bin); + str->length(0); if (str->reserve(SRID_SIZE, 512)) return 0; - str->length(0); str->q_append(srid); if ((null_value= !Geometry::create_from_wkt(&buffer, &trs, str, 0))) return 0; diff --git a/sql/unireg.cc b/sql/unireg.cc index 06151d9318b..899b612bd89 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -979,13 +979,17 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options, null_count+= field->length & 7; if (field->default_value && !field->default_value->flags && - !(field->flags & BLOB_FLAG)) + (!(field->flags & BLOB_FLAG) || field->sql_type == MYSQL_TYPE_GEOMETRY)) { Item *expr= field->default_value->expr; + int res= !expr->fixed && // may be already fixed if ALTER TABLE expr->fix_fields(thd, &expr); if (!res) res= expr->save_in_field(regfield, 1); + if (!res && (field->flags & BLOB_FLAG)) + regfield->reset(); + /* If not ok or warning of level 'note' */ if (res != 0 && res != 3) { @@ -994,6 +998,7 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options, delete regfield; //To avoid memory leak goto err; } + delete regfield; //To avoid memory leak } else if (regfield->real_type() == MYSQL_TYPE_ENUM && (field->flags & NOT_NULL_FLAG)) From 8e255b98ab73f51b79e1a9c2cccc8cd84bdf53d0 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 11 Oct 2017 12:21:40 +0400 Subject: [PATCH 27/34] MDEV-13923 Assertion `!is_set() || (m_status == DA_OK_BULK && is_bulk_op())' failed upon altering table with geometry field. Tests added. --- .../innodb_gis/r/alter_spatial_index.result | 16 +++++++++++++++ .../innodb_gis/t/alter_spatial_index.test | 20 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/mysql-test/suite/innodb_gis/r/alter_spatial_index.result b/mysql-test/suite/innodb_gis/r/alter_spatial_index.result index 5d6e5787d8c..e101c6142db 100644 --- a/mysql-test/suite/innodb_gis/r/alter_spatial_index.result +++ b/mysql-test/suite/innodb_gis/r/alter_spatial_index.result @@ -740,3 +740,19 @@ ALTER TABLE t1 ADD SPATIAL INDEX(p); ALTER TABLE t1 FORCE, LOCK=NONE; ERROR 0A000: LOCK=NONE is not supported. Reason: Do not support online operation on table with GIS index. Try LOCK=SHARED DROP TABLE t1; +create table t1 (p point not null default if(unix_timestamp()>10,POINT(1,1),0)) ENGINE=innodb; +set timestamp=10; +insert into t1 values(default); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +drop table t1; +SET timestamp=default; +create table t1 (p point not null default if(unix_timestamp()>10,POINT(1,1),0)) ENGINE=innodb; +set timestamp=10; +alter table t1 add column i int; +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +drop table t1; +SET timestamp=default; +CREATE OR REPLACE TABLE t1 (a INT) ENGINE=InnoDB; +ALTER TABLE t1 ADD COLUMN b POINT DEFAULT '0'; +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_gis/t/alter_spatial_index.test b/mysql-test/suite/innodb_gis/t/alter_spatial_index.test index f02c2f9cd1a..c4cd100c7e3 100644 --- a/mysql-test/suite/innodb_gis/t/alter_spatial_index.test +++ b/mysql-test/suite/innodb_gis/t/alter_spatial_index.test @@ -739,3 +739,23 @@ ALTER TABLE t1 ADD SPATIAL INDEX(p); --error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON ALTER TABLE t1 FORCE, LOCK=NONE; DROP TABLE t1; + +create table t1 (p point not null default if(unix_timestamp()>10,POINT(1,1),0)) ENGINE=innodb; +set timestamp=10; +--error ER_CANT_CREATE_GEOMETRY_OBJECT +insert into t1 values(default); +drop table t1; +SET timestamp=default; + +create table t1 (p point not null default if(unix_timestamp()>10,POINT(1,1),0)) ENGINE=innodb; +set timestamp=10; +--error ER_CANT_CREATE_GEOMETRY_OBJECT +alter table t1 add column i int; +drop table t1; +SET timestamp=default; + +CREATE OR REPLACE TABLE t1 (a INT) ENGINE=InnoDB; +--error ER_CANT_CREATE_GEOMETRY_OBJECT +ALTER TABLE t1 ADD COLUMN b POINT DEFAULT '0'; +DROP TABLE t1; + From a0df2693a29e7a7387773cdb9d068738c1d66920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 11 Oct 2017 11:41:31 +0300 Subject: [PATCH 28/34] Remove an unused parameter btr_store_big_rec_extern_fields(): Remove the unused parameter 'upd' that was added in https://github.com/mysql/mysql-server/commit/ce0a1e85e24e48b8171f767b44330d and merged to MariaDB 10.2.2 in commit 2e814d4702d71a04388386a9f591d14a35980bfe. --- storage/innobase/btr/btr0bulk.cc | 3 +-- storage/innobase/btr/btr0cur.cc | 1 - storage/innobase/include/btr0cur.h | 1 - storage/innobase/row/row0ins.cc | 4 ++-- storage/innobase/row/row0log.cc | 2 +- storage/innobase/row/row0upd.cc | 3 +-- 6 files changed, 5 insertions(+), 9 deletions(-) diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index 139e3116d06..5fae57fe2d4 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -564,8 +564,7 @@ PageBulk::storeExt( page_cur->block = m_block; dberr_t err = btr_store_big_rec_extern_fields( - &btr_pcur, NULL, offsets, big_rec, m_mtr, - BTR_STORE_INSERT_BULK); + &btr_pcur, offsets, big_rec, m_mtr, BTR_STORE_INSERT_BULK); ut_ad(page_offset(m_cur_rec) == page_offset(page_cur->rec)); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index bb13b6a71d3..4bb87cfaafb 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -6647,7 +6647,6 @@ btr_store_big_rec_extern_fields( btr_pcur_t* pcur, /*!< in/out: a persistent cursor. if btr_mtr is restarted, then this can be repositioned. */ - const upd_t* upd, /*!< in: update vector */ ulint* offsets, /*!< in/out: rec_get_offsets() on pcur. the "external storage" flags in offsets will correctly correspond diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 3a98280082f..d346a047eac 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -656,7 +656,6 @@ btr_store_big_rec_extern_fields( btr_pcur_t* pcur, /*!< in/out: a persistent cursor. if btr_mtr is restarted, then this can be repositioned. */ - const upd_t* upd, /*!< in: update vector */ ulint* offsets, /*!< in/out: rec_get_offsets() on pcur. the "external storage" flags in offsets will correctly correspond diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 49822acee3c..df14e9f8123 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -398,7 +398,7 @@ row_ins_clust_index_entry_by_modify( DEBUG_SYNC_C("before_row_ins_upd_extern"); err = btr_store_big_rec_extern_fields( - pcur, update, *offsets, big_rec, mtr, + pcur, *offsets, big_rec, mtr, BTR_STORE_INSERT_UPDATE); DEBUG_SYNC_C("after_row_ins_upd_extern"); dtuple_big_rec_free(big_rec); @@ -2502,7 +2502,7 @@ row_ins_index_entry_big_rec( DEBUG_SYNC_C_IF_THD(thd, "before_row_ins_extern"); error = btr_store_big_rec_extern_fields( - &pcur, 0, offsets, big_rec, &mtr, BTR_STORE_INSERT); + &pcur, offsets, big_rec, &mtr, BTR_STORE_INSERT); DEBUG_SYNC_C_IF_THD(thd, "after_row_ins_extern"); if (error == DB_SUCCESS diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 747959fcde5..3fc7deab4ae 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -2307,7 +2307,7 @@ func_exit_committed: if (big_rec) { if (error == DB_SUCCESS) { error = btr_store_big_rec_extern_fields( - &pcur, update, cur_offsets, big_rec, &mtr, + &pcur, cur_offsets, big_rec, &mtr, BTR_STORE_UPDATE); } diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index ca21549b9d8..3cc5a242fe4 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -2895,8 +2895,7 @@ row_upd_clust_rec( DEBUG_SYNC_C("before_row_upd_extern"); err = btr_store_big_rec_extern_fields( - pcur, node->update, offsets, big_rec, mtr, - BTR_STORE_UPDATE); + pcur, offsets, big_rec, mtr, BTR_STORE_UPDATE); DEBUG_SYNC_C("after_row_upd_extern"); } From 18a979df6ffea027ae39da9a0923fde7ae552464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 11 Oct 2017 11:52:25 +0300 Subject: [PATCH 29/34] Fix a warning about unused variable fil_ibd_create(): commit b731a5bcf2a0c86b6e31e4a99e3c632bb39a9c53 introduced a variable that was unused outside Windows. Use it on all platforms. --- storage/innobase/fil/fil0fil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index b8387f64861..f90238ffafb 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -3721,7 +3721,7 @@ fil_ibd_create( return(DB_ERROR); } - bool is_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(flags); + const bool is_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(flags); #ifdef _WIN32 if (is_compressed) { @@ -3729,10 +3729,9 @@ fil_ibd_create( } #endif - success = os_file_set_size(path, file, - os_offset_t(size)*UNIV_PAGE_SIZE, - FSP_FLAGS_HAS_PAGE_COMPRESSION(flags)); - + success = os_file_set_size( + path, file, + os_offset_t(size) << UNIV_PAGE_SIZE_SHIFT, is_compressed); if (!success) { os_file_close(file); From f9066dc347499ea2fd25f21def4b377a7037760a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 10 Oct 2017 21:49:09 +0200 Subject: [PATCH 30/34] MDEV-14023 10.1 InnoDB tables with virtual columns cannot be accessed in 10.2 in 10.1 innodb was basically ignoring virtual columns. In particular, information about them was not stored in system tables. To make 10.1 table usable in 10.2 it needs to be rebuilt to have virtual colunm metadata properly recreated. See also a followup: MDEV-14046 Allow ALGORITHM=INPLACE for 10.1 tables that contain virtual columns --- storage/innobase/handler/handler0alter.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 084fc807553..61e9c29107a 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -570,6 +570,13 @@ ha_innobase::check_if_supported_inplace_alter( { DBUG_ENTER("check_if_supported_inplace_alter"); + /* Before 10.2.2 information about virtual columns was not stored in + system tables. We need to do a full alter to rebuild proper 10.2.2+ + metadata with the information about virtual columns */ + if (table->s->mysql_version < 100202 && table->s->virtual_fields) { + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + } + if (high_level_read_only || srv_sys_space.created_new_raw() || srv_force_recovery) { From 3062445a64ff50c7a29493356a3454777d4dd595 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 11 Oct 2017 18:13:44 +0400 Subject: [PATCH 31/34] MDEV-14038 ALTER TABLE does not exit on error with InnoDB + bad default function Changing Field::set_default from void to int. It now uses the same return value notation with Field::store*() and Item::save_in_field(). --- mysql-test/suite/innodb/r/innodb-alter.result | 30 +++++++++++++++++++ .../innodb/r/innodb-online-alter-gis.result | 10 +++++++ mysql-test/suite/innodb/t/innodb-alter.test | 28 +++++++++++++++++ .../innodb/t/innodb-online-alter-gis.test | 10 +++++++ sql/field.cc | 11 +++---- sql/field.h | 4 +-- storage/innobase/handler/handler0alter.cc | 11 +++++-- 7 files changed, 95 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-alter.result b/mysql-test/suite/innodb/r/innodb-alter.result index aa78f55c78f..b06c6060375 100644 --- a/mysql-test/suite/innodb/r/innodb-alter.result +++ b/mysql-test/suite/innodb/r/innodb-alter.result @@ -857,3 +857,33 @@ DROP TABLE dest_db.t1; DROP TABLE source_db.t1; DROP DATABASE source_db; DROP DATABASE dest_db; +USE test; +# +# MDEV-14038 ALTER TABLE does not exit on error with InnoDB + bad default function +# +CREATE TABLE t1 (a INT NOT NULL DEFAULT 0) ENGINE=InnoDB; +iNSERT INTO t1 VALUES (10); +ALTER TABLE t1 ADD b TINYINT NOT NULL DEFAULT if(unix_timestamp()>1,1000,0); +ERROR 22003: Out of range value for column 'b' at row 1 +SELECT * FROM t1; +a +10 +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL DEFAULT 0) ENGINE=InnoDB; +iNSERT INTO t1 VALUES (10); +ALTER TABLE t1 ADD b DATE NOT NULL DEFAULT if(unix_timestamp()>1,TIMESTAMP'2001-01-01 10:20:30',0); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +SELECT * FROM t1; +a b +10 2001-01-01 +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL DEFAULT 0) ENGINE=InnoDB; +iNSERT INTO t1 VALUES (10); +ALTER TABLE t1 ADD b TIME NOT NULL DEFAULT if(unix_timestamp()>1,TIMESTAMP'2001-01-01 10:20:30',0); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +SELECT * FROM t1; +a b +10 10:20:30 +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/innodb-online-alter-gis.result b/mysql-test/suite/innodb/r/innodb-online-alter-gis.result index c7daac48e48..79c0f2386aa 100644 --- a/mysql-test/suite/innodb/r/innodb-online-alter-gis.result +++ b/mysql-test/suite/innodb/r/innodb-online-alter-gis.result @@ -37,3 +37,13 @@ Level Code Message show errors; Level Code Message drop table t1; +# +# MDEV-14038 ALTER TABLE does not exit on error with InnoDB + bad default function +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +ALTER TABLE t1 ADD COLUMN b LINESTRING DEFAULT POINT(1,1); +ERROR 22007: Incorrect LINESTRING value: 'POINT' for column 'b' at row 1 +DESCRIBE t1; +Field Type Null Key Default Extra +a int(11) YES NULL +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-alter.test b/mysql-test/suite/innodb/t/innodb-alter.test index 5e681f96b4a..d936dcad15c 100644 --- a/mysql-test/suite/innodb/t/innodb-alter.test +++ b/mysql-test/suite/innodb/t/innodb-alter.test @@ -494,6 +494,34 @@ eval ALTER TABLE $source_db.t1 DROP INDEX index2, algorithm=inplace; eval DROP TABLE $source_db.t1; eval DROP DATABASE $source_db; eval DROP DATABASE $dest_db; +USE test; +--echo # +--echo # MDEV-14038 ALTER TABLE does not exit on error with InnoDB + bad default function +--echo # +CREATE TABLE t1 (a INT NOT NULL DEFAULT 0) ENGINE=InnoDB; +iNSERT INTO t1 VALUES (10); +--error ER_WARN_DATA_OUT_OF_RANGE +ALTER TABLE t1 ADD b TINYINT NOT NULL DEFAULT if(unix_timestamp()>1,1000,0); +SELECT * FROM t1; +DROP TABLE t1; + +# DATETIME-to-DATE truncation is OK +CREATE TABLE t1 (a INT NOT NULL DEFAULT 0) ENGINE=InnoDB; +iNSERT INTO t1 VALUES (10); +--enable_info +ALTER TABLE t1 ADD b DATE NOT NULL DEFAULT if(unix_timestamp()>1,TIMESTAMP'2001-01-01 10:20:30',0); +--disable_info +SELECT * FROM t1; +DROP TABLE t1; + +# DATETIME-to-TIME truncation is OK +CREATE TABLE t1 (a INT NOT NULL DEFAULT 0) ENGINE=InnoDB; +iNSERT INTO t1 VALUES (10); +--enable_info +ALTER TABLE t1 ADD b TIME NOT NULL DEFAULT if(unix_timestamp()>1,TIMESTAMP'2001-01-01 10:20:30',0); +--disable_info +SELECT * FROM t1; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-online-alter-gis.test b/mysql-test/suite/innodb/t/innodb-online-alter-gis.test index 64d07ba23aa..2cb88d398bb 100644 --- a/mysql-test/suite/innodb/t/innodb-online-alter-gis.test +++ b/mysql-test/suite/innodb/t/innodb-online-alter-gis.test @@ -19,3 +19,13 @@ ALTER ONLINE TABLE t1 ADD PRIMARY KEY(a),DROP INDEX d, LOCK=SHARED; show warnings; show errors; drop table t1; + +--echo # +--echo # MDEV-14038 ALTER TABLE does not exit on error with InnoDB + bad default function +--echo # + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD +ALTER TABLE t1 ADD COLUMN b LINESTRING DEFAULT POINT(1,1); +DESCRIBE t1; +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index c9cf3c3dcb2..6b3f836048f 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2335,15 +2335,15 @@ Field *Field::clone(MEM_ROOT *root, my_ptrdiff_t diff) return tmp; } -void Field::set_default() +int Field::set_default() { if (default_value) { Query_arena backup_arena; table->in_use->set_n_backup_active_arena(table->expr_arena, &backup_arena); - (void) default_value->expr->save_in_field(this, 0); + int rc= default_value->expr->save_in_field(this, 0); table->in_use->restore_active_arena(table->expr_arena, &backup_arena); - return; + return rc; } /* Copy constant value stored in s->default_values */ my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values - @@ -2352,6 +2352,7 @@ void Field::set_default() if (maybe_null_in_table()) *null_ptr= ((*null_ptr & (uchar) ~null_bit) | (null_ptr[l_offset] & null_bit)); + return 0; } @@ -9665,7 +9666,7 @@ Field_bit::unpack(uchar *to, const uchar *from, const uchar *from_end, } -void Field_bit::set_default() +int Field_bit::set_default() { if (bit_len > 0) { @@ -9673,7 +9674,7 @@ void Field_bit::set_default() uchar bits= get_rec_bits(bit_ptr + col_offset, bit_ofs, bit_len); set_rec_bits(bits, bit_ptr, bit_ofs, bit_len); } - Field::set_default(); + return Field::set_default(); } /* diff --git a/sql/field.h b/sql/field.h index 91e97c8dce7..1d0ce8c74cf 100644 --- a/sql/field.h +++ b/sql/field.h @@ -953,7 +953,7 @@ public: my_ptrdiff_t l_offset= (my_ptrdiff_t) (record - table->record[0]); return ptr + l_offset; } - virtual void set_default(); + virtual int set_default(); bool has_update_default_function() const { @@ -3715,7 +3715,7 @@ public: virtual uchar *pack(uchar *to, const uchar *from, uint max_length); virtual const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end, uint param_data); - virtual void set_default(); + virtual int set_default(); Field *new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr, uint32 length, diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 61e9c29107a..d7fc070d1d7 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1076,8 +1076,15 @@ ha_innobase::check_if_supported_inplace_alter( /* Compute the DEFAULT values of non-constant columns (VCOL_SESSION_FUNC | VCOL_TIME_FUNC). */ - (*af)->set_default(); - goto next_column; + switch ((*af)->set_default()) { + case 0: /* OK */ + case 3: /* DATETIME to TIME or DATE conversion */ + goto next_column; + case -1: /* OOM, or GEOMETRY type mismatch */ + case 1: /* A number adjusted to the min/max value */ + case 2: /* String truncation, or conversion problem */ + break; + } } DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); From dc8ac122bb484b1e88c0aafee3e961208b93bbb5 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Wed, 11 Oct 2017 21:51:09 +0530 Subject: [PATCH 32/34] MDEV-13928: Missing symbols building RocksDB on macOS 10.12.6 rdb_sst_info.cc must be compiled with RTTI --- storage/rocksdb/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/rocksdb/CMakeLists.txt b/storage/rocksdb/CMakeLists.txt index 6db82119b45..a459cbe2d36 100644 --- a/storage/rocksdb/CMakeLists.txt +++ b/storage/rocksdb/CMakeLists.txt @@ -169,7 +169,7 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") # (also had to add -frtti above, because something that event_listener.cc # includes requires it. So, now everything in MariaRocks is compiled with # -frtti) - set_source_files_properties(event_listener.cc rdb_cf_options.cc + set_source_files_properties(event_listener.cc rdb_cf_options.cc rdb_sst_info.cc PROPERTIES COMPILE_FLAGS -frtti) ENDIF() From 4c9d19ee657b882fcb5a2daea702357a1a73b55f Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 11 Oct 2017 08:37:35 -0700 Subject: [PATCH 33/34] Fixed the bug mdev-13796. A reference to a CTE may occur not in the master of the CTE specification. In this case if the reference to the CTE is the first one the specification should be detached from its master and attached to the referencing select. Also fixed the TYPE column in the lines of the EXPLAIN output created for CTE tables. --- mysql-test/r/cte_nonrecursive.result | 36 +++++++++++++++++++++++----- mysql-test/r/cte_recursive.result | 26 ++++++++++---------- mysql-test/t/cte_nonrecursive.test | 19 +++++++++++++++ sql/sql_cte.cc | 10 +++++++- sql/sql_lex.cc | 27 ++++++++++++++++++++- sql/sql_lex.h | 1 + 6 files changed, 98 insertions(+), 21 deletions(-) diff --git a/mysql-test/r/cte_nonrecursive.result b/mysql-test/r/cte_nonrecursive.result index 79d380a04db..453f1319ccb 100644 --- a/mysql-test/r/cte_nonrecursive.result +++ b/mysql-test/r/cte_nonrecursive.result @@ -86,7 +86,7 @@ select * from t2,t where t2.c=t.a; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where 1 PRIMARY ref key0 key0 5 test.t2.c 2 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort +2 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort explain select * from t2, (select a, count(*) from t1 where b >= 'c' group by a) as t where t2.c=t.a; @@ -176,7 +176,7 @@ select * from t2 where c in (select c from t); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where 1 PRIMARY ref key0 key0 8 test.t2.c 2 Using where; FirstMatch(t2) -2 SUBQUERY t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort +2 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort explain select * from t2 where c in (select c from (select count(*) as c from t1 @@ -245,8 +245,8 @@ select * from t as r1, t as r2 where r1.a=r2.a; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 8 Using where 1 PRIMARY ref key0 key0 5 r1.a 2 -3 SUBQUERY t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary -2 SUBQUERY t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary +3 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary +2 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary explain select * from (select distinct a from t1 where b >= 'c') as r1, (select distinct a from t1 where b >= 'c') as r2 @@ -370,7 +370,7 @@ select * from t2,t where t2.c=t.a; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where 1 PRIMARY ref key0 key0 5 test.t2.c 2 -2 SUBQUERY t1 ALL NULL NULL NULL NULL 8 Using where +2 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where 3 UNION t2 ALL NULL NULL NULL NULL 4 Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL explain @@ -598,7 +598,7 @@ select * from v2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where 1 PRIMARY ref key0 key0 5 test.t2.c 2 -3 SUBQUERY t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort +3 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort # with clause in the specification of a view that whose definition # table alias for a with table create view v3 as @@ -1055,3 +1055,27 @@ deallocate prepare stmt1; deallocate prepare stmt2; drop view v1,v2; drop table t1,t2; +# +# MDEV-13796: UNION of two materialized CTEs +# +CREATE TABLE t1 (id int, k int); +CREATE TABLE t2 (id int); +INSERT INTO t1 VALUES (3,5), (1,7), (4,3); +INSERT INTO t2 VALUES (4), (3), (2); +WITH d1 AS (SELECT SUM(k) FROM t1, t2 as t2 WHERE t1.id = t2.id), +d2 AS (SELECT SUM(k) FROM t1, t2 as t2 WHERE t1.id = t2.id) +SELECT * FROM d1 UNION SELECT * FROM d2; +SUM(k) +8 +explain WITH d1 AS (SELECT SUM(k) FROM t1, t2 as t2 WHERE t1.id = t2.id), +d2 AS (SELECT SUM(k) FROM t1, t2 as t2 WHERE t1.id = t2.id) +SELECT * FROM d1 UNION SELECT * FROM d2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 9 +2 DERIVED t1 ALL NULL NULL NULL NULL 3 +2 DERIVED t2 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) +4 UNION ALL NULL NULL NULL NULL 9 +3 DERIVED t1 ALL NULL NULL NULL NULL 3 +3 DERIVED t2 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +DROP TABLE t1,t2; diff --git a/mysql-test/r/cte_recursive.result b/mysql-test/r/cte_recursive.result index 42ba01e42de..057e3fe034c 100644 --- a/mysql-test/r/cte_recursive.result +++ b/mysql-test/r/cte_recursive.result @@ -86,7 +86,7 @@ select t2.a from t1,t2 where t1.a+1=t2.a select * from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 30 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where +2 DERIVED t2 ALL NULL NULL NULL NULL 5 Using where 3 UNION t1 ALL NULL NULL NULL NULL 5 3 UNION t2 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -114,7 +114,7 @@ select t2.a from t1,t2 where t1.a+1=t2.a select * from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 5 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where +2 DERIVED t2 ALL NULL NULL NULL NULL 5 Using where 3 RECURSIVE UNION ALL NULL NULL NULL NULL 5 3 RECURSIVE UNION t2 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -691,13 +691,13 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY ALL NULL NULL NULL NULL 2 100.00 Using where 1 PRIMARY ref key0 key0 5 c.h_id 2 100.00 1 PRIMARY ref key0 key0 5 c.w_id 2 100.00 -3 SUBQUERY folks ALL NULL NULL NULL NULL 12 100.00 Using where +3 DERIVED folks ALL NULL NULL NULL NULL 12 100.00 Using where 4 RECURSIVE UNION ALL NULL NULL NULL NULL 2 100.00 4 RECURSIVE UNION p ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join) 5 RECURSIVE UNION ALL NULL NULL NULL NULL 2 100.00 5 RECURSIVE UNION p ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join) NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL -2 UNCACHEABLE SUBQUERY ALL NULL NULL NULL NULL 12 100.00 Using where +2 DERIVED ALL NULL NULL NULL NULL 12 100.00 Using where Warnings: Note 1003 with recursive ancestor_couple_ids as (select `a`.`father` AS `h_id`,`a`.`mother` AS `w_id` from `coupled_ancestors` `a` where `a`.`father` is not null and `a`.`mother` is not null), coupled_ancestors as (select `test`.`folks`.`id` AS `id`,`test`.`folks`.`name` AS `name`,`test`.`folks`.`dob` AS `dob`,`test`.`folks`.`father` AS `father`,`test`.`folks`.`mother` AS `mother` from `test`.`folks` where `test`.`folks`.`name` = 'Me' union all select `test`.`p`.`id` AS `id`,`test`.`p`.`name` AS `name`,`test`.`p`.`dob` AS `dob`,`test`.`p`.`father` AS `father`,`test`.`p`.`mother` AS `mother` from `test`.`folks` `p` join `ancestor_couple_ids` `fa` where `test`.`p`.`id` = `fa`.`h_id` union all select `test`.`p`.`id` AS `id`,`test`.`p`.`name` AS `name`,`test`.`p`.`dob` AS `dob`,`test`.`p`.`father` AS `father`,`test`.`p`.`mother` AS `mother` from `test`.`folks` `p` join `ancestor_couple_ids` `ma` where `test`.`p`.`id` = `ma`.`w_id`)select `h`.`name` AS `name`,`h`.`dob` AS `dob`,`w`.`name` AS `name`,`w`.`dob` AS `dob` from `ancestor_couple_ids` `c` join `coupled_ancestors` `h` join `coupled_ancestors` `w` where `h`.`id` = `c`.`h_id` and `w`.`id` = `c`.`w_id` # simple mutual recursion @@ -877,7 +877,7 @@ where p.id = a.father or p.id = a.mother select * from ancestors; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY ALL NULL NULL NULL NULL 12 100.00 -2 SUBQUERY folks ALL NULL NULL NULL NULL 12 100.00 Using where +2 DERIVED folks ALL NULL NULL NULL NULL 12 100.00 Using where 3 RECURSIVE UNION p ALL NULL NULL NULL NULL 12 100.00 3 RECURSIVE UNION ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join) NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL @@ -1236,7 +1236,7 @@ where p.id = ma.mother select * from ancestors; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 12 -2 SUBQUERY folks ALL NULL NULL NULL NULL 12 Using where +2 DERIVED folks ALL NULL NULL NULL NULL 12 Using where 3 RECURSIVE UNION p ALL PRIMARY NULL NULL NULL 12 3 RECURSIVE UNION ref key0 key0 5 test.p.id 2 4 RECURSIVE UNION p ALL PRIMARY NULL NULL NULL 12 @@ -1300,14 +1300,14 @@ from prev_gen select ancestors.name, ancestors.dob from ancestors; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 24 -4 SUBQUERY folks ALL NULL NULL NULL NULL 12 Using where +4 DERIVED folks ALL NULL NULL NULL NULL 12 Using where 6 RECURSIVE UNION ALL NULL NULL NULL NULL 12 -5 RECURSIVE UNION ALL NULL NULL NULL NULL 24 -NULL UNION RESULT ALL NULL NULL NULL NULL NULL -3 SUBQUERY folks ALL NULL NULL NULL NULL 12 Using where +3 DERIVED folks ALL NULL NULL NULL NULL 12 Using where 2 RECURSIVE UNION folks ALL PRIMARY NULL NULL NULL 12 2 RECURSIVE UNION ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) NULL UNION RESULT ALL NULL NULL NULL NULL NULL +5 RECURSIVE UNION ALL NULL NULL NULL NULL 24 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL explain FORMAT=JSON with recursive prev_gen @@ -1831,7 +1831,7 @@ select t2.a from t1,t2 where t1.a+1=t2.a select * from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 5 -2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where +2 DERIVED t2 ALL NULL NULL NULL NULL 5 Using where 4 RECURSIVE UNION ALL NULL NULL NULL NULL 5 4 RECURSIVE UNION t2 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -2783,7 +2783,7 @@ SELECT c1 FROM t, cte ) SELECT COUNT(*) FROM cte; id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra 1 PRIMARY ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 -2 SUBQUERY t ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 +2 DERIVED t ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 3 RECURSIVE UNION t ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 3 RECURSIVE UNION ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 Using join buffer (flat, BNL join) NULL UNION RESULT ALL NULL NULL NULL NULL NULL 0.00 NULL NULL @@ -2801,7 +2801,7 @@ SELECT c2 FROM t, cte ) SELECT COUNT(*) FROM cte; id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra 1 PRIMARY ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 -2 SUBQUERY t ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 +2 DERIVED t ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 3 RECURSIVE UNION t ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 3 RECURSIVE UNION ALL NULL NULL NULL NULL 4 4.00 100.00 100.00 Using join buffer (flat, BNL join) NULL UNION RESULT ALL NULL NULL NULL NULL NULL 0.00 NULL NULL diff --git a/mysql-test/t/cte_nonrecursive.test b/mysql-test/t/cte_nonrecursive.test index 980bff01694..57b7ae1658f 100644 --- a/mysql-test/t/cte_nonrecursive.test +++ b/mysql-test/t/cte_nonrecursive.test @@ -724,3 +724,22 @@ deallocate prepare stmt2; drop view v1,v2; drop table t1,t2; + +--echo # +--echo # MDEV-13796: UNION of two materialized CTEs +--echo # + +CREATE TABLE t1 (id int, k int); +CREATE TABLE t2 (id int); +INSERT INTO t1 VALUES (3,5), (1,7), (4,3); +INSERT INTO t2 VALUES (4), (3), (2); + +let $q= +WITH d1 AS (SELECT SUM(k) FROM t1, t2 as t2 WHERE t1.id = t2.id), + d2 AS (SELECT SUM(k) FROM t1, t2 as t2 WHERE t1.id = t2.id) +SELECT * FROM d1 UNION SELECT * FROM d2; + +eval $q; +eval explain $q; + +DROP TABLE t1,t2; diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 1b14c5b68b7..e1af30123f6 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -991,7 +991,7 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) been done yet. */ if (with_elem && sl->master_unit() == with_elem->spec) - break; + break; With_clause *with_clause=sl->get_with_clause(); if (with_clause) { @@ -1039,13 +1039,21 @@ bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) } with= with_elem; if (!with_elem->is_referenced() || with_elem->is_recursive) + { derived= with_elem->spec; + if (derived->get_master() != select_lex && + !is_with_table_recursive_reference()) + { + derived->move_as_slave(select_lex); + } + } else { if(!(derived= with_elem->clone_parsed_spec(thd, this))) return true; derived->with_element= with_elem; } + derived->first_select()->linkage= DERIVED_TABLE_TYPE; with_elem->inc_references(); return false; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7879edc3f67..c8474c66ca1 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2304,6 +2304,30 @@ st_select_lex_node *st_select_lex_node:: insert_chain_before( return this; } + +/* + Detach the node from its master and attach it to a new master +*/ + +void st_select_lex_node::move_as_slave(st_select_lex_node *new_master) +{ + exclude_from_tree(); + if (new_master->slave) + { + st_select_lex_node *curr= new_master->slave; + for ( ; curr->next ; curr= curr->next) ; + prev= &curr->next; + } + else + { + prev= &new_master->slave; + new_master->slave= this; + } + next= 0; + master= new_master; +} + + /* Exclude a node from the tree lex structure, but leave it in the global list of nodes. @@ -4404,7 +4428,8 @@ void st_select_lex::set_explain_type(bool on_the_fly) pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs. */ if (tab->table && tab->table->pos_in_table_list && - tab->table->pos_in_table_list->with) + tab->table->pos_in_table_list->with && + tab->table->pos_in_table_list->with->is_recursive) { uses_cte= true; break; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a1ef42861b4..9ab09c9fe7e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -561,6 +561,7 @@ public: } st_select_lex_node *insert_chain_before(st_select_lex_node **ptr_pos_to_insert, st_select_lex_node *end_chain_node); + void move_as_slave(st_select_lex_node *new_master); friend class st_select_lex_unit; friend bool mysql_new_select(LEX *lex, bool move_down); friend bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, From a4fa940bad7f3a2c4afff776977ad5e46dfe95d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 12 Oct 2017 12:56:20 +0300 Subject: [PATCH 34/34] MDEV-11336: Enable defragmentation on 10.2 when tests pass Problem was that we could take page latches on different order than wat is entitled with SX-lock. To follow the latching order defined in WL#6326, acquire index->lock X-latch. This entitles us to acquire page latches in any order for the index. btr0btr.cc Document latch rules before and after MariaDB 10.2.2 sync0rw.cc Document latch compatibility rules better. btr_defragment_merge_pages Fix parameter value. btr_defragment_thread Acquire X-lock to dict_index_t::lock before restoring cursor position and continuing defragmentation. ha_innobase::optimize Restore defragment feature. Testing Add GIS-index and FT-index to table being defragmented. Defragmentation is not done to GIS-indexes and FT auxiliary tables. --- mysql-test/suite/innodb/disabled.def | 9 -- .../innodb/r/innodb_defrag_concurrent.result | 17 +++- .../innodb/t/innodb_defrag_concurrent.test | 28 +++++- storage/innobase/btr/btr0btr.cc | 91 ++++++++++++++++--- storage/innobase/btr/btr0defragment.cc | 11 ++- storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/sync/sync0rw.cc | 13 ++- 7 files changed, 133 insertions(+), 38 deletions(-) diff --git a/mysql-test/suite/innodb/disabled.def b/mysql-test/suite/innodb/disabled.def index 9a92e99df2e..c435de278b9 100644 --- a/mysql-test/suite/innodb/disabled.def +++ b/mysql-test/suite/innodb/disabled.def @@ -10,14 +10,5 @@ # ############################################################################## -innodb_defragment_fill_factor : MDEV-11336 Fix and enable innodb_defragment -innodb.defrag_mdl-9155 : MDEV-11336 Fix and enable innodb_defragment -innodb.innodb_defrag_concurrent : MDEV-11336 Fix and enable innodb_defragment -innodb.innodb_defrag_stats : MDEV-11336 Fix and enable innodb_defragment -innodb.innodb_defrag_stats_many_tables : MDEV-11336 Fix and enable innodb_defragment -innodb.innodb_defragment : MDEV-11336 Fix and enable innodb_defragment -innodb.innodb_defragment_fill_factor : MDEV-11336 Fix and enable innodb_defragment -innodb.innodb_defragment_small : MDEV-11336 Fix and enable innodb_defragment -innodb.innodb_defrag_binlog : MDEV-11336 Fix and enable innodb_defragment innodb-wl5980-alter : MDEV-9469 / MDEV-13668 extra crash in 10.2 create-index-debug : MDEV-13680 InnoDB may crash when btr_page_alloc() fails diff --git a/mysql-test/suite/innodb/r/innodb_defrag_concurrent.result b/mysql-test/suite/innodb/r/innodb_defrag_concurrent.result index ff32bf694cb..d10727b95b4 100644 --- a/mysql-test/suite/innodb/r/innodb_defrag_concurrent.result +++ b/mysql-test/suite/innodb/r/innodb_defrag_concurrent.result @@ -3,7 +3,15 @@ select @@global.innodb_stats_persistent; @@global.innodb_stats_persistent 0 set global innodb_defragment_stats_accuracy = 80; -CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), c INT, KEY second(a, b),KEY third(c)) ENGINE=INNODB; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, +b VARCHAR(256), +c INT, +g GEOMETRY NOT NULL, +t VARCHAR(256), +KEY second(a, b), +KEY third(c), +SPATIAL gk(g), +FULLTEXT INDEX fti(t)) ENGINE=INNODB; connect con1,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK; connect con2,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK; connect con3,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK; @@ -40,9 +48,9 @@ count(stat_value) > 0 connection con1; optimize table t1;; connection default; -INSERT INTO t1 VALUES (400000, REPEAT('A', 256),300000);; +INSERT INTO t1 VALUES (400000, REPEAT('A', 256),300000, Point(1,1),'More like a test but different.');; connection con2; -INSERT INTO t1 VALUES (500000, REPEAT('A', 256),400000);; +INSERT INTO t1 VALUES (500000, REPEAT('A', 256),400000, Point(1,1),'Totally different text book.');; connection con3; DELETE FROM t1 where a between 1 and 100;; connection con4; @@ -59,6 +67,9 @@ disconnect con4; optimize table t1; Table Op Msg_type Msg_text test.t1 optimize status OK +check table t1 extended; +Table Op Msg_type Msg_text +test.t1 check status OK select count(*) from t1; count(*) 15723 diff --git a/mysql-test/suite/innodb/t/innodb_defrag_concurrent.test b/mysql-test/suite/innodb/t/innodb_defrag_concurrent.test index f596fab2a15..bbcd72f1a3a 100644 --- a/mysql-test/suite/innodb/t/innodb_defrag_concurrent.test +++ b/mysql-test/suite/innodb/t/innodb_defrag_concurrent.test @@ -16,7 +16,26 @@ select @@global.innodb_stats_persistent; set global innodb_defragment_stats_accuracy = 80; # Create table. -CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), c INT, KEY second(a, b),KEY third(c)) ENGINE=INNODB; +# +# TODO: Currently we do not defragment spatial indexes, +# because doing it properly would require +# appropriate logic around the SSN (split +# sequence number). +# +# Also do not defragment auxiliary tables related to FULLTEXT INDEX. +# +# Both types added to this test to make sure they do not cause +# problems. +# +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, +b VARCHAR(256), +c INT, +g GEOMETRY NOT NULL, +t VARCHAR(256), +KEY second(a, b), +KEY third(c), +SPATIAL gk(g), +FULLTEXT INDEX fti(t)) ENGINE=INNODB; connect (con1,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); connect (con2,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); @@ -36,7 +55,7 @@ let $i = $data_size; while ($i) { eval - INSERT INTO t1 VALUES ($data_size + 1 - $i, REPEAT('A', 256), $i); + INSERT INTO t1 VALUES ($data_size + 1 - $i, REPEAT('A', 256), $i, Point($i,$i), 'This is a test message.'); dec $i; } --enable_query_log @@ -69,10 +88,10 @@ connection con1; --send optimize table t1; connection default; ---send INSERT INTO t1 VALUES (400000, REPEAT('A', 256),300000); +--send INSERT INTO t1 VALUES (400000, REPEAT('A', 256),300000, Point(1,1),'More like a test but different.'); connection con2; ---send INSERT INTO t1 VALUES (500000, REPEAT('A', 256),400000); +--send INSERT INTO t1 VALUES (500000, REPEAT('A', 256),400000, Point(1,1),'Totally different text book.'); connection con3; --send DELETE FROM t1 where a between 1 and 100; @@ -103,6 +122,7 @@ disconnect con3; disconnect con4; optimize table t1; +check table t1 extended; select count(*) from t1; select count(*) from t1 force index (second); diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index bf4a123c2ee..e638af8a217 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -77,22 +77,85 @@ btr_corruption_report( /* Latching strategy of the InnoDB B-tree -------------------------------------- -A tree latch protects all non-leaf nodes of the tree. Each node of a tree -also has a latch of its own. -A B-tree operation normally first acquires an S-latch on the tree. It -searches down the tree and releases the tree latch when it has the -leaf node latch. To save CPU time we do not acquire any latch on -non-leaf nodes of the tree during a search, those pages are only bufferfixed. +Node pointer page latches acquisition is protected by index->lock latch. -If an operation needs to restructure the tree, it acquires an X-latch on -the tree before searching to a leaf node. If it needs, for example, to -split a leaf, -(1) InnoDB decides the split point in the leaf, -(2) allocates a new page, -(3) inserts the appropriate node pointer to the first non-leaf level, -(4) releases the tree X-latch, -(5) and then moves records from the leaf to the new allocated page. +Before MariaDB 10.2.2, all node pointer pages were protected by index->lock +either in S (shared) or X (exclusive) mode and block->lock was not acquired on +node pointer pages. + +After MariaDB 10.2.2, block->lock S-latch or X-latch is used to protect +node pointer pages and obtaiment of node pointer page latches is protected by +index->lock. + +(0) Definition: B-tree level. + +(0.1) The leaf pages of the B-tree are at level 0. + +(0.2) The parent of a page at level L has level L+1. (The level of the +root page is equal to the tree height.) + +(0.3) The B-tree lock (index->lock) is the parent of the root page and +has a level = tree height + 1. + +Index->lock has 3 possible locking modes: + +(1) S-latch: + +(1.1) All latches for pages must be obtained in descending order of tree level. + +(1.2) Before obtaining the first node pointer page latch at a given B-tree +level, parent latch must be held (at level +1 ). + +(1.3) If a node pointer page is already latched at the same level +we can only obtain latch to its right sibling page latch at the same level. + +(1.4) Release of the node pointer page latches must be done in +child-to-parent order. (Prevents deadlocks when obtained index->lock +in SX mode). + +(1.4.1) Level L node pointer page latch can be released only when +no latches at children level i.e. level < L are hold. + +(1.4.2) All latches from node pointer pages must be released so +that no latches are obtained between. + +(1.5) [implied by (1.1), (1.2)] Root page latch must be first node pointer +latch obtained. + +(2) SX-latch: + +In this case rules (1.2) and (1.3) from S-latch case are relaxed and +merged into (2.2) and rule (1.4) is removed. Thus, latch acquisition +can be skipped at some tree levels and latches can be obtained in +a less restricted order. + +(2.1) [identical to (1.1)]: All latches for pages must be obtained in descending +order of tree level. + +(2.2) When a node pointer latch at level L is obtained, +the left sibling page latch in the same level or some ancestor +page latch (at level > L) must be hold. + +(2.3) [implied by (2.1), (2.2)] The first node pointer page latch obtained can +be any node pointer page. + +(3) X-latch: + +Node pointer latches can be obtained in any order. + +NOTE: New rules after MariaDB 10.2.2 does not affect the latching rules of leaf pages: + +index->lock S-latch is needed in read for the node pointer traversal. When the leaf +level is reached, index-lock can be released (and with the MariaDB 10.2.2 changes, all +node pointer latches). Left to right index travelsal in leaf page level can be safely done +by obtaining right sibling leaf page latch and then releasing the old page latch. + +Single leaf page modifications (BTR_MODIFY_LEAF) are protected by index->lock +S-latch. + +B-tree operations involving page splits or merges (BTR_MODIFY_TREE) and page +allocations are protected by index->lock X-latch. Node pointers ------------- diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index 335b4fc220d..70444ca1830 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -564,7 +564,7 @@ btr_defragment_merge_pages( page_get_infimum_rec(from_page)); node_ptr = dict_index_build_node_ptr( index, rec, page_get_page_no(from_page), - heap, level + 1); + heap, level); btr_insert_on_non_leaf_level(0, index, level+1, node_ptr, mtr); } @@ -797,11 +797,16 @@ DECLARE_THREAD(btr_defragment_thread)(void*) now = ut_timer_now(); mtr_start(&mtr); - btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, &mtr); cursor = btr_pcur_get_btr_cur(pcur); index = btr_cur_get_index(cursor); - first_block = btr_cur_get_block(cursor); mtr.set_named_space(index->space); + /* To follow the latching order defined in WL#6326, acquire index->lock X-latch. + This entitles us to acquire page latches in any order for the index. */ + mtr_x_lock(&index->lock, &mtr); + /* This will acquire index->lock SX-latch, which per WL#6363 is allowed + when we are already holding the X-latch. */ + btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, &mtr); + first_block = btr_cur_get_block(cursor); last_block = btr_defragment_n_pages(first_block, index, srv_defragment_n_pages, diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3374f46fb24..e7bf2b649f9 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -15066,7 +15066,7 @@ ha_innobase::optimize( calls to OPTIMIZE, which is undesirable. */ /* TODO: Defragment is disabled for now */ - if (0) { + if (srv_defragment) { int err; err = defragment_table(m_prebuilt->table->name.m_name, NULL, false); diff --git a/storage/innobase/sync/sync0rw.cc b/storage/innobase/sync/sync0rw.cc index 6322b14335f..37b64910713 100644 --- a/storage/innobase/sync/sync0rw.cc +++ b/storage/innobase/sync/sync0rw.cc @@ -84,10 +84,15 @@ lock_word < -(X_LOCK_DECR + X_LOCK_HALF_DECR): 2 - (lock_word + X_LOCK_DECR + X_LOCK_HALF_DECR) LOCK COMPATIBILITY MATRIX - S SX X - S + + - - SX + - - - X - - - + + | S|SX| X| + --+--+--+--+ + S| +| +| -| + --+--+--+--+ + SX| +| -| -| + --+--+--+--+ + X| -| -| -| + --+--+--+--+ The lock_word is always read and updated atomically and consistently, so that it always represents the state of the lock, and the state of the lock changes