mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
Merge branch '10.4' into bb-10.4-mdev17096
This commit is contained in:
@@ -98,17 +98,20 @@ ELSEIF(RPM)
|
||||
SET(CHECKMODULE /usr/bin/checkmodule CACHE STRING "")
|
||||
SET(SEMODULE_PACKAGE /usr/bin/semodule_package CACHE STRING "")
|
||||
SET(WITH_LIBARCHIVE ON CACHE STRING "")
|
||||
SET(PLUGIN_AUTH_SOCKET YES)
|
||||
ELSEIF(DEB)
|
||||
SET(WITH_SSL system CACHE STRING "")
|
||||
SET(WITH_ZLIB system CACHE STRING "")
|
||||
SET(WITH_LIBWRAP ON)
|
||||
SET(HAVE_EMBEDDED_PRIVILEGE_CONTROL ON)
|
||||
SET(WITH_LIBARCHIVE ON CACHE STRING "")
|
||||
SET(PLUGIN_AUTH_SOCKET YES)
|
||||
ELSE()
|
||||
SET(WITH_SSL bundled CACHE STRING "")
|
||||
SET(WITH_ZLIB bundled CACHE STRING "")
|
||||
SET(WITH_JEMALLOC static CACHE STRING "")
|
||||
SET(WITH_LIBARCHIVE STATIC CACHE STRING "")
|
||||
SET(PLUGIN_AUTH_SOCKET STATIC)
|
||||
ENDIF()
|
||||
|
||||
IF(NOT COMPILATION_COMMENT)
|
||||
|
||||
@@ -28,20 +28,20 @@ OPTION(WITH_WSREP_ALL
|
||||
"Build all components of WSREP (unit tests, sample programs)"
|
||||
OFF)
|
||||
|
||||
# Set the patch version
|
||||
SET(WSREP_PATCH_VERSION "22")
|
||||
|
||||
# Obtain wsrep API version
|
||||
FILE(STRINGS "${CMAKE_SOURCE_DIR}/wsrep-lib/wsrep-API/v26/wsrep_api.h" WSREP_API_VERSION
|
||||
LIMIT_COUNT 1 REGEX "WSREP_INTERFACE_VERSION")
|
||||
STRING(REGEX MATCH "([0-9]+)" WSREP_API_VERSION "${WSREP_API_VERSION}")
|
||||
|
||||
SET(WSREP_VERSION "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}"
|
||||
CACHE INTERNAL "WSREP version")
|
||||
|
||||
SET(WSREP_PROC_INFO ${WITH_WSREP})
|
||||
|
||||
IF(WITH_WSREP)
|
||||
# Set the patch version
|
||||
SET(WSREP_PATCH_VERSION "22")
|
||||
|
||||
# Obtain wsrep API version
|
||||
FILE(STRINGS "${CMAKE_SOURCE_DIR}/wsrep-lib/wsrep-API/v26/wsrep_api.h" WSREP_API_VERSION
|
||||
LIMIT_COUNT 1 REGEX "WSREP_INTERFACE_VERSION")
|
||||
STRING(REGEX MATCH "([0-9]+)" WSREP_API_VERSION "${WSREP_API_VERSION}")
|
||||
|
||||
SET(WSREP_VERSION "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}"
|
||||
CACHE INTERNAL "WSREP version")
|
||||
|
||||
SET(WSREP_PROC_INFO ${WITH_WSREP})
|
||||
|
||||
SET(WSREP_PATCH_VERSION "wsrep_${WSREP_VERSION}")
|
||||
if (NOT WITH_WSREP_ALL)
|
||||
SET(WSREP_LIB_WITH_UNIT_TESTS OFF CACHE BOOL
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2014, 2018, MariaDB Corporation.
|
||||
Copyright (c) 2014, 2019, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -71,10 +71,8 @@ static my_bool per_page_details;
|
||||
static ulint n_merge;
|
||||
extern ulong srv_checksum_algorithm;
|
||||
static ulint physical_page_size; /* Page size in bytes on disk. */
|
||||
static ulint logical_page_size; /* Page size when uncompressed. */
|
||||
ulong srv_page_size;
|
||||
ulong srv_page_size_shift;
|
||||
page_size_t univ_page_size(0, 0, false);
|
||||
/* Current page number (0 based). */
|
||||
unsigned long long cur_page_num;
|
||||
/* Skip the checksum verification. */
|
||||
@@ -276,13 +274,11 @@ void print_leaf_stats(
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the page size of the filespace from the filespace header.
|
||||
/** Get the ROW_FORMAT=COMPRESSED size from the filespace header.
|
||||
@param[in] buf buffer used to read the page.
|
||||
@return page size */
|
||||
static
|
||||
const page_size_t
|
||||
get_page_size(
|
||||
byte* buf)
|
||||
@return ROW_FORMAT_COMPRESSED page size
|
||||
@retval 0 if not ROW_FORMAT=COMPRESSED */
|
||||
static ulint get_zip_size(const byte* buf)
|
||||
{
|
||||
const unsigned flags = mach_read_from_4(buf + FIL_PAGE_DATA
|
||||
+ FSP_SPACE_FLAGS);
|
||||
@@ -294,11 +290,14 @@ get_page_size(
|
||||
: UNIV_PAGE_SIZE_SHIFT_ORIG;
|
||||
|
||||
srv_page_size = 1U << srv_page_size_shift;
|
||||
|
||||
univ_page_size.copy_from(
|
||||
page_size_t(srv_page_size, srv_page_size, false));
|
||||
|
||||
return(page_size_t(flags));
|
||||
ulint zip_size = FSP_FLAGS_GET_ZIP_SSIZE(flags);
|
||||
if (zip_size) {
|
||||
zip_size = (UNIV_ZIP_SIZE_MIN >> 1) << zip_size;
|
||||
physical_page_size = zip_size;
|
||||
} else {
|
||||
physical_page_size = srv_page_size;
|
||||
}
|
||||
return zip_size;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -430,7 +429,7 @@ ulint read_file(
|
||||
|
||||
/** Check if page is corrupted or not.
|
||||
@param[in] buf page frame
|
||||
@param[in] page_size page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] is_encrypted true if page0 contained cryp_data
|
||||
with crypt_scheme encrypted
|
||||
@param[in] is_compressed true if page0 fsp_flags contained
|
||||
@@ -440,7 +439,7 @@ static
|
||||
bool
|
||||
is_page_corrupted(
|
||||
byte* buf,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
bool is_encrypted,
|
||||
bool is_compressed)
|
||||
{
|
||||
@@ -465,12 +464,12 @@ is_page_corrupted(
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (page_size.is_compressed()) {
|
||||
if (!zip_size) {
|
||||
/* check the stored log sequence numbers
|
||||
for uncompressed tablespace. */
|
||||
logseq = mach_read_from_4(buf + FIL_PAGE_LSN + 4);
|
||||
logseqfield = mach_read_from_4(
|
||||
buf + page_size.logical() -
|
||||
buf + srv_page_size -
|
||||
FIL_PAGE_END_LSN_OLD_CHKSUM + 4);
|
||||
|
||||
if (is_log_enabled) {
|
||||
@@ -499,8 +498,7 @@ is_page_corrupted(
|
||||
so if crypt checksum does not match we verify checksum using
|
||||
normal method. */
|
||||
if (is_encrypted && key_version != 0) {
|
||||
is_corrupted = !fil_space_verify_crypt_checksum(buf,
|
||||
page_size);
|
||||
is_corrupted = !fil_space_verify_crypt_checksum(buf, zip_size);
|
||||
if (is_corrupted && log_file) {
|
||||
fprintf(log_file,
|
||||
"Page " ULINTPF ":%llu may be corrupted;"
|
||||
@@ -516,7 +514,7 @@ is_page_corrupted(
|
||||
|
||||
if (is_corrupted) {
|
||||
is_corrupted = buf_page_is_corrupted(
|
||||
true, buf, page_size, NULL);
|
||||
true, buf, zip_size, NULL);
|
||||
}
|
||||
|
||||
return(is_corrupted);
|
||||
@@ -568,7 +566,6 @@ is_page_empty(
|
||||
/********************************************************************//**
|
||||
Rewrite the checksum for the page.
|
||||
@param [in/out] page page buffer
|
||||
@param [in] physical_page_size page size in bytes on disk.
|
||||
@param [in] iscompressed Is compressed/Uncompressed Page.
|
||||
|
||||
@retval true : do rewrite
|
||||
@@ -579,7 +576,6 @@ Rewrite the checksum for the page.
|
||||
bool
|
||||
update_checksum(
|
||||
byte* page,
|
||||
ulong physical_page_size,
|
||||
bool iscompressed)
|
||||
{
|
||||
ib_uint32_t checksum = 0;
|
||||
@@ -696,7 +692,6 @@ func_exit:
|
||||
@param[in] compressed Enabled if tablespace is
|
||||
compressed.
|
||||
@param[in,out] pos current file position.
|
||||
@param[in] page_size page size in bytes on disk.
|
||||
|
||||
@retval true if successfully written
|
||||
@retval false if a non-recoverable error occurred
|
||||
@@ -708,12 +703,11 @@ write_file(
|
||||
FILE* file,
|
||||
byte* buf,
|
||||
bool compressed,
|
||||
fpos_t* pos,
|
||||
ulong page_size)
|
||||
fpos_t* pos)
|
||||
{
|
||||
bool do_update;
|
||||
|
||||
do_update = update_checksum(buf, page_size, compressed);
|
||||
do_update = update_checksum(buf, compressed);
|
||||
|
||||
if (file != stdin) {
|
||||
if (do_update) {
|
||||
@@ -733,8 +727,9 @@ write_file(
|
||||
}
|
||||
}
|
||||
|
||||
if (page_size
|
||||
!= fwrite(buf, 1, page_size, file == stdin ? stdout : file)) {
|
||||
if (physical_page_size
|
||||
!= fwrite(buf, 1, physical_page_size,
|
||||
file == stdin ? stdout : file)) {
|
||||
fprintf(stderr, "Failed to write page::%llu to %s: %s\n",
|
||||
cur_page_num, filename, strerror(errno));
|
||||
|
||||
@@ -757,7 +752,6 @@ Parse the page and collect/dump the information about page type
|
||||
@param [in] page buffer page
|
||||
@param [out] xdes extend descriptor page
|
||||
@param [in] file file for diagnosis.
|
||||
@param [in] page_size page_size
|
||||
@param [in] is_encrypted tablespace is encrypted
|
||||
*/
|
||||
void
|
||||
@@ -765,7 +759,6 @@ parse_page(
|
||||
const byte* page,
|
||||
byte* xdes,
|
||||
FILE* file,
|
||||
const page_size_t& page_size,
|
||||
bool is_encrypted)
|
||||
{
|
||||
unsigned long long id;
|
||||
@@ -824,8 +817,7 @@ parse_page(
|
||||
}
|
||||
|
||||
size_range_id = (data_bytes * SIZE_RANGES_FOR_PAGE
|
||||
+ page_size.logical() - 1) /
|
||||
page_size.logical();
|
||||
+ srv_page_size - 1) / srv_page_size;
|
||||
|
||||
if (size_range_id > SIZE_RANGES_FOR_PAGE + 1) {
|
||||
/* data_bytes is bigger than logical_page_size */
|
||||
@@ -844,7 +836,7 @@ parse_page(
|
||||
it = index_ids.find(id);
|
||||
per_index_stats &index = (it->second);
|
||||
const byte* des = xdes + XDES_ARR_OFFSET
|
||||
+ XDES_SIZE * ((page_no & (page_size.physical() - 1))
|
||||
+ XDES_SIZE * ((page_no & (physical_page_size - 1))
|
||||
/ FSP_EXTENT_SIZE);
|
||||
if (xdes_get_bit(des, XDES_FREE_BIT,
|
||||
page_no % FSP_EXTENT_SIZE)) {
|
||||
@@ -1007,7 +999,7 @@ parse_page(
|
||||
|
||||
case FIL_PAGE_TYPE_FSP_HDR:
|
||||
page_type.n_fil_page_type_fsp_hdr++;
|
||||
memcpy(xdes, page, page_size.physical());
|
||||
memcpy(xdes, page, physical_page_size);
|
||||
if (page_type_dump) {
|
||||
fprintf(file, "#::%llu\t\t|\t\tFile Space "
|
||||
"Header\t\t|\t%s\n", cur_page_num, str);
|
||||
@@ -1016,7 +1008,7 @@ parse_page(
|
||||
|
||||
case FIL_PAGE_TYPE_XDES:
|
||||
page_type.n_fil_page_type_xdes++;
|
||||
memcpy(xdes, page, page_size.physical());
|
||||
memcpy(xdes, page, physical_page_size);
|
||||
if (page_type_dump) {
|
||||
fprintf(file, "#::%llu\t\t|\t\tExtent descriptor "
|
||||
"page\t\t|\t%s\n", cur_page_num, str);
|
||||
@@ -1384,18 +1376,13 @@ get_options(
|
||||
|
||||
/** Check from page 0 if table is encrypted.
|
||||
@param[in] filename Filename
|
||||
@param[in] page_size page size
|
||||
@param[in] page Page 0
|
||||
@retval true if tablespace is encrypted, false if not
|
||||
*/
|
||||
static
|
||||
bool check_encryption(
|
||||
const char* filename,
|
||||
const page_size_t& page_size,
|
||||
byte * page)
|
||||
static bool check_encryption(const char* filename, const byte* page)
|
||||
{
|
||||
ulint offset = (FSP_HEADER_OFFSET + (XDES_ARR_OFFSET + XDES_SIZE *
|
||||
(page_size.physical()) / FSP_EXTENT_SIZE));
|
||||
ulint offset = FSP_HEADER_OFFSET + XDES_ARR_OFFSET + XDES_SIZE *
|
||||
physical_page_size / FSP_EXTENT_SIZE;
|
||||
|
||||
if (memcmp(page + offset, CRYPT_MAGIC, MAGIC_SZ) != 0) {
|
||||
return false;
|
||||
@@ -1431,7 +1418,7 @@ bool check_encryption(
|
||||
/**
|
||||
Verify page checksum.
|
||||
@param[in] buf page to verify
|
||||
@param[in] page_size page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] is_encrypted true if tablespace is encrypted
|
||||
@param[in] is_compressed true if tablespace is page compressed
|
||||
@param[in,out] mismatch_count Number of pages failed in checksum verify
|
||||
@@ -1440,7 +1427,7 @@ Verify page checksum.
|
||||
static
|
||||
int verify_checksum(
|
||||
byte* buf,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
bool is_encrypted,
|
||||
bool is_compressed,
|
||||
unsigned long long* mismatch_count)
|
||||
@@ -1449,7 +1436,7 @@ int verify_checksum(
|
||||
bool is_corrupted = false;
|
||||
|
||||
is_corrupted = is_page_corrupted(
|
||||
buf, page_size, is_encrypted, is_compressed);
|
||||
buf, zip_size, is_encrypted, is_compressed);
|
||||
|
||||
if (is_corrupted) {
|
||||
fprintf(stderr, "Fail: page::%llu invalid\n",
|
||||
@@ -1477,7 +1464,7 @@ int verify_checksum(
|
||||
@param[in] filename File name
|
||||
@param[in] fil_in File pointer
|
||||
@param[in] buf page
|
||||
@param[in] page_size page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] pos File position
|
||||
@param[in] is_encrypted true if tablespace is encrypted
|
||||
@param[in] is_compressed true if tablespace is page compressed
|
||||
@@ -1488,7 +1475,7 @@ rewrite_checksum(
|
||||
const char* filename,
|
||||
FILE* fil_in,
|
||||
byte* buf,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
fpos_t* pos,
|
||||
bool is_encrypted,
|
||||
bool is_compressed)
|
||||
@@ -1500,8 +1487,7 @@ rewrite_checksum(
|
||||
!is_encrypted &&
|
||||
!is_compressed
|
||||
&& !write_file(filename, fil_in, buf,
|
||||
page_size.is_compressed(), pos,
|
||||
static_cast<ulong>(page_size.physical()))) {
|
||||
zip_size, pos)) {
|
||||
|
||||
exit_status = 1;
|
||||
}
|
||||
@@ -1682,22 +1668,19 @@ int main(
|
||||
|
||||
/* Determine page size, zip_size and page compression
|
||||
from fsp_flags and encryption metadata from page 0 */
|
||||
const page_size_t& page_size = get_page_size(buf);
|
||||
ulint zip_size = get_zip_size(buf);
|
||||
|
||||
ulint flags = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + buf);
|
||||
ulint zip_size = page_size.is_compressed() ? page_size.logical() : 0;
|
||||
logical_page_size = page_size.is_compressed() ? zip_size : 0;
|
||||
physical_page_size = page_size.physical();
|
||||
bool is_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(flags);
|
||||
|
||||
if (page_size.physical() > UNIV_ZIP_SIZE_MIN) {
|
||||
if (physical_page_size > UNIV_ZIP_SIZE_MIN) {
|
||||
/* Read rest of the page 0 to determine crypt_data */
|
||||
bytes = read_file(buf, partial_page_read, page_size.physical(), fil_in);
|
||||
if (bytes != page_size.physical()) {
|
||||
bytes = read_file(buf, partial_page_read, physical_page_size, fil_in);
|
||||
if (bytes != physical_page_size) {
|
||||
fprintf(stderr, "Error: Was not able to read the "
|
||||
"rest of the page ");
|
||||
fprintf(stderr, "of " ULINTPF " bytes. Bytes read was " ULINTPF "\n",
|
||||
page_size.physical() - UNIV_ZIP_SIZE_MIN, bytes);
|
||||
physical_page_size - UNIV_ZIP_SIZE_MIN, bytes);
|
||||
|
||||
exit_status = 1;
|
||||
goto my_exit;
|
||||
@@ -1706,7 +1689,7 @@ int main(
|
||||
}
|
||||
|
||||
/* Now that we have full page 0 in buffer, check encryption */
|
||||
bool is_encrypted = check_encryption(filename, page_size, buf);
|
||||
bool is_encrypted = check_encryption(filename, buf);
|
||||
|
||||
/* Verify page 0 contents. Note that we can't allow
|
||||
checksum mismatch on page 0, because that would mean we
|
||||
@@ -1715,7 +1698,7 @@ int main(
|
||||
unsigned long long tmp_allow_mismatches = allow_mismatches;
|
||||
allow_mismatches = 0;
|
||||
|
||||
exit_status = verify_checksum(buf, page_size, is_encrypted, is_compressed, &mismatch_count);
|
||||
exit_status = verify_checksum(buf, zip_size, is_encrypted, is_compressed, &mismatch_count);
|
||||
|
||||
if (exit_status) {
|
||||
fprintf(stderr, "Error: Page 0 checksum mismatch, can't continue. \n");
|
||||
@@ -1725,7 +1708,7 @@ int main(
|
||||
}
|
||||
|
||||
if ((exit_status = rewrite_checksum(filename, fil_in, buf,
|
||||
page_size, &pos, is_encrypted, is_compressed))) {
|
||||
zip_size, &pos, is_encrypted, is_compressed))) {
|
||||
goto my_exit;
|
||||
}
|
||||
|
||||
@@ -1748,10 +1731,10 @@ int main(
|
||||
}
|
||||
|
||||
if (page_type_summary || page_type_dump) {
|
||||
parse_page(buf, xdes, fil_page_type, page_size, is_encrypted);
|
||||
parse_page(buf, xdes, fil_page_type, is_encrypted);
|
||||
}
|
||||
|
||||
pages = (ulint) (size / page_size.physical());
|
||||
pages = (ulint) (size / physical_page_size);
|
||||
|
||||
if (just_count) {
|
||||
if (read_from_stdin) {
|
||||
@@ -1788,12 +1771,9 @@ int main(
|
||||
partial_page_read = false;
|
||||
|
||||
offset = (off_t) start_page
|
||||
* (off_t) page_size.physical();
|
||||
#ifdef _WIN32
|
||||
if (_fseeki64(fil_in, offset, SEEK_SET)) {
|
||||
#else
|
||||
if (fseeko(fil_in, offset, SEEK_SET)) {
|
||||
#endif /* _WIN32 */
|
||||
* (off_t) physical_page_size;
|
||||
if (IF_WIN(_fseeki64,fseeko)(fil_in, offset,
|
||||
SEEK_SET)) {
|
||||
perror("Error: Unable to seek to "
|
||||
"necessary offset");
|
||||
|
||||
@@ -1825,8 +1805,7 @@ int main(
|
||||
if partial_page_read is enable. */
|
||||
bytes = read_file(buf,
|
||||
partial_page_read,
|
||||
static_cast<ulong>(
|
||||
page_size.physical()),
|
||||
physical_page_size,
|
||||
fil_in);
|
||||
|
||||
partial_page_read = false;
|
||||
@@ -1851,8 +1830,7 @@ int main(
|
||||
while (!feof(fil_in)) {
|
||||
|
||||
bytes = read_file(buf, partial_page_read,
|
||||
static_cast<ulong>(
|
||||
page_size.physical()), fil_in);
|
||||
physical_page_size, fil_in);
|
||||
partial_page_read = false;
|
||||
|
||||
if (!bytes && feof(fil_in)) {
|
||||
@@ -1861,17 +1839,17 @@ int main(
|
||||
|
||||
if (ferror(fil_in)) {
|
||||
fprintf(stderr, "Error reading " ULINTPF " bytes",
|
||||
page_size.physical());
|
||||
physical_page_size);
|
||||
perror(" ");
|
||||
|
||||
exit_status = 1;
|
||||
goto my_exit;
|
||||
}
|
||||
|
||||
if (bytes != page_size.physical()) {
|
||||
if (bytes != physical_page_size) {
|
||||
fprintf(stderr, "Error: bytes read (" ULINTPF ") "
|
||||
"doesn't match page size (" ULINTPF ")\n",
|
||||
bytes, page_size.physical());
|
||||
bytes, physical_page_size);
|
||||
exit_status = 1;
|
||||
goto my_exit;
|
||||
}
|
||||
@@ -1896,13 +1874,13 @@ int main(
|
||||
checksum verification.*/
|
||||
if (!no_check
|
||||
&& !skip_page
|
||||
&& (exit_status = verify_checksum(buf, page_size,
|
||||
&& (exit_status = verify_checksum(buf, zip_size,
|
||||
is_encrypted, is_compressed, &mismatch_count))) {
|
||||
goto my_exit;
|
||||
}
|
||||
|
||||
if ((exit_status = rewrite_checksum(filename, fil_in, buf,
|
||||
page_size, &pos, is_encrypted, is_compressed))) {
|
||||
zip_size, &pos, is_encrypted, is_compressed))) {
|
||||
goto my_exit;
|
||||
}
|
||||
|
||||
@@ -1916,7 +1894,7 @@ int main(
|
||||
}
|
||||
|
||||
if (page_type_summary || page_type_dump) {
|
||||
parse_page(buf, xdes, fil_page_type, page_size, is_encrypted);
|
||||
parse_page(buf, xdes, fil_page_type, is_encrypted);
|
||||
}
|
||||
|
||||
/* do counter increase and progress printing */
|
||||
|
||||
@@ -231,11 +231,11 @@ xb_fil_cur_open(
|
||||
|
||||
posix_fadvise(cursor->file, 0, 0, POSIX_FADV_SEQUENTIAL);
|
||||
|
||||
const page_size_t page_size(node->space->flags);
|
||||
cursor->page_size = page_size;
|
||||
cursor->page_size = node->space->physical_size();
|
||||
cursor->zip_size = node->space->zip_size();
|
||||
|
||||
/* Allocate read buffer */
|
||||
cursor->buf_size = XB_FIL_CUR_PAGES * page_size.physical();
|
||||
cursor->buf_size = XB_FIL_CUR_PAGES * cursor->page_size;
|
||||
cursor->orig_buf = static_cast<byte *>
|
||||
(malloc(cursor->buf_size + srv_page_size));
|
||||
cursor->buf = static_cast<byte *>
|
||||
@@ -250,18 +250,17 @@ xb_fil_cur_open(
|
||||
if (!node->space->crypt_data
|
||||
&& os_file_read(IORequestRead,
|
||||
node->handle, cursor->buf, 0,
|
||||
page_size.physical())) {
|
||||
cursor->page_size)) {
|
||||
mutex_enter(&fil_system.mutex);
|
||||
if (!node->space->crypt_data) {
|
||||
node->space->crypt_data
|
||||
= fil_space_read_crypt_data(page_size,
|
||||
cursor->buf);
|
||||
node->space->crypt_data = fil_space_read_crypt_data(
|
||||
node->space->zip_size(), cursor->buf);
|
||||
}
|
||||
mutex_exit(&fil_system.mutex);
|
||||
}
|
||||
|
||||
cursor->space_size = (ulint)(cursor->statinfo.st_size
|
||||
/ page_size.physical());
|
||||
/ cursor->page_size);
|
||||
|
||||
cursor->read_filter = read_filter;
|
||||
cursor->read_filter->init(&cursor->read_filter_ctxt, cursor,
|
||||
@@ -276,7 +275,7 @@ static bool page_is_corrupted(const byte *page, ulint page_no,
|
||||
{
|
||||
byte tmp_frame[UNIV_PAGE_SIZE_MAX];
|
||||
byte tmp_page[UNIV_PAGE_SIZE_MAX];
|
||||
const ulint page_size = cursor->page_size.physical();
|
||||
const ulint page_size = cursor->page_size;
|
||||
ulint page_type = mach_read_from_2(page + FIL_PAGE_TYPE);
|
||||
|
||||
/* We ignore the doublewrite buffer pages.*/
|
||||
@@ -325,7 +324,7 @@ static bool page_is_corrupted(const byte *page, ulint page_no,
|
||||
|| (space->crypt_data
|
||||
&& space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED))) {
|
||||
|
||||
if (!fil_space_verify_crypt_checksum(page, cursor->page_size))
|
||||
if (!fil_space_verify_crypt_checksum(page, space->zip_size()))
|
||||
return true;
|
||||
|
||||
/* Compressed encrypted need to be decrypted
|
||||
@@ -345,8 +344,7 @@ static bool page_is_corrupted(const byte *page, ulint page_no,
|
||||
}
|
||||
|
||||
if (page_type != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) {
|
||||
return buf_page_is_corrupted(true, tmp_page,
|
||||
cursor->page_size, space);
|
||||
return buf_page_is_corrupted(true, tmp_page, 0, space);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,14 +359,14 @@ static bool page_is_corrupted(const byte *page, ulint page_no,
|
||||
|
||||
return (!decomp
|
||||
|| (decomp != srv_page_size
|
||||
&& cursor->page_size.is_compressed())
|
||||
&& cursor->zip_size)
|
||||
|| page_type == FIL_PAGE_PAGE_COMPRESSED
|
||||
|| page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
|
||||
|| buf_page_is_corrupted(true, tmp_page,
|
||||
cursor->page_size, space));
|
||||
space->zip_size(), space));
|
||||
}
|
||||
|
||||
return buf_page_is_corrupted(true, page, cursor->page_size, space);
|
||||
return buf_page_is_corrupted(true, page, space->zip_size(), space);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
@@ -389,7 +387,7 @@ xb_fil_cur_read(
|
||||
xb_fil_cur_result_t ret;
|
||||
ib_int64_t offset;
|
||||
ib_int64_t to_read;
|
||||
const ulint page_size = cursor->page_size.physical();
|
||||
const ulint page_size = cursor->page_size;
|
||||
xb_ad(!cursor->is_system() || page_size == srv_page_size);
|
||||
|
||||
cursor->read_filter->get_next_batch(&cursor->read_filter_ctxt,
|
||||
@@ -459,7 +457,7 @@ read_retry:
|
||||
"10 retries. File %s seems to be "
|
||||
"corrupted.", cursor->abs_path);
|
||||
ret = XB_FIL_CUR_ERROR;
|
||||
buf_page_print(page, cursor->page_size);
|
||||
ut_print_buf(stderr, page, page_size);
|
||||
break;
|
||||
}
|
||||
msg(cursor->thread_n, "Database page corruption detected at page "
|
||||
|
||||
@@ -38,7 +38,9 @@ struct xb_fil_cur_t {
|
||||
char abs_path[FN_REFLEN];
|
||||
/*!< absolute file path */
|
||||
MY_STAT statinfo; /*!< information about the file */
|
||||
page_size_t page_size; /*!< page size */
|
||||
ulint zip_size; /*!< compressed page size in bytes or 0
|
||||
for uncompressed pages */
|
||||
ulint page_size; /*!< physical page size */
|
||||
xb_read_filt_t* read_filter; /*!< read filter */
|
||||
xb_read_filt_ctxt_t read_filter_ctxt;
|
||||
/*!< read filter context */
|
||||
@@ -57,9 +59,6 @@ struct xb_fil_cur_t {
|
||||
ulint space_id; /*!< ID of tablespace */
|
||||
ulint space_size; /*!< space size in pages */
|
||||
|
||||
/** TODO: remove this default constructor */
|
||||
xb_fil_cur_t() : page_size(0), read_filter(0), read_filter_ctxt() {}
|
||||
|
||||
/** @return whether this is not a file-per-table tablespace */
|
||||
bool is_system() const
|
||||
{
|
||||
|
||||
@@ -127,7 +127,7 @@ rf_bitmap_get_next_batch(
|
||||
of pages */
|
||||
{
|
||||
ulint start_page_id;
|
||||
const ulint page_size = ctxt->page_size.physical();
|
||||
const ulint page_size = ctxt->page_size;
|
||||
|
||||
start_page_id = (ulint)(ctxt->offset / page_size);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ struct xb_read_filt_ctxt_t {
|
||||
/* Move these to union if any other filters are added in future */
|
||||
xb_page_bitmap_range *bitmap_range; /*!< changed page bitmap range
|
||||
iterator for space_id */
|
||||
page_size_t page_size; /*!< page size */
|
||||
ulint page_size; /*!< page size */
|
||||
ulint filter_batch_end;/*!< the ending page id of the
|
||||
current changed page block in
|
||||
the bitmap */
|
||||
|
||||
@@ -75,8 +75,7 @@ wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
||||
ctxt->cursor = cursor;
|
||||
|
||||
/* allocate buffer for incremental backup (4096 pages) */
|
||||
cp->delta_buf_size = (cursor->page_size.physical() / 4)
|
||||
* cursor->page_size.physical();
|
||||
cp->delta_buf_size = (cursor->page_size / 4) * cursor->page_size;
|
||||
cp->delta_buf = (unsigned char *)os_mem_alloc_large(&cp->delta_buf_size);
|
||||
|
||||
if (!cp->delta_buf) {
|
||||
@@ -88,7 +87,8 @@ wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
|
||||
/* write delta meta info */
|
||||
snprintf(meta_name, sizeof(meta_name), "%s%s", dst_name,
|
||||
XB_DELTA_INFO_SUFFIX);
|
||||
const xb_delta_info_t info(cursor->page_size, cursor->space_id);
|
||||
const xb_delta_info_t info(cursor->page_size, cursor->zip_size,
|
||||
cursor->space_id);
|
||||
if (!xb_write_delta_metadata(meta_name, &info)) {
|
||||
msg(cursor->thread_n,"Error: "
|
||||
"failed to write meta info for %s",
|
||||
@@ -116,8 +116,7 @@ wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
|
||||
ulint i;
|
||||
xb_fil_cur_t *cursor = ctxt->cursor;
|
||||
byte *page;
|
||||
const ulint page_size
|
||||
= cursor->page_size.physical();
|
||||
const ulint page_size = cursor->page_size;
|
||||
xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt);
|
||||
|
||||
for (i = 0, page = cursor->buf; i < cursor->buf_npages;
|
||||
@@ -162,8 +161,7 @@ static my_bool
|
||||
wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
|
||||
{
|
||||
xb_fil_cur_t *cursor = ctxt->cursor;
|
||||
const ulint page_size
|
||||
= cursor->page_size.physical();
|
||||
const ulint page_size = cursor->page_size;
|
||||
xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt);
|
||||
|
||||
if (cp->npages != page_size / 4) {
|
||||
|
||||
@@ -1861,11 +1861,6 @@ static bool innodb_init_param()
|
||||
msg("innodb_data_file_path = %s",
|
||||
innobase_data_file_path);
|
||||
|
||||
/* This is the first time univ_page_size is used.
|
||||
It was initialized to 16k pages before srv_page_size was set */
|
||||
univ_page_size.copy_from(
|
||||
page_size_t(srv_page_size, srv_page_size, false));
|
||||
|
||||
srv_sys_space.set_space_id(TRX_SYS_SPACE);
|
||||
srv_sys_space.set_name("innodb_system");
|
||||
srv_sys_space.set_path(srv_data_home);
|
||||
@@ -2173,8 +2168,7 @@ xb_read_delta_metadata(const char *filepath, xb_delta_info_t *info)
|
||||
msg("page_size is required in %s", filepath);
|
||||
r = FALSE;
|
||||
} else {
|
||||
info->page_size = page_size_t(zip_size ? zip_size : page_size,
|
||||
page_size, zip_size != 0);
|
||||
info->page_size = zip_size ? zip_size : page_size;
|
||||
}
|
||||
|
||||
if (info->space_id == ULINT_UNDEFINED) {
|
||||
@@ -2202,9 +2196,8 @@ xb_write_delta_metadata(const char *filename, const xb_delta_info_t *info)
|
||||
"page_size = " ULINTPF "\n"
|
||||
"zip_size = " ULINTPF " \n"
|
||||
"space_id = " ULINTPF "\n",
|
||||
info->page_size.logical(),
|
||||
info->page_size.is_compressed()
|
||||
? info->page_size.physical() : 0,
|
||||
info->page_size,
|
||||
info->zip_size,
|
||||
info->space_id);
|
||||
len = strlen(buf);
|
||||
|
||||
@@ -3107,7 +3100,7 @@ xb_load_single_table_tablespace(
|
||||
|
||||
ut_a(node_size != (os_offset_t) -1);
|
||||
|
||||
n_pages = node_size / page_size_t(file->flags()).physical();
|
||||
n_pages = node_size / fil_space_t::physical_size(file->flags());
|
||||
|
||||
space = fil_space_create(
|
||||
name, file->space_id(), file->flags(),
|
||||
@@ -3312,7 +3305,7 @@ retry:
|
||||
}
|
||||
|
||||
/* TRX_SYS page can't be compressed or encrypted. */
|
||||
if (buf_page_is_corrupted(false, page, univ_page_size)) {
|
||||
if (buf_page_is_corrupted(false, page, 0)) {
|
||||
if (n_retries--) {
|
||||
os_thread_sleep(1000);
|
||||
goto retry;
|
||||
@@ -4590,16 +4583,15 @@ xb_space_create_file(
|
||||
fsp_header_init_fields(page, space_id, flags);
|
||||
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
|
||||
|
||||
const page_size_t page_size(flags);
|
||||
const ulint zip_size = fil_space_t::zip_size(flags);
|
||||
|
||||
if (!page_size.is_compressed()) {
|
||||
if (!zip_size) {
|
||||
buf_flush_init_for_writing(NULL, page, NULL, 0);
|
||||
|
||||
ret = os_file_write(IORequestWrite, path, *file, page, 0,
|
||||
srv_page_size);
|
||||
} else {
|
||||
page_zip_des_t page_zip;
|
||||
ulint zip_size = page_size.physical();
|
||||
page_zip_set_size(&page_zip, zip_size);
|
||||
page_zip.data = page + srv_page_size;
|
||||
fprintf(stderr, "zip_size = " ULINTPF "\n", zip_size);
|
||||
@@ -4776,19 +4768,20 @@ exit:
|
||||
}
|
||||
|
||||
/* No matching space found. create the new one. */
|
||||
const ulint flags = info.page_size.is_compressed()
|
||||
? get_bit_shift(info.page_size.physical()
|
||||
const ulint flags = info.zip_size
|
||||
? get_bit_shift(info.page_size
|
||||
>> (UNIV_ZIP_SIZE_SHIFT_MIN - 1))
|
||||
<< FSP_FLAGS_POS_ZIP_SSIZE
|
||||
| FSP_FLAGS_MASK_POST_ANTELOPE
|
||||
| FSP_FLAGS_MASK_ATOMIC_BLOBS
|
||||
| (info.page_size.logical() == UNIV_PAGE_SIZE_ORIG
|
||||
| (srv_page_size == UNIV_PAGE_SIZE_ORIG
|
||||
? 0
|
||||
: get_bit_shift(info.page_size.logical()
|
||||
: get_bit_shift(srv_page_size
|
||||
>> (UNIV_ZIP_SIZE_SHIFT_MIN - 1))
|
||||
<< FSP_FLAGS_POS_PAGE_SSIZE)
|
||||
: FSP_FLAGS_PAGE_SSIZE();
|
||||
ut_ad(page_size_t(flags).equals_to(info.page_size));
|
||||
ut_ad(fil_space_t::zip_size(flags) == info.zip_size);
|
||||
ut_ad(fil_space_t::physical_size(flags) == info.page_size);
|
||||
|
||||
if (fil_space_create(dest_space_name, info.space_id, flags,
|
||||
FIL_TYPE_TABLESPACE, 0)) {
|
||||
@@ -4825,7 +4818,7 @@ xtrabackup_apply_delta(
|
||||
ulint page_in_buffer;
|
||||
ulint incremental_buffers = 0;
|
||||
|
||||
xb_delta_info_t info(univ_page_size, SRV_TMP_SPACE_ID);
|
||||
xb_delta_info_t info(srv_page_size, 0, SRV_TMP_SPACE_ID);
|
||||
ulint page_size;
|
||||
ulint page_size_shift;
|
||||
byte* incremental_buffer_base = NULL;
|
||||
@@ -4863,7 +4856,7 @@ xtrabackup_apply_delta(
|
||||
goto error;
|
||||
}
|
||||
|
||||
page_size = info.page_size.physical();
|
||||
page_size = info.page_size;
|
||||
page_size_shift = get_bit_shift(page_size);
|
||||
msg("page size for %s is %zu bytes",
|
||||
src_path, page_size);
|
||||
|
||||
@@ -28,11 +28,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
struct xb_delta_info_t
|
||||
{
|
||||
xb_delta_info_t(page_size_t page_size, ulint space_id)
|
||||
: page_size(page_size), space_id(space_id) {}
|
||||
xb_delta_info_t(ulint page_size, ulint zip_size, ulint space_id)
|
||||
: page_size(page_size), zip_size(zip_size), space_id(space_id) {}
|
||||
|
||||
page_size_t page_size;
|
||||
ulint space_id;
|
||||
ulint page_size;
|
||||
ulint zip_size;
|
||||
ulint space_id;
|
||||
};
|
||||
|
||||
/* value of the --incremental option */
|
||||
|
||||
@@ -123,6 +123,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
|
||||
../sql/sql_tvc.cc ../sql/sql_tvc.h
|
||||
../sql/opt_split.cc
|
||||
../sql/item_vers.cc
|
||||
../sql/opt_trace.cc
|
||||
${GEN_SOURCES}
|
||||
${MYSYS_LIBWRAP_SOURCE}
|
||||
)
|
||||
|
||||
@@ -8,6 +8,6 @@ flush privileges;
|
||||
connect(localhost,USER,,test,MASTER_PORT,MASTER_SOCKET);
|
||||
ERROR 28000: Access denied for user 'USER'@'localhost'
|
||||
ERROR 28000: Access denied for user 'USER'@'localhost'
|
||||
update mysql.global_priv set priv=json_remove(priv, '$.plugin');
|
||||
update mysql.global_priv set priv=json_compact(json_remove(priv, '$.plugin'));
|
||||
flush privileges;
|
||||
uninstall plugin unix_socket;
|
||||
|
||||
@@ -36,7 +36,7 @@ connect (fail,localhost,$USER);
|
||||
--error ER_ACCESS_DENIED_NO_PASSWORD_ERROR
|
||||
change_user $USER;
|
||||
|
||||
update mysql.global_priv set priv=json_remove(priv, '$.plugin');
|
||||
update mysql.global_priv set priv=json_compact(json_remove(priv, '$.plugin'));
|
||||
flush privileges;
|
||||
uninstall plugin unix_socket;
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ GLOBAL_VARIABLES
|
||||
INDEX_STATISTICS
|
||||
KEY_CACHES
|
||||
KEY_COLUMN_USAGE
|
||||
OPTIMIZER_TRACE
|
||||
PARAMETERS
|
||||
PARTITIONS
|
||||
PLUGINS
|
||||
@@ -864,6 +865,8 @@ information_schema COLUMNS COLUMN_DEFAULT
|
||||
information_schema COLUMNS COLUMN_TYPE
|
||||
information_schema COLUMNS GENERATION_EXPRESSION
|
||||
information_schema EVENTS EVENT_DEFINITION
|
||||
information_schema OPTIMIZER_TRACE QUERY
|
||||
information_schema OPTIMIZER_TRACE TRACE
|
||||
information_schema PARAMETERS DTD_IDENTIFIER
|
||||
information_schema PARTITIONS PARTITION_EXPRESSION
|
||||
information_schema PARTITIONS SUBPARTITION_EXPRESSION
|
||||
|
||||
@@ -43,6 +43,7 @@ INNODB_TABLESPACES_SCRUBBING
|
||||
INNODB_TRX
|
||||
KEY_CACHES
|
||||
KEY_COLUMN_USAGE
|
||||
OPTIMIZER_TRACE
|
||||
PARAMETERS
|
||||
PARTITIONS
|
||||
PLUGINS
|
||||
@@ -123,6 +124,7 @@ INNODB_TABLESPACES_SCRUBBING SPACE
|
||||
INNODB_TRX trx_id
|
||||
KEY_CACHES KEY_CACHE_NAME
|
||||
KEY_COLUMN_USAGE CONSTRAINT_SCHEMA
|
||||
OPTIMIZER_TRACE QUERY
|
||||
PARAMETERS SPECIFIC_SCHEMA
|
||||
PARTITIONS TABLE_SCHEMA
|
||||
PLUGINS PLUGIN_NAME
|
||||
@@ -203,6 +205,7 @@ INNODB_TABLESPACES_SCRUBBING SPACE
|
||||
INNODB_TRX trx_id
|
||||
KEY_CACHES KEY_CACHE_NAME
|
||||
KEY_COLUMN_USAGE CONSTRAINT_SCHEMA
|
||||
OPTIMIZER_TRACE QUERY
|
||||
PARAMETERS SPECIFIC_SCHEMA
|
||||
PARTITIONS TABLE_SCHEMA
|
||||
PLUGINS PLUGIN_NAME
|
||||
@@ -288,6 +291,7 @@ INNODB_TABLESPACES_SCRUBBING information_schema.INNODB_TABLESPACES_SCRUBBING 1
|
||||
INNODB_TRX information_schema.INNODB_TRX 1
|
||||
KEY_CACHES information_schema.KEY_CACHES 1
|
||||
KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1
|
||||
OPTIMIZER_TRACE information_schema.OPTIMIZER_TRACE 1
|
||||
PARAMETERS information_schema.PARAMETERS 1
|
||||
PARTITIONS information_schema.PARTITIONS 1
|
||||
PLUGINS information_schema.PLUGINS 1
|
||||
@@ -358,6 +362,7 @@ Database: information_schema
|
||||
| INNODB_TRX |
|
||||
| KEY_CACHES |
|
||||
| KEY_COLUMN_USAGE |
|
||||
| OPTIMIZER_TRACE |
|
||||
| PARAMETERS |
|
||||
| PARTITIONS |
|
||||
| PLUGINS |
|
||||
@@ -428,6 +433,7 @@ Database: INFORMATION_SCHEMA
|
||||
| INNODB_TRX |
|
||||
| KEY_CACHES |
|
||||
| KEY_COLUMN_USAGE |
|
||||
| OPTIMIZER_TRACE |
|
||||
| PARAMETERS |
|
||||
| PARTITIONS |
|
||||
| PLUGINS |
|
||||
@@ -459,5 +465,5 @@ Wildcard: inf_rmation_schema
|
||||
| information_schema |
|
||||
SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') GROUP BY TABLE_SCHEMA;
|
||||
table_schema count(*)
|
||||
information_schema 65
|
||||
information_schema 66
|
||||
mysql 31
|
||||
|
||||
@@ -63,6 +63,6 @@ test
|
||||
Phase 7/7: Running 'FLUSH PRIVILEGES'
|
||||
OK
|
||||
connect con1,localhost,root,foo,,,;
|
||||
update mysql.global_priv set priv=json_remove(priv, '$.plugin', '$.authentication_string');
|
||||
update mysql.global_priv set priv=json_compact(json_remove(priv, '$.plugin', '$.authentication_string'));
|
||||
flush privileges;
|
||||
set global event_scheduler=OFF;
|
||||
|
||||
@@ -17,7 +17,7 @@ update mysql.global_priv set priv=json_set(priv, '$.plugin', 'mysql_native_passw
|
||||
|
||||
connect(con1,localhost,root,foo,,,);
|
||||
|
||||
update mysql.global_priv set priv=json_remove(priv, '$.plugin', '$.authentication_string');
|
||||
update mysql.global_priv set priv=json_compact(json_remove(priv, '$.plugin', '$.authentication_string'));
|
||||
flush privileges;
|
||||
# Load event table
|
||||
set global event_scheduler=OFF;
|
||||
|
||||
@@ -693,6 +693,12 @@ The following specify which files/extra groups are read (specified before remain
|
||||
extended_keys, exists_to_in, orderby_uses_equalities,
|
||||
condition_pushdown_for_derived, split_materialized,
|
||||
condition_pushdown_for_subquery
|
||||
--optimizer-trace=name
|
||||
Controls tracing of the Optimizer:
|
||||
optimizer_trace=option=val[,option=val...], where option
|
||||
is one of {enabled} and val is one of {on, off, default}
|
||||
--optimizer-trace-max-mem-size=#
|
||||
Maximum allowed size of an optimizer trace
|
||||
--optimizer-use-condition-selectivity=#
|
||||
Controls selectivity of which conditions the optimizer
|
||||
takes into account to calculate cardinality of a partial
|
||||
@@ -1563,6 +1569,8 @@ optimizer-prune-level 1
|
||||
optimizer-search-depth 62
|
||||
optimizer-selectivity-sampling-limit 100
|
||||
optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on
|
||||
optimizer-trace
|
||||
optimizer-trace-max-mem-size 1048576
|
||||
optimizer-use-condition-selectivity 4
|
||||
performance-schema FALSE
|
||||
performance-schema-accounts-size -1
|
||||
|
||||
3499
mysql-test/main/opt_trace.result
Normal file
3499
mysql-test/main/opt_trace.result
Normal file
File diff suppressed because it is too large
Load Diff
335
mysql-test/main/opt_trace.test
Normal file
335
mysql-test/main/opt_trace.test
Normal file
@@ -0,0 +1,335 @@
|
||||
--source include/not_embedded.inc
|
||||
SELECT table_name, column_name FROM information_schema.columns where table_name="OPTIMIZER_TRACE";
|
||||
show variables like 'optimizer_trace';
|
||||
set optimizer_trace="enabled=on";
|
||||
show variables like 'optimizer_trace';
|
||||
set optimizer_trace="enabled=off";
|
||||
create table t1 (a int, b int);
|
||||
insert into t1 values (1,2),(2,3);
|
||||
|
||||
create table t2 (b int);
|
||||
insert into t2 values (1),(2);
|
||||
|
||||
analyze table t1;
|
||||
analyze table t2;
|
||||
create function f1 (a int) returns INT
|
||||
return 1;
|
||||
|
||||
create view v1 as select * from t1 where t1.a=1;
|
||||
create view v2 as select * from t1 where t1.a=1 group by t1.b;
|
||||
set optimizer_trace="enabled=on";
|
||||
|
||||
--echo # Mergeable views/derived tables
|
||||
select * from v1;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
select * from (select * from t1 where t1.a=1)q;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
|
||||
--echo # Non-Mergeable views
|
||||
select * from v2;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
|
||||
drop table t1,t2;
|
||||
drop view v1,v2;
|
||||
drop function f1;
|
||||
|
||||
create table t1(a int, b int);
|
||||
insert into t1 values (0,0),(1,1),(2,1),(3,2),(4,3),
|
||||
(5,3),(6,3),(7,3),(8,3),(9,3);
|
||||
create table t2(a int, b int);
|
||||
insert into t2 values (0,0),(1,1),(2,1),(3,2),(4,3),
|
||||
(5,3),(6,3),(7,3),(8,3),(9,3);
|
||||
|
||||
ANALYZE TABLE t1;
|
||||
ANALYZE TABLE t2;
|
||||
|
||||
create view v1 as select a from t1 group by b;
|
||||
create view v2 as select a from t2;
|
||||
|
||||
--echo # Mergeable view
|
||||
explain select * from v2 ;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
|
||||
--echo # Non-Mergeable view
|
||||
explain select * from v1 ;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
drop table t1,t2;
|
||||
drop view v1,v2;
|
||||
|
||||
--echo #
|
||||
--echo # print ref-keyues array
|
||||
--echo #
|
||||
|
||||
create table t0 (a int);
|
||||
INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
|
||||
create table t1 (a int, b int, c int, key(a));
|
||||
insert into t1 select A.a*10 + B.a, A.a*10 + B.a, A.a*10 + B.a from t0 A, t0 B;
|
||||
|
||||
create table t2(a int, b int, c int , key(a));
|
||||
insert into t2 select A.a*10 + B.a, A.a*10 + B.a, A.a*10 + B.a from t0 A, t0 B;
|
||||
|
||||
analyze table t1;
|
||||
analyze table t2;
|
||||
|
||||
explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
drop table t1,t2,t0;
|
||||
|
||||
--echo #
|
||||
--echo # group_by min max optimization
|
||||
--echo #
|
||||
CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, a INT NOT NULL, KEY(a));
|
||||
--disable_query_log
|
||||
INSERT INTO t1(a) VALUES (1), (2), (3), (4);
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
INSERT INTO t1(a) SELECT a FROM t1;
|
||||
--enable_query_log
|
||||
|
||||
analyze table t1;
|
||||
EXPLAIN SELECT DISTINCT a FROM t1;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # With group by , where clause and MIN/MAX function
|
||||
--echo #
|
||||
CREATE TABLE t1 (a INT, b INT, c int, d int, KEY(a,b,c,d));
|
||||
INSERT INTO t1 VALUES (1,1,1,1), (2,2,2,2), (3,3,3,3), (4,4,4,4), (1,0,1,1), (3,2,3,3), (4,5,4,4);
|
||||
ANALYZE TABLE t1;
|
||||
EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (id INT NOT NULL, a DATE, KEY(id,a));
|
||||
INSERT INTO t1 values (1,'2001-01-01'),(1,'2001-01-02'),
|
||||
(1,'2001-01-03'),(1,'2001-01-04'),
|
||||
(2,'2001-01-01'),(2,'2001-01-02'),
|
||||
(2,'2001-01-03'),(2,'2001-01-04'),
|
||||
(3,'2001-01-01'),(3,'2001-01-02'),
|
||||
(3,'2001-01-03'),(3,'2001-01-04'),
|
||||
(4,'2001-01-01'),(4,'2001-01-02'),
|
||||
(4,'2001-01-03'),(4,'2001-01-04');
|
||||
set optimizer_trace='enabled=on';
|
||||
EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # Late ORDER BY optimization
|
||||
--echo #
|
||||
|
||||
create table ten(a int);
|
||||
insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table one_k(a int primary key);
|
||||
insert into one_k select A.a + B.a* 10 + C.a * 100 from ten A, ten B, ten C;
|
||||
create table t1 (
|
||||
pk int not null,
|
||||
a int,
|
||||
b int,
|
||||
c int,
|
||||
filler char(100),
|
||||
KEY a_a(c),
|
||||
KEY a_c(a,c),
|
||||
KEY a_b(a,b)
|
||||
);
|
||||
|
||||
insert into t1
|
||||
select a, a,a,a, 'filler-dataaa' from test.one_k;
|
||||
update t1 set a=1 where pk between 0 and 180;
|
||||
update t1 set b=2 where pk between 0 and 20;
|
||||
analyze table t1;
|
||||
set optimizer_trace='enabled=on';
|
||||
explain select * from t1 where a=1 and b=2 order by c limit 1;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
drop table t1,ten,one_k;
|
||||
|
||||
--echo #
|
||||
--echo # TABLE ELIMINATION
|
||||
--echo #
|
||||
|
||||
create table t1 (a int);
|
||||
insert into t1 values (0),(1),(2),(3);
|
||||
create table t0 as select * from t1;
|
||||
|
||||
create table t2 (a int primary key, b int)
|
||||
as select a, a as b from t1 where a in (1,2);
|
||||
|
||||
create table t3 (a int primary key, b int)
|
||||
as select a, a as b from t1 where a in (1,3);
|
||||
|
||||
set optimizer_trace='enabled=on';
|
||||
|
||||
analyze table t1;
|
||||
analyze table t2;
|
||||
analyze table t3;
|
||||
|
||||
--echo # table t2 should be eliminated
|
||||
explain
|
||||
select t1.a from t1 left join t2 on t1.a=t2.a;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
|
||||
--echo # no tables should be eliminated
|
||||
explain select * from t1 left join t2 on t2.a=t1.a;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
|
||||
--echo # multiple tables are eliminated
|
||||
explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and t3.a=t1.a;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
drop table t0, t1, t2, t3;
|
||||
|
||||
--echo #
|
||||
--echo # IN subquery to sem-join is traced
|
||||
--echo #
|
||||
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
|
||||
create table t1(a int, b int);
|
||||
insert into t1 values (0,0),(1,1),(2,2);
|
||||
create table t2 as select * from t1;
|
||||
|
||||
create table t11(a int, b int);
|
||||
|
||||
create table t10 (pk int, a int);
|
||||
insert into t10 select a,a from t0;
|
||||
create table t12 like t10;
|
||||
insert into t12 select * from t10;
|
||||
|
||||
analyze table t1,t10;
|
||||
|
||||
set optimizer_trace='enabled=on';
|
||||
explain extended select * from t1 where a in (select pk from t10);
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
drop table t0,t1,t11,t10,t12,t2;
|
||||
|
||||
--echo #
|
||||
--echo # Selectivities for columns and indexes.
|
||||
--echo #
|
||||
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
|
||||
create table t1 (
|
||||
pk int,
|
||||
a int,
|
||||
b int,
|
||||
key pk(pk),
|
||||
key pk_a(pk,a),
|
||||
key pk_a_b(pk,a,b));
|
||||
insert into t1 select a,a,a from t0;
|
||||
|
||||
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS (a,b) INDEXES ();
|
||||
set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
|
||||
set @save_use_stat_tables= @@use_stat_tables;
|
||||
set @@optimizer_use_condition_selectivity=4;
|
||||
set @@use_stat_tables= PREFERABLY;
|
||||
set optimizer_trace='enabled=on';
|
||||
explain select * from t1 where pk = 2 and a=5 and b=1;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
|
||||
set @@use_stat_tables= @save_use_stat_tables;
|
||||
drop table t0,t1;
|
||||
set optimizer_trace="enabled=off";
|
||||
|
||||
--echo #
|
||||
--echo # Tests added to show that sub-statements are not traced
|
||||
--echo #
|
||||
|
||||
create table t1(a int);
|
||||
insert into t1 values (1),(2),(3),(4);
|
||||
create table t2(a int);
|
||||
insert into t2 values (1),(2),(3),(4);
|
||||
delimiter |;
|
||||
create function f1(a int) returns int
|
||||
begin
|
||||
declare a int default 0;
|
||||
set a= a+ (select count(*) from t2);
|
||||
return a;
|
||||
end|
|
||||
|
||||
create function f2(a int) returns int
|
||||
begin
|
||||
declare a int default 0;
|
||||
select count(*) from t2 into a;
|
||||
return a;
|
||||
end|
|
||||
|
||||
delimiter ;|
|
||||
set optimizer_trace='enabled=on';
|
||||
select f1(a) from t1;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
select f2(a) from t1;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
drop table t1,t2;
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
set optimizer_trace='enabled=off';
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-18489: Limit the memory used by the optimizer trace
|
||||
--echo #
|
||||
|
||||
create table t1 (a int);
|
||||
insert into t1 values (1),(2);
|
||||
|
||||
set optimizer_trace='enabled=on';
|
||||
set @save_optimizer_trace_max_mem_size= @@optimizer_trace_max_mem_size;
|
||||
select * from t1;
|
||||
select length(trace) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
|
||||
set optimizer_trace_max_mem_size=100;
|
||||
select * from t1;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
|
||||
set optimizer_trace_max_mem_size=0;
|
||||
select * from t1;
|
||||
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
||||
drop table t1;
|
||||
set optimizer_trace='enabled=off';
|
||||
set @@optimizer_trace_max_mem_size= @save_optimizer_trace_max_mem_size;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-18527: Optimizer trace for DELETE query shows table:null
|
||||
--echo #
|
||||
|
||||
create table ten(a int);
|
||||
insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t0 (a int, b int);
|
||||
insert into t0 select a,a from ten;
|
||||
alter table t0 add key(a);
|
||||
|
||||
set optimizer_trace=1;
|
||||
explain delete from t0 where t0.a<3;
|
||||
select * from information_schema.optimizer_trace;
|
||||
drop table ten,t0;
|
||||
set optimizer_trace='enabled=off';
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-18528: Optimizer trace support for multi-table UPDATE and DELETE
|
||||
--echo #
|
||||
|
||||
create table ten(a int);
|
||||
insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t0 (a int, b int);
|
||||
insert into t0 select a,a from ten;
|
||||
alter table t0 add key(a);
|
||||
create table t1 like t0;
|
||||
insert into t1 select * from t0;
|
||||
explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3;
|
||||
select * from information_schema.optimizer_trace;
|
||||
drop table ten,t0,t1;
|
||||
249
mysql-test/main/opt_trace_index_merge.result
Normal file
249
mysql-test/main/opt_trace_index_merge.result
Normal file
@@ -0,0 +1,249 @@
|
||||
set @tmp_opt_switch= @@optimizer_switch;
|
||||
set optimizer_switch='index_merge_sort_intersection=on';
|
||||
set optimizer_trace='enabled=on';
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (a int, b int, c int, filler char(100),
|
||||
key(a), key(b), key(c));
|
||||
insert into t1 select
|
||||
A.a * B.a*10 + C.a*100,
|
||||
A.a * B.a*10 + C.a*100,
|
||||
A.a,
|
||||
'filler'
|
||||
from t0 A, t0 B, t0 C;
|
||||
This should use union:
|
||||
explain select * from t1 where a=1 or b=1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index_merge a,b a,b 5,5 NULL 2 Using union(a,b); Using where
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
|
||||
explain select * from t1 where a=1 or b=1 {
|
||||
"steps": [
|
||||
{
|
||||
"join_preparation": {
|
||||
"select_id": 1,
|
||||
"steps": [
|
||||
{
|
||||
"expanded_query": "select `t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`c` AS `c`,`t1`.`filler` AS `filler` from `t1` where `t1`.`a` = 1 or `t1`.`b` = 1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_optimization": {
|
||||
"select_id": 1,
|
||||
"steps": [
|
||||
{
|
||||
"condition_processing": {
|
||||
"condition": "WHERE",
|
||||
"original_condition": "t1.a = 1 or t1.b = 1",
|
||||
"steps": [
|
||||
{
|
||||
"transformation": "equality_propagation",
|
||||
"resulting_condition": "multiple equal(1, t1.a) or multiple equal(1, t1.b)"
|
||||
},
|
||||
{
|
||||
"transformation": "constant_propagation",
|
||||
"resulting_condition": "multiple equal(1, t1.a) or multiple equal(1, t1.b)"
|
||||
},
|
||||
{
|
||||
"transformation": "trivial_condition_removal",
|
||||
"resulting_condition": "multiple equal(1, t1.a) or multiple equal(1, t1.b)"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"table_dependencies": [
|
||||
{
|
||||
"table": "t1",
|
||||
"row_may_be_null": false,
|
||||
"map_bit": 0,
|
||||
"depends_on_map_bits": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref_optimizer_key_uses": []
|
||||
},
|
||||
{
|
||||
"rows_estimation": [
|
||||
{
|
||||
"table": "t1",
|
||||
"range_analysis": {
|
||||
"table_scan": {
|
||||
"rows": 1000,
|
||||
"cost": 231.69
|
||||
},
|
||||
"potential_range_indexes": [
|
||||
{
|
||||
"index": "a",
|
||||
"usable": true,
|
||||
"key_parts": ["a"]
|
||||
},
|
||||
{
|
||||
"index": "b",
|
||||
"usable": true,
|
||||
"key_parts": ["b"]
|
||||
},
|
||||
{
|
||||
"index": "c",
|
||||
"usable": false,
|
||||
"cause": "not applicable"
|
||||
}
|
||||
],
|
||||
"setup_range_conditions": [],
|
||||
"group_index_range": {
|
||||
"chosen": false,
|
||||
"cause": "no group by or distinct"
|
||||
},
|
||||
"analyzing_range_alternatives": {
|
||||
"range_scan_alternatives": [],
|
||||
"analyzing_roworder_intersect": {
|
||||
"cause": "too few roworder scans"
|
||||
},
|
||||
"analyzing_sort_intersect": {},
|
||||
"analyzing_index_merge_union": [
|
||||
{
|
||||
"indexes_to_merge": [
|
||||
{
|
||||
"range_scan_alternatives": [
|
||||
{
|
||||
"index": "a",
|
||||
"ranges": ["1 <= a <= 1"],
|
||||
"rowid_ordered": true,
|
||||
"using_mrr": false,
|
||||
"index_only": true,
|
||||
"rows": 1,
|
||||
"cost": 2.21,
|
||||
"chosen": true
|
||||
}
|
||||
],
|
||||
"index_to_merge": "a",
|
||||
"cumulated_cost": 2.21
|
||||
},
|
||||
{
|
||||
"range_scan_alternatives": [
|
||||
{
|
||||
"index": "b",
|
||||
"ranges": ["1 <= b <= 1"],
|
||||
"rowid_ordered": true,
|
||||
"using_mrr": false,
|
||||
"index_only": true,
|
||||
"rows": 1,
|
||||
"cost": 2.21,
|
||||
"chosen": true
|
||||
}
|
||||
],
|
||||
"index_to_merge": "b",
|
||||
"cumulated_cost": 4.42
|
||||
}
|
||||
],
|
||||
"cost_of_reading_ranges": 4.42,
|
||||
"use_roworder_union": true,
|
||||
"cause": "always cheaper than non roworder retrieval",
|
||||
"analyzing_roworder_scans": [
|
||||
{
|
||||
"type": "range_scan",
|
||||
"index": "a",
|
||||
"rows": 1,
|
||||
"ranges": ["1 <= a <= 1"],
|
||||
"analyzing_roworder_intersect": {
|
||||
"cause": "too few roworder scans"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "range_scan",
|
||||
"index": "b",
|
||||
"rows": 1,
|
||||
"ranges": ["1 <= b <= 1"],
|
||||
"analyzing_roworder_intersect": {
|
||||
"cause": "too few roworder scans"
|
||||
}
|
||||
}
|
||||
],
|
||||
"index_roworder_union_cost": 6.2137,
|
||||
"members": 2,
|
||||
"chosen": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"chosen_range_access_summary": {
|
||||
"range_access_plan": {
|
||||
"type": "index_roworder_union",
|
||||
"union_of": [
|
||||
{
|
||||
"type": "range_scan",
|
||||
"index": "a",
|
||||
"rows": 1,
|
||||
"ranges": ["1 <= a <= 1"]
|
||||
},
|
||||
{
|
||||
"type": "range_scan",
|
||||
"index": "b",
|
||||
"rows": 1,
|
||||
"ranges": ["1 <= b <= 1"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rows_for_plan": 2,
|
||||
"cost_for_plan": 6.2137,
|
||||
"chosen": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"selectivity_for_indexes": [],
|
||||
"selectivity_for_columns": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"execution_plan_for_potential_materialization": {
|
||||
"steps": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"considered_execution_plans": [
|
||||
{
|
||||
"plan_prefix": [],
|
||||
"table": "t1",
|
||||
"best_access_path": {
|
||||
"considered_access_paths": [
|
||||
{
|
||||
"access_type": "range",
|
||||
"resulting_rows": 2,
|
||||
"cost": 6.2137,
|
||||
"chosen": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attaching_conditions_to_tables": {
|
||||
"original_condition": "t1.a = 1 or t1.b = 1",
|
||||
"attached_conditions_computation": [],
|
||||
"attached_conditions_summary": [
|
||||
{
|
||||
"table": "t1",
|
||||
"attached": "t1.a = 1 or t1.b = 1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_execution": {
|
||||
"select_id": 1,
|
||||
"steps": []
|
||||
}
|
||||
}
|
||||
]
|
||||
} 0 0
|
||||
drop table t0,t1;
|
||||
set optimizer_trace="enabled=off";
|
||||
set @@optimizer_switch= @tmp_opt_switch;
|
||||
21
mysql-test/main/opt_trace_index_merge.test
Normal file
21
mysql-test/main/opt_trace_index_merge.test
Normal file
@@ -0,0 +1,21 @@
|
||||
--source include/not_embedded.inc
|
||||
set @tmp_opt_switch= @@optimizer_switch;
|
||||
set optimizer_switch='index_merge_sort_intersection=on';
|
||||
set optimizer_trace='enabled=on';
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (a int, b int, c int, filler char(100),
|
||||
key(a), key(b), key(c));
|
||||
insert into t1 select
|
||||
A.a * B.a*10 + C.a*100,
|
||||
A.a * B.a*10 + C.a*100,
|
||||
A.a,
|
||||
'filler'
|
||||
from t0 A, t0 B, t0 C;
|
||||
|
||||
--echo This should use union:
|
||||
explain select * from t1 where a=1 or b=1;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
drop table t0,t1;
|
||||
set optimizer_trace="enabled=off";
|
||||
set @@optimizer_switch= @tmp_opt_switch;
|
||||
242
mysql-test/main/opt_trace_index_merge_innodb.result
Normal file
242
mysql-test/main/opt_trace_index_merge_innodb.result
Normal file
@@ -0,0 +1,242 @@
|
||||
create table t1
|
||||
(
|
||||
pk1 int not null,
|
||||
pk2 int not null,
|
||||
key1 int not null,
|
||||
key2 int not null,
|
||||
key (key1),
|
||||
key (key2),
|
||||
primary key (pk1, pk2)
|
||||
)engine=Innodb;
|
||||
analyze table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status Engine-independent statistics collected
|
||||
test.t1 analyze status OK
|
||||
set optimizer_trace="enabled=on";
|
||||
set @tmp_index_merge_ror_cpk=@@optimizer_switch;
|
||||
set optimizer_switch='extended_keys=off';
|
||||
explain select * from t1 where pk1 != 0 and key1 = 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref PRIMARY,key1 key1 4 const 1 Using index condition
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
|
||||
explain select * from t1 where pk1 != 0 and key1 = 1 {
|
||||
"steps": [
|
||||
{
|
||||
"join_preparation": {
|
||||
"select_id": 1,
|
||||
"steps": [
|
||||
{
|
||||
"expanded_query": "select `t1`.`pk1` AS `pk1`,`t1`.`pk2` AS `pk2`,`t1`.`key1` AS `key1`,`t1`.`key2` AS `key2` from `t1` where `t1`.`pk1` <> 0 and `t1`.`key1` = 1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_optimization": {
|
||||
"select_id": 1,
|
||||
"steps": [
|
||||
{
|
||||
"condition_processing": {
|
||||
"condition": "WHERE",
|
||||
"original_condition": "t1.pk1 <> 0 and t1.key1 = 1",
|
||||
"steps": [
|
||||
{
|
||||
"transformation": "equality_propagation",
|
||||
"resulting_condition": "t1.pk1 <> 0 and multiple equal(1, t1.key1)"
|
||||
},
|
||||
{
|
||||
"transformation": "constant_propagation",
|
||||
"resulting_condition": "t1.pk1 <> 0 and multiple equal(1, t1.key1)"
|
||||
},
|
||||
{
|
||||
"transformation": "trivial_condition_removal",
|
||||
"resulting_condition": "t1.pk1 <> 0 and multiple equal(1, t1.key1)"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"table_dependencies": [
|
||||
{
|
||||
"table": "t1",
|
||||
"row_may_be_null": false,
|
||||
"map_bit": 0,
|
||||
"depends_on_map_bits": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref_optimizer_key_uses": [
|
||||
{
|
||||
"table": "t1",
|
||||
"field": "key1",
|
||||
"equals": "1",
|
||||
"null_rejecting": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rows_estimation": [
|
||||
{
|
||||
"table": "t1",
|
||||
"range_analysis": {
|
||||
"table_scan": {
|
||||
"rows": 1000,
|
||||
"cost": 206.1
|
||||
},
|
||||
"potential_range_indexes": [
|
||||
{
|
||||
"index": "PRIMARY",
|
||||
"usable": true,
|
||||
"key_parts": ["pk1", "pk2"]
|
||||
},
|
||||
{
|
||||
"index": "key1",
|
||||
"usable": true,
|
||||
"key_parts": ["key1"]
|
||||
},
|
||||
{
|
||||
"index": "key2",
|
||||
"usable": false,
|
||||
"cause": "not applicable"
|
||||
}
|
||||
],
|
||||
"setup_range_conditions": [],
|
||||
"group_index_range": {
|
||||
"chosen": false,
|
||||
"cause": "no group by or distinct"
|
||||
},
|
||||
"analyzing_range_alternatives": {
|
||||
"range_scan_alternatives": [
|
||||
{
|
||||
"index": "PRIMARY",
|
||||
"ranges": ["pk1 < 0", "0 < pk1"],
|
||||
"rowid_ordered": true,
|
||||
"using_mrr": false,
|
||||
"index_only": false,
|
||||
"rows": 1001,
|
||||
"cost": 203.59,
|
||||
"chosen": true
|
||||
},
|
||||
{
|
||||
"index": "key1",
|
||||
"ranges": ["1 <= key1 <= 1"],
|
||||
"rowid_ordered": true,
|
||||
"using_mrr": false,
|
||||
"index_only": false,
|
||||
"rows": 1,
|
||||
"cost": 2.21,
|
||||
"chosen": true
|
||||
}
|
||||
],
|
||||
"analyzing_roworder_intersect": {
|
||||
"intersecting_indexes": [
|
||||
{
|
||||
"index": "key1",
|
||||
"index_scan_cost": 1,
|
||||
"cumulateed_index_scan_cost": 1,
|
||||
"disk_sweep_cost": 1.0014,
|
||||
"cumulative_total_cost": 2.0014,
|
||||
"usable": true,
|
||||
"matching_rows_now": 1,
|
||||
"intersect_covering_with_this_index": false,
|
||||
"chosen": true
|
||||
}
|
||||
],
|
||||
"clustered_pk": {
|
||||
"index_scan_cost": 0.002,
|
||||
"cumulateed_index_scan_cost": 1.002,
|
||||
"disk_sweep_cost": 1.0014,
|
||||
"clustered_pk_added_to_intersect": false,
|
||||
"cause": "cost"
|
||||
},
|
||||
"chosen": false,
|
||||
"cause": "too few indexes to merge"
|
||||
},
|
||||
"analyzing_index_merge_union": []
|
||||
},
|
||||
"chosen_range_access_summary": {
|
||||
"range_access_plan": {
|
||||
"type": "range_scan",
|
||||
"index": "key1",
|
||||
"rows": 1,
|
||||
"ranges": ["1 <= key1 <= 1"]
|
||||
},
|
||||
"rows_for_plan": 1,
|
||||
"cost_for_plan": 2.21,
|
||||
"chosen": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"selectivity_for_indexes": [
|
||||
{
|
||||
"index_name": "PRIMARY",
|
||||
"selectivity_from_index": 1.001
|
||||
},
|
||||
{
|
||||
"index_name": "key1",
|
||||
"selectivity_from_index": 0.001
|
||||
}
|
||||
],
|
||||
"selectivity_for_columns": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"execution_plan_for_potential_materialization": {
|
||||
"steps": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"considered_execution_plans": [
|
||||
{
|
||||
"plan_prefix": [],
|
||||
"table": "t1",
|
||||
"best_access_path": {
|
||||
"considered_access_paths": [
|
||||
{
|
||||
"access_type": "ref",
|
||||
"index": "key1",
|
||||
"used_range_estimates": true,
|
||||
"rows": 1,
|
||||
"cost": 2,
|
||||
"chosen": true
|
||||
},
|
||||
{
|
||||
"type": "scan",
|
||||
"chosen": false,
|
||||
"cause": "cost"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attaching_conditions_to_tables": {
|
||||
"original_condition": "t1.key1 = 1 and t1.pk1 <> 0",
|
||||
"attached_conditions_computation": [],
|
||||
"attached_conditions_summary": [
|
||||
{
|
||||
"table": "t1",
|
||||
"attached": "t1.pk1 <> 0"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_execution": {
|
||||
"select_id": 1,
|
||||
"steps": []
|
||||
}
|
||||
}
|
||||
]
|
||||
} 0 0
|
||||
drop table t1;
|
||||
set @@optimizer_switch= @tmp_index_merge_ror_cpk;
|
||||
set optimizer_trace="enabled=off";
|
||||
31
mysql-test/main/opt_trace_index_merge_innodb.test
Normal file
31
mysql-test/main/opt_trace_index_merge_innodb.test
Normal file
@@ -0,0 +1,31 @@
|
||||
--source include/not_embedded.inc
|
||||
--source include/have_innodb.inc
|
||||
create table t1
|
||||
(
|
||||
pk1 int not null,
|
||||
pk2 int not null,
|
||||
key1 int not null,
|
||||
key2 int not null,
|
||||
key (key1),
|
||||
key (key2),
|
||||
primary key (pk1, pk2)
|
||||
)engine=Innodb;
|
||||
|
||||
--disable_query_log
|
||||
let $1=1000;
|
||||
while ($1)
|
||||
{
|
||||
eval insert into t1 values (1+$1/10,$1 mod 100,$1,$1/100);
|
||||
dec $1;
|
||||
}
|
||||
--enable_query_log
|
||||
analyze table t1;
|
||||
|
||||
set optimizer_trace="enabled=on";
|
||||
set @tmp_index_merge_ror_cpk=@@optimizer_switch;
|
||||
set optimizer_switch='extended_keys=off';
|
||||
explain select * from t1 where pk1 != 0 and key1 = 1;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
drop table t1;
|
||||
set @@optimizer_switch= @tmp_index_merge_ror_cpk;
|
||||
set optimizer_trace="enabled=off";
|
||||
396
mysql-test/main/opt_trace_security.result
Normal file
396
mysql-test/main/opt_trace_security.result
Normal file
@@ -0,0 +1,396 @@
|
||||
create database db1;
|
||||
use db1;
|
||||
create table t1(a int);
|
||||
insert into t1 values (1),(2),(3);
|
||||
create table t2(a int);
|
||||
CREATE USER 'foo'@'%';
|
||||
CREATE USER 'bar'@'%';
|
||||
create definer=foo SQL SECURITY definer view db1.v1 as select * from db1.t1;
|
||||
create definer=foo function f1 (a int) returns INT SQL SECURITY DEFINER
|
||||
BEGIN
|
||||
insert into t2 select * from t1;
|
||||
return a+1;
|
||||
END|
|
||||
set optimizer_trace="enabled=on";
|
||||
select * from db1.t1;
|
||||
ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't1'
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
|
||||
0 1
|
||||
set optimizer_trace="enabled=off";
|
||||
grant select(a) on db1.t1 to 'foo'@'%';
|
||||
set optimizer_trace="enabled=on";
|
||||
select * from db1.t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
# INSUFFICIENT PRIVILEGES should be set to 1
|
||||
# Trace and Query should be empty
|
||||
# We need SELECT privilege on the table db1.t1;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
|
||||
0 1
|
||||
set optimizer_trace="enabled=off";
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
|
||||
grant select on db1.t1 to 'foo'@'%';
|
||||
grant select on db1.t2 to 'foo'@'%';
|
||||
set optimizer_trace="enabled=on";
|
||||
#
|
||||
# SELECT privilege on the table db1.t1
|
||||
# The trace would be present.
|
||||
#
|
||||
select * from db1.t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
|
||||
select * from db1.t1 {
|
||||
"steps": [
|
||||
{
|
||||
"join_preparation": {
|
||||
"select_id": 1,
|
||||
"steps": [
|
||||
{
|
||||
"expanded_query": "select `db1`.`t1`.`a` AS `a` from `t1`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_optimization": {
|
||||
"select_id": 1,
|
||||
"steps": [
|
||||
{
|
||||
"table_dependencies": [
|
||||
{
|
||||
"table": "t1",
|
||||
"row_may_be_null": false,
|
||||
"map_bit": 0,
|
||||
"depends_on_map_bits": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rows_estimation": [
|
||||
{
|
||||
"table": "t1",
|
||||
"table_scan": {
|
||||
"rows": 3,
|
||||
"cost": 2.0051
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"execution_plan_for_potential_materialization": {
|
||||
"steps": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"considered_execution_plans": [
|
||||
{
|
||||
"plan_prefix": [],
|
||||
"table": "t1",
|
||||
"best_access_path": {
|
||||
"considered_access_paths": [
|
||||
{
|
||||
"access_type": "scan",
|
||||
"resulting_rows": 3,
|
||||
"cost": 2.0051,
|
||||
"chosen": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attaching_conditions_to_tables": {
|
||||
"original_condition": null,
|
||||
"attached_conditions_computation": [],
|
||||
"attached_conditions_summary": [
|
||||
{
|
||||
"table": "t1",
|
||||
"attached": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_execution": {
|
||||
"select_id": 1,
|
||||
"steps": []
|
||||
}
|
||||
}
|
||||
]
|
||||
} 0 0
|
||||
set optimizer_trace="enabled=off";
|
||||
grant select on db1.v1 to 'foo'@'%';
|
||||
grant show view on db1.v1 to 'foo'@'%';
|
||||
grant select on db1.v1 to 'bar'@'%';
|
||||
grant show view on db1.v1 to 'bar'@'%';
|
||||
select current_user();
|
||||
current_user()
|
||||
foo@%
|
||||
set optimizer_trace="enabled=on";
|
||||
select * from db1.v1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
|
||||
select * from db1.v1 {
|
||||
"steps": [
|
||||
{
|
||||
"join_preparation": {
|
||||
"select_id": 1,
|
||||
"steps": [
|
||||
{
|
||||
"view": {
|
||||
"table": "v1",
|
||||
"select_id": 2,
|
||||
"merged": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_preparation": {
|
||||
"select_id": 2,
|
||||
"steps": [
|
||||
{
|
||||
"expanded_query": "/* select#2 */ select `db1`.`t1`.`a` AS `a` from `t1`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"expanded_query": "/* select#1 */ select `db1`.`t1`.`a` AS `a` from `v1`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_optimization": {
|
||||
"select_id": 1,
|
||||
"steps": [
|
||||
{
|
||||
"table_dependencies": [
|
||||
{
|
||||
"table": "t1",
|
||||
"row_may_be_null": false,
|
||||
"map_bit": 0,
|
||||
"depends_on_map_bits": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rows_estimation": [
|
||||
{
|
||||
"table": "t1",
|
||||
"table_scan": {
|
||||
"rows": 3,
|
||||
"cost": 2.0051
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"execution_plan_for_potential_materialization": {
|
||||
"steps": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"considered_execution_plans": [
|
||||
{
|
||||
"plan_prefix": [],
|
||||
"table": "t1",
|
||||
"best_access_path": {
|
||||
"considered_access_paths": [
|
||||
{
|
||||
"access_type": "scan",
|
||||
"resulting_rows": 3,
|
||||
"cost": 2.0051,
|
||||
"chosen": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"attaching_conditions_to_tables": {
|
||||
"original_condition": null,
|
||||
"attached_conditions_computation": [],
|
||||
"attached_conditions_summary": [
|
||||
{
|
||||
"table": "t1",
|
||||
"attached": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_execution": {
|
||||
"select_id": 1,
|
||||
"steps": []
|
||||
}
|
||||
}
|
||||
]
|
||||
} 0 0
|
||||
set optimizer_trace="enabled=off";
|
||||
select current_user();
|
||||
current_user()
|
||||
bar@%
|
||||
set optimizer_trace="enabled=on";
|
||||
select * from db1.v1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
#
|
||||
# INSUFFICIENT PRIVILEGES should be set to 1
|
||||
# Trace and Query should be empty
|
||||
# Privileges for the underlying tables of the
|
||||
# view should also be present for the current user
|
||||
#
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
|
||||
0 1
|
||||
set optimizer_trace="enabled=off";
|
||||
grant execute on function db1.f1 to 'foo'@'%';
|
||||
grant execute on function db1.f1 to 'bar'@'%';
|
||||
grant select on db1.t1 to 'bar'@'%';
|
||||
grant insert on db1.t2 to 'foo'@'%';
|
||||
select current_user();
|
||||
current_user()
|
||||
foo@%
|
||||
set optimizer_trace="enabled=on";
|
||||
select db1.f1(a) from db1.t1;
|
||||
db1.f1(a)
|
||||
2
|
||||
3
|
||||
4
|
||||
select INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
|
||||
INSUFFICIENT_PRIVILEGES
|
||||
0
|
||||
set optimizer_trace="enabled=off";
|
||||
select current_user();
|
||||
current_user()
|
||||
bar@%
|
||||
set optimizer_trace="enabled=on";
|
||||
#
|
||||
# The trace should be empty, because the current user
|
||||
# does not have INSERT privilege for table t2 which is
|
||||
# used in the function f1
|
||||
#
|
||||
select db1.f1(a) from db1.t1;
|
||||
db1.f1(a)
|
||||
2
|
||||
3
|
||||
4
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
|
||||
0 1
|
||||
set optimizer_trace="enabled=off";
|
||||
select current_user();
|
||||
current_user()
|
||||
root@localhost
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM foo;
|
||||
drop user if exists foo;
|
||||
drop user if exists bar;
|
||||
drop table db1.t1, db1.t2;
|
||||
drop database db1;
|
||||
#
|
||||
# Privilege checking for optimizer trace across connections
|
||||
#
|
||||
connection default;
|
||||
create database db1;
|
||||
use db1;
|
||||
create table t1(a int);
|
||||
insert into t1 values (1),(2),(3);
|
||||
create table t2(a int);
|
||||
CREATE USER 'foo'@'localhost';
|
||||
CREATE USER 'bar'@'localhost';
|
||||
grant all on *.* to foo@localhost with grant option;
|
||||
grant all on *.* to bar@localhost with grant option;
|
||||
connect con_foo,localhost, foo,, db1;
|
||||
connection default;
|
||||
connect con_bar,localhost, bar,, db1;
|
||||
connection default;
|
||||
create definer=foo@localhost SQL SECURITY definer view db1.v1 as select * from db1.t1;
|
||||
create function f1 (a int) returns INT SQL SECURITY DEFINER
|
||||
BEGIN
|
||||
insert into t2 select * from t1;
|
||||
return a+1;
|
||||
END|
|
||||
grant execute on function f1 to bar@localhost;
|
||||
connection con_foo;
|
||||
set optimizer_trace='enabled=on';
|
||||
select * from db1.t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
#
|
||||
# Test that security context changes are allowed when, and only
|
||||
# when, invoker has all global privileges.
|
||||
#
|
||||
select query, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
|
||||
query INSUFFICIENT_PRIVILEGES
|
||||
select * from db1.t1 0
|
||||
set optimizer_trace='enabled=off';
|
||||
connection con_bar;
|
||||
set optimizer_trace='enabled=on';
|
||||
select f1(a) from db1.t1;
|
||||
f1(a)
|
||||
2
|
||||
3
|
||||
4
|
||||
select query, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
|
||||
query INSUFFICIENT_PRIVILEGES
|
||||
select f1(a) from db1.t1 0
|
||||
set optimizer_trace='enabled=off';
|
||||
connection default;
|
||||
revoke shutdown on *.* from foo@localhost;
|
||||
disconnect con_foo;
|
||||
connect con_foo, localhost, foo,, db1;
|
||||
connection con_foo;
|
||||
set optimizer_trace='enabled=on';
|
||||
select f1(a) from db1.t1;
|
||||
f1(a)
|
||||
2
|
||||
3
|
||||
4
|
||||
#
|
||||
# Test to check if invoker has all global privileges or not, only then
|
||||
# the security context changes are allowed. The user has been revoked
|
||||
# shutdown privilege so INSUFFICIENT PRIVILEGES should be set to 1.
|
||||
#
|
||||
select query, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
|
||||
query INSUFFICIENT_PRIVILEGES
|
||||
1
|
||||
set optimizer_trace='enabled=off';
|
||||
connection default;
|
||||
select current_user();
|
||||
current_user()
|
||||
root@localhost
|
||||
select * from db1.v1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
drop user foo@localhost, bar@localhost;
|
||||
drop view db1.v1;
|
||||
drop table db1.t1;
|
||||
drop database db1;
|
||||
set optimizer_trace="enabled=off";
|
||||
197
mysql-test/main/opt_trace_security.test
Normal file
197
mysql-test/main/opt_trace_security.test
Normal file
@@ -0,0 +1,197 @@
|
||||
--source include/not_embedded.inc
|
||||
create database db1;
|
||||
use db1;
|
||||
create table t1(a int);
|
||||
insert into t1 values (1),(2),(3);
|
||||
create table t2(a int);
|
||||
|
||||
CREATE USER 'foo'@'%';
|
||||
CREATE USER 'bar'@'%';
|
||||
|
||||
create definer=foo SQL SECURITY definer view db1.v1 as select * from db1.t1;
|
||||
|
||||
delimiter |;
|
||||
create definer=foo function f1 (a int) returns INT SQL SECURITY DEFINER
|
||||
BEGIN
|
||||
insert into t2 select * from t1;
|
||||
return a+1;
|
||||
END|
|
||||
delimiter ;|
|
||||
|
||||
--change_user foo
|
||||
set optimizer_trace="enabled=on";
|
||||
--error 1142
|
||||
select * from db1.t1;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace="enabled=off";
|
||||
|
||||
--change_user root
|
||||
grant select(a) on db1.t1 to 'foo'@'%';
|
||||
|
||||
--change_user foo
|
||||
set optimizer_trace="enabled=on";
|
||||
select * from db1.t1;
|
||||
|
||||
--echo # INSUFFICIENT PRIVILEGES should be set to 1
|
||||
--echo # Trace and Query should be empty
|
||||
--echo # We need SELECT privilege on the table db1.t1;
|
||||
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace="enabled=off";
|
||||
|
||||
--change_user root
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
grant select on db1.t1 to 'foo'@'%';
|
||||
grant select on db1.t2 to 'foo'@'%';
|
||||
|
||||
--change_user foo
|
||||
set optimizer_trace="enabled=on";
|
||||
|
||||
--echo #
|
||||
--echo # SELECT privilege on the table db1.t1
|
||||
--echo # The trace would be present.
|
||||
--echo #
|
||||
select * from db1.t1;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace="enabled=off";
|
||||
|
||||
--change_user root
|
||||
|
||||
grant select on db1.v1 to 'foo'@'%';
|
||||
grant show view on db1.v1 to 'foo'@'%';
|
||||
|
||||
grant select on db1.v1 to 'bar'@'%';
|
||||
grant show view on db1.v1 to 'bar'@'%';
|
||||
|
||||
--change_user foo
|
||||
select current_user();
|
||||
set optimizer_trace="enabled=on";
|
||||
select * from db1.v1;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace="enabled=off";
|
||||
|
||||
--change_user bar
|
||||
select current_user();
|
||||
set optimizer_trace="enabled=on";
|
||||
select * from db1.v1;
|
||||
--echo #
|
||||
--echo # INSUFFICIENT PRIVILEGES should be set to 1
|
||||
--echo # Trace and Query should be empty
|
||||
--echo # Privileges for the underlying tables of the
|
||||
--echo # view should also be present for the current user
|
||||
--echo #
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace="enabled=off";
|
||||
|
||||
--change_user root
|
||||
grant execute on function db1.f1 to 'foo'@'%';
|
||||
grant execute on function db1.f1 to 'bar'@'%';
|
||||
|
||||
grant select on db1.t1 to 'bar'@'%';
|
||||
grant insert on db1.t2 to 'foo'@'%';
|
||||
|
||||
--change_user foo
|
||||
select current_user();
|
||||
set optimizer_trace="enabled=on";
|
||||
|
||||
select db1.f1(a) from db1.t1;
|
||||
select INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace="enabled=off";
|
||||
|
||||
--change_user bar
|
||||
select current_user();
|
||||
set optimizer_trace="enabled=on";
|
||||
--echo #
|
||||
--echo # The trace should be empty, because the current user
|
||||
--echo # does not have INSERT privilege for table t2 which is
|
||||
--echo # used in the function f1
|
||||
--echo #
|
||||
select db1.f1(a) from db1.t1;
|
||||
select * from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace="enabled=off";
|
||||
|
||||
--change_user root
|
||||
select current_user();
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM foo;
|
||||
|
||||
--change_user root
|
||||
drop user if exists foo;
|
||||
drop user if exists bar;
|
||||
drop table db1.t1, db1.t2;
|
||||
drop database db1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Privilege checking for optimizer trace across connections
|
||||
--echo #
|
||||
|
||||
connection default;
|
||||
create database db1;
|
||||
use db1;
|
||||
create table t1(a int);
|
||||
insert into t1 values (1),(2),(3);
|
||||
create table t2(a int);
|
||||
|
||||
CREATE USER 'foo'@'localhost';
|
||||
CREATE USER 'bar'@'localhost';
|
||||
grant all on *.* to foo@localhost with grant option;
|
||||
grant all on *.* to bar@localhost with grant option;
|
||||
#grant select on db1.t1 to bar@localhost;
|
||||
#grant insert on db1.t2 to bar@localhost;
|
||||
|
||||
connect (con_foo,localhost, foo,, db1);
|
||||
connection default;
|
||||
connect (con_bar,localhost, bar,, db1);
|
||||
connection default;
|
||||
create definer=foo@localhost SQL SECURITY definer view db1.v1 as select * from db1.t1;
|
||||
|
||||
delimiter |;
|
||||
create function f1 (a int) returns INT SQL SECURITY DEFINER
|
||||
BEGIN
|
||||
insert into t2 select * from t1;
|
||||
return a+1;
|
||||
END|
|
||||
delimiter ;|
|
||||
|
||||
grant execute on function f1 to bar@localhost;
|
||||
|
||||
connection con_foo;
|
||||
set optimizer_trace='enabled=on';
|
||||
select * from db1.t1;
|
||||
--echo #
|
||||
--echo # Test that security context changes are allowed when, and only
|
||||
--echo # when, invoker has all global privileges.
|
||||
--echo #
|
||||
select query, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace='enabled=off';
|
||||
|
||||
connection con_bar;
|
||||
set optimizer_trace='enabled=on';
|
||||
select f1(a) from db1.t1;
|
||||
select query, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace='enabled=off';
|
||||
|
||||
connection default;
|
||||
revoke shutdown on *.* from foo@localhost;
|
||||
disconnect con_foo;
|
||||
connect (con_foo, localhost, foo,, db1);
|
||||
|
||||
connection con_foo;
|
||||
set optimizer_trace='enabled=on';
|
||||
select f1(a) from db1.t1;
|
||||
--echo #
|
||||
--echo # Test to check if invoker has all global privileges or not, only then
|
||||
--echo # the security context changes are allowed. The user has been revoked
|
||||
--echo # shutdown privilege so INSUFFICIENT PRIVILEGES should be set to 1.
|
||||
--echo #
|
||||
select query, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
|
||||
set optimizer_trace='enabled=off';
|
||||
|
||||
connection default;
|
||||
select current_user();
|
||||
select * from db1.v1;
|
||||
drop user foo@localhost, bar@localhost;
|
||||
drop view db1.v1;
|
||||
drop table db1.t1;
|
||||
drop database db1;
|
||||
set optimizer_trace="enabled=off";
|
||||
@@ -1164,5 +1164,14 @@ NULL
|
||||
NULL
|
||||
DROP TABLE t1, t2, t3;
|
||||
#
|
||||
# MDEV-18447 Assertion `!is_zero_datetime()' failed in Timestamp_or_zero_datetime::tv
|
||||
#
|
||||
CREATE TABLE t1 (a TIMESTAMP DEFAULT 0, b TIMESTAMP DEFAULT 0, c TIME DEFAULT 0);
|
||||
INSERT INTO t1 VALUES (0,0,0);
|
||||
SELECT c IN (GREATEST(a,b)) FROM t1;
|
||||
c IN (GREATEST(a,b))
|
||||
0
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 10.4 tests
|
||||
#
|
||||
|
||||
@@ -760,6 +760,14 @@ CREATE TABLE t3 (pk INT PRIMARY KEY, b TIMESTAMP) ENGINE=MyISAM;
|
||||
SELECT ( SELECT b FROM t1 LIMIT 1 ) AS sq FROM t2 LEFT JOIN t3 USING (pk);
|
||||
DROP TABLE t1, t2, t3;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-18447 Assertion `!is_zero_datetime()' failed in Timestamp_or_zero_datetime::tv
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a TIMESTAMP DEFAULT 0, b TIMESTAMP DEFAULT 0, c TIME DEFAULT 0);
|
||||
INSERT INTO t1 VALUES (0,0,0);
|
||||
SELECT c IN (GREATEST(a,b)) FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.4 tests
|
||||
|
||||
@@ -205,6 +205,10 @@ def information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_SCHEMA 10 NULL YES varc
|
||||
def information_schema KEY_COLUMN_USAGE TABLE_CATALOG 4 '' NO varchar 512 1536 NULL NULL NULL utf8 utf8_general_ci varchar(512) select NEVER NULL
|
||||
def information_schema KEY_COLUMN_USAGE TABLE_NAME 6 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
|
||||
def information_schema KEY_COLUMN_USAGE TABLE_SCHEMA 5 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
|
||||
def information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES 4 0 NO tinyint NULL NULL 3 0 NULL NULL NULL tinyint(1) select NEVER NULL
|
||||
def information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE 3 0 NO int NULL NULL 10 0 NULL NULL NULL int(20) select NEVER NULL
|
||||
def information_schema OPTIMIZER_TRACE QUERY 1 '' NO longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext select NEVER NULL
|
||||
def information_schema OPTIMIZER_TRACE TRACE 2 '' NO longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext select NEVER NULL
|
||||
def information_schema PARAMETERS CHARACTER_MAXIMUM_LENGTH 8 NULL YES int NULL NULL 10 0 NULL NULL NULL int(21) select NEVER NULL
|
||||
def information_schema PARAMETERS CHARACTER_OCTET_LENGTH 9 NULL YES int NULL NULL 10 0 NULL NULL NULL int(21) select NEVER NULL
|
||||
def information_schema PARAMETERS CHARACTER_SET_NAME 13 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
|
||||
@@ -743,6 +747,10 @@ NULL information_schema KEY_COLUMN_USAGE POSITION_IN_UNIQUE_CONSTRAINT bigint NU
|
||||
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_COLUMN_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
1.0000 information_schema OPTIMIZER_TRACE QUERY longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
|
||||
1.0000 information_schema OPTIMIZER_TRACE TRACE longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
|
||||
NULL information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE int NULL NULL NULL NULL int(20)
|
||||
NULL information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES tinyint NULL NULL NULL NULL tinyint(1)
|
||||
3.0000 information_schema PARAMETERS SPECIFIC_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512)
|
||||
3.0000 information_schema PARAMETERS SPECIFIC_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
3.0000 information_schema PARAMETERS SPECIFIC_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
|
||||
@@ -205,6 +205,10 @@ def information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_SCHEMA 10 NULL YES varc
|
||||
def information_schema KEY_COLUMN_USAGE TABLE_CATALOG 4 '' NO varchar 512 1536 NULL NULL NULL utf8 utf8_general_ci varchar(512) NEVER NULL
|
||||
def information_schema KEY_COLUMN_USAGE TABLE_NAME 6 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
|
||||
def information_schema KEY_COLUMN_USAGE TABLE_SCHEMA 5 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
|
||||
def information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES 4 0 NO tinyint NULL NULL 3 0 NULL NULL NULL tinyint(1) NEVER NULL
|
||||
def information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE 3 0 NO int NULL NULL 10 0 NULL NULL NULL int(20) NEVER NULL
|
||||
def information_schema OPTIMIZER_TRACE QUERY 1 '' NO longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext NEVER NULL
|
||||
def information_schema OPTIMIZER_TRACE TRACE 2 '' NO longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext NEVER NULL
|
||||
def information_schema PARAMETERS CHARACTER_MAXIMUM_LENGTH 8 NULL YES int NULL NULL 10 0 NULL NULL NULL int(21) NEVER NULL
|
||||
def information_schema PARAMETERS CHARACTER_OCTET_LENGTH 9 NULL YES int NULL NULL 10 0 NULL NULL NULL int(21) NEVER NULL
|
||||
def information_schema PARAMETERS CHARACTER_SET_NAME 13 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
|
||||
@@ -743,6 +747,10 @@ NULL information_schema KEY_COLUMN_USAGE POSITION_IN_UNIQUE_CONSTRAINT bigint NU
|
||||
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_COLUMN_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
1.0000 information_schema OPTIMIZER_TRACE QUERY longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
|
||||
1.0000 information_schema OPTIMIZER_TRACE TRACE longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
|
||||
NULL information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE int NULL NULL NULL NULL int(20)
|
||||
NULL information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES tinyint NULL NULL NULL NULL tinyint(1)
|
||||
3.0000 information_schema PARAMETERS SPECIFIC_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512)
|
||||
3.0000 information_schema PARAMETERS SPECIFIC_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
3.0000 information_schema PARAMETERS SPECIFIC_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
|
||||
|
||||
@@ -489,6 +489,31 @@ user_comment
|
||||
Separator -----------------------------------------------------
|
||||
TABLE_CATALOG def
|
||||
TABLE_SCHEMA information_schema
|
||||
TABLE_NAME OPTIMIZER_TRACE
|
||||
TABLE_TYPE SYSTEM VIEW
|
||||
ENGINE MYISAM_OR_MARIA
|
||||
VERSION 11
|
||||
ROW_FORMAT DYNAMIC_OR_PAGE
|
||||
TABLE_ROWS #TBLR#
|
||||
AVG_ROW_LENGTH #ARL#
|
||||
DATA_LENGTH #DL#
|
||||
MAX_DATA_LENGTH #MDL#
|
||||
INDEX_LENGTH #IL#
|
||||
DATA_FREE #DF#
|
||||
AUTO_INCREMENT NULL
|
||||
CREATE_TIME #CRT#
|
||||
UPDATE_TIME #UT#
|
||||
CHECK_TIME #CT#
|
||||
TABLE_COLLATION utf8_general_ci
|
||||
CHECKSUM NULL
|
||||
CREATE_OPTIONS #CO#
|
||||
TABLE_COMMENT #TC#
|
||||
MAX_INDEX_LENGTH #MIL#
|
||||
TEMPORARY Y
|
||||
user_comment
|
||||
Separator -----------------------------------------------------
|
||||
TABLE_CATALOG def
|
||||
TABLE_SCHEMA information_schema
|
||||
TABLE_NAME PARAMETERS
|
||||
TABLE_TYPE SYSTEM VIEW
|
||||
ENGINE MYISAM_OR_MARIA
|
||||
@@ -1530,6 +1555,31 @@ user_comment
|
||||
Separator -----------------------------------------------------
|
||||
TABLE_CATALOG def
|
||||
TABLE_SCHEMA information_schema
|
||||
TABLE_NAME OPTIMIZER_TRACE
|
||||
TABLE_TYPE SYSTEM VIEW
|
||||
ENGINE MYISAM_OR_MARIA
|
||||
VERSION 11
|
||||
ROW_FORMAT DYNAMIC_OR_PAGE
|
||||
TABLE_ROWS #TBLR#
|
||||
AVG_ROW_LENGTH #ARL#
|
||||
DATA_LENGTH #DL#
|
||||
MAX_DATA_LENGTH #MDL#
|
||||
INDEX_LENGTH #IL#
|
||||
DATA_FREE #DF#
|
||||
AUTO_INCREMENT NULL
|
||||
CREATE_TIME #CRT#
|
||||
UPDATE_TIME #UT#
|
||||
CHECK_TIME #CT#
|
||||
TABLE_COLLATION utf8_general_ci
|
||||
CHECKSUM NULL
|
||||
CREATE_OPTIONS #CO#
|
||||
TABLE_COMMENT #TC#
|
||||
MAX_INDEX_LENGTH #MIL#
|
||||
TEMPORARY Y
|
||||
user_comment
|
||||
Separator -----------------------------------------------------
|
||||
TABLE_CATALOG def
|
||||
TABLE_SCHEMA information_schema
|
||||
TABLE_NAME PARAMETERS
|
||||
TABLE_TYPE SYSTEM VIEW
|
||||
ENGINE MYISAM_OR_MARIA
|
||||
|
||||
@@ -489,6 +489,31 @@ user_comment
|
||||
Separator -----------------------------------------------------
|
||||
TABLE_CATALOG def
|
||||
TABLE_SCHEMA information_schema
|
||||
TABLE_NAME OPTIMIZER_TRACE
|
||||
TABLE_TYPE SYSTEM VIEW
|
||||
ENGINE MYISAM_OR_MARIA
|
||||
VERSION 11
|
||||
ROW_FORMAT DYNAMIC_OR_PAGE
|
||||
TABLE_ROWS #TBLR#
|
||||
AVG_ROW_LENGTH #ARL#
|
||||
DATA_LENGTH #DL#
|
||||
MAX_DATA_LENGTH #MDL#
|
||||
INDEX_LENGTH #IL#
|
||||
DATA_FREE #DF#
|
||||
AUTO_INCREMENT NULL
|
||||
CREATE_TIME #CRT#
|
||||
UPDATE_TIME #UT#
|
||||
CHECK_TIME #CT#
|
||||
TABLE_COLLATION utf8_general_ci
|
||||
CHECKSUM NULL
|
||||
CREATE_OPTIONS #CO#
|
||||
TABLE_COMMENT #TC#
|
||||
MAX_INDEX_LENGTH #MIL#
|
||||
TEMPORARY Y
|
||||
user_comment
|
||||
Separator -----------------------------------------------------
|
||||
TABLE_CATALOG def
|
||||
TABLE_SCHEMA information_schema
|
||||
TABLE_NAME PARAMETERS
|
||||
TABLE_TYPE SYSTEM VIEW
|
||||
ENGINE MYISAM_OR_MARIA
|
||||
@@ -1530,6 +1555,31 @@ user_comment
|
||||
Separator -----------------------------------------------------
|
||||
TABLE_CATALOG def
|
||||
TABLE_SCHEMA information_schema
|
||||
TABLE_NAME OPTIMIZER_TRACE
|
||||
TABLE_TYPE SYSTEM VIEW
|
||||
ENGINE MYISAM_OR_MARIA
|
||||
VERSION 11
|
||||
ROW_FORMAT DYNAMIC_OR_PAGE
|
||||
TABLE_ROWS #TBLR#
|
||||
AVG_ROW_LENGTH #ARL#
|
||||
DATA_LENGTH #DL#
|
||||
MAX_DATA_LENGTH #MDL#
|
||||
INDEX_LENGTH #IL#
|
||||
DATA_FREE #DF#
|
||||
AUTO_INCREMENT NULL
|
||||
CREATE_TIME #CRT#
|
||||
UPDATE_TIME #UT#
|
||||
CHECK_TIME #CT#
|
||||
TABLE_COLLATION utf8_general_ci
|
||||
CHECKSUM NULL
|
||||
CREATE_OPTIONS #CO#
|
||||
TABLE_COMMENT #TC#
|
||||
MAX_INDEX_LENGTH #MIL#
|
||||
TEMPORARY Y
|
||||
user_comment
|
||||
Separator -----------------------------------------------------
|
||||
TABLE_CATALOG def
|
||||
TABLE_SCHEMA information_schema
|
||||
TABLE_NAME PARAMETERS
|
||||
TABLE_TYPE SYSTEM VIEW
|
||||
ENGINE MYISAM_OR_MARIA
|
||||
|
||||
@@ -51,7 +51,6 @@ galera.galera_var_reject_queries : assertion in inline_mysql_socket_send
|
||||
query_cache : MDEV-18137: Galera test failure on query_cache
|
||||
galera.galera_autoinc_sst_mariabackup : MDEV-18177 Galera test failure on galera_autoinc_sst_mariabackup
|
||||
galera.galera_ist_mariabackup : Leaves port open
|
||||
galera.galera_sst_rsync2 : MDEV-18178 Galera test failure on galera_sst_rsync2
|
||||
galera.galera_kill_largechanges : MDEV-18179 Galera test failure on galera.galera_kill_largechanges
|
||||
galera.galera_concurrent_ctas : MDEV-18180 Galera test failure on galera.galera_concurrent_ctas
|
||||
galera.galera_var_retry_autocommit: MDEV-18181 Galera test failure on galera.galera_var_retry_autocommit
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
connection node_2;
|
||||
connection node_1;
|
||||
SET SESSION wsrep_sync_wait = 0;
|
||||
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 LONGBLOB) ENGINE=InnoDB;
|
||||
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
connection node_2;
|
||||
connection node_1;
|
||||
connection node_1;
|
||||
connection node_2;
|
||||
Performing State Transfer on a server that has been shut down cleanly and restarted
|
||||
|
||||
@@ -3,6 +3,8 @@ connection node_1;
|
||||
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
|
||||
connection node_2;
|
||||
SET GLOBAL wsrep_load_data_splitting = TRUE;
|
||||
Warnings:
|
||||
Warning 1287 '@@wsrep_load_data_splitting' is deprecated and will be removed in a future release
|
||||
connection node_2;
|
||||
SELECT COUNT(*) = 95000 FROM t1;
|
||||
COUNT(*) = 95000
|
||||
@@ -11,4 +13,6 @@ wsrep_last_committed_diff
|
||||
1
|
||||
connection node_1;
|
||||
SET GLOBAL wsrep_load_data_splitting = 1;;
|
||||
Warnings:
|
||||
Warning 1287 '@@wsrep_load_data_splitting' is deprecated and will be removed in a future release
|
||||
DROP TABLE t1;
|
||||
|
||||
@@ -5,7 +5,5 @@
|
||||
|
||||
[mysqld.1]
|
||||
wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
|
||||
wsrep_sync_wait=0
|
||||
[mysqld.2]
|
||||
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
|
||||
wsrep_sync_wait=0
|
||||
|
||||
@@ -25,5 +25,4 @@ COUNT(*) = 1
|
||||
DROP TABLE t1;
|
||||
connection node_3;
|
||||
Resuming node ...
|
||||
connection node_3;
|
||||
CALL mtr.add_suppression("WSREP: gcs_caused() returned -1 \\(Operation not permitted\\)");
|
||||
|
||||
@@ -56,8 +56,8 @@ DROP TABLE t1;
|
||||
|
||||
# Reconnect node #3 so that MTR's end-of-test checks can run
|
||||
|
||||
--source include/galera_resume.inc
|
||||
--connection node_3
|
||||
--source include/galera_resume.inc
|
||||
--source include/wait_until_connected_again.inc
|
||||
|
||||
--disable_query_log
|
||||
|
||||
@@ -15,7 +15,7 @@ SET @idx1_id = 0;
|
||||
CREATE TABLE t1(f1 INT NOT NULL,
|
||||
f2 VARCHAR(100) PRIMARY KEY)ENGINE=InnoDB;
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@tbl1_id = @tbl_id
|
||||
@@ -32,7 +32,7 @@ CREATE TABLE t1(f1 INT NOT NULL,
|
||||
f2 VARCHAR(100),
|
||||
INDEX idx(f2))ENGINE=InnoDB;
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@tbl1_id = @tbl_id
|
||||
@@ -49,7 +49,7 @@ CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100), f3 VARCHAR(100),
|
||||
INDEX idx(f2, f3), index idx1(f3, f2))ENGINE=InnoDB;
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), MODIFY f3 VARCHAR(150);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), MODIFY f3 VARCHAR(150), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@@ -72,7 +72,7 @@ CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100),
|
||||
INDEX idx(f2(40)))ENGINE=InnoDB;
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@@ -93,7 +93,7 @@ CREATE TABLE t1(f1 INT NOT NULL,
|
||||
f2 VARCHAR(100), FULLTEXT idx(f2))ENGINE=InnoDB;
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@@ -117,7 +117,7 @@ INDEX idx(f3))ENGINE=InnoDB;
|
||||
INSERT INTO t1(f1, f2) VALUES(1, repeat('a', 40));
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(100);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(100), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@@ -163,7 +163,7 @@ f2 VARCHAR(100),
|
||||
INDEX idx(f2(10)))ENGINE=InnoDB;
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), DROP INDEX idx, ADD INDEX idx(f2(10));
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), DROP INDEX idx, ADD INDEX idx(f2(10)), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@@ -251,7 +251,7 @@ CREATE TABLE t1(f1 INT NOT NULL,
|
||||
f2 VARCHAR(100),
|
||||
INDEX idx(f2))ENGINE=InnoDB;
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT;
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT, ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@tbl1_id = @tbl_id
|
||||
@@ -267,7 +267,7 @@ t1 CREATE TABLE `t1` (
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100) PRIMARY KEY)ENGINE=InnoDB;
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT;
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT, ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@tbl1_id = @tbl_id
|
||||
|
||||
@@ -128,3 +128,50 @@ HANDLER h READ `PRIMARY` PREV WHERE 0;
|
||||
pk f1 f2 f3 f4 f5 f6 f7 f8 filler
|
||||
HANDLER h CLOSE;
|
||||
DROP TABLE t1;
|
||||
create table t (
|
||||
a varchar(9),
|
||||
b int,
|
||||
c int,
|
||||
row_start bigint unsigned generated always as row start invisible,
|
||||
row_end bigint unsigned generated always as row end invisible,
|
||||
period for system_time (row_start, row_end)
|
||||
) engine=innodb row_format=compressed with system versioning;
|
||||
insert into t values (repeat('a', 9), 1, 1);
|
||||
set @@system_versioning_alter_history = keep;
|
||||
alter table t modify a varchar(10), algorithm=instant;
|
||||
alter table t change b bb int, algorithm=instant;
|
||||
alter table t modify c int without system versioning, algorithm=instant;
|
||||
set @@system_versioning_alter_history = error;
|
||||
check table t;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t check status OK
|
||||
drop table t;
|
||||
#
|
||||
# MDEV-18219 Assertion `index->n_core_null_bytes <= ...' failed
|
||||
# in rec_init_offsets after instant DROP COLUMN
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b INT NOT NULL) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES
|
||||
(0,9),(2,7),(3,1),(3,4),(8,4),(3,7),(6,1),(3,8),(1,2),(4,1),(0,8),(5,3),
|
||||
(1,3),(1,6),(2,1),(8,7),(6,0),(1,9),(9,4),(0,6),(9,3),(0,9),(9,4),(2,4),
|
||||
(2,7),(7,8),(8,2),(2,5),(6,1),(4,5),(5,3),(6,8),(4,9),(5,7),(7,5),(5,1),
|
||||
(8,8),(5,7),(3,8),(0,1),(8,4),(8,3),(9,7),(4,8),(1,1),(0,4),(2,6),(8,5),
|
||||
(8,8),(8,7),(6,7),(1,7),(9,6),(3,6),(1,9),(0,3),(5,3),(2,4),(0,6),(2,0),
|
||||
(6,5),(1,6),(2,4),(9,1),(3,0),(6,4),(1,3),(0,8),(3,5),(3,1),(8,9),(9,9),
|
||||
(7,9),(4,5),(2,2),(3,8),(0,8),(7,1),(2,0),(1,5),(7,3),(4,4),(3,9),(7,2),
|
||||
(6,2),(0,4),(2,0),(1,5),(5,7),(4,5),(3,7),(6,0),(2,1),(5,0),(1,0),(2,0),
|
||||
(8,4),(5,7),(3,5),(0,5),(7,6),(5,9),(1,2),(4,2),(8,5),(8,7),(2,8),(1,8),
|
||||
(4,3),(1,6),(7,8),(3,7),(4,6),(1,1),(3,0),(1,6),(2,0),(3,4),(4,8),(3,9),
|
||||
(8,0),(4,9),(4,0),(3,9),(6,4),(7,4),(5,8),(4,7),(7,3),(5,9),(2,3),(7,3),
|
||||
(0,4),(5,9),(9,8),(4,2),(3,6),(2,6),(1,8),(7,0),(0,0),(2,3),(1,2),(3,3),
|
||||
(2,7),(6,0),(9,0),(6,9),(4,6),(9,8),(0,7),(9,1),(9,6),(4,3),(7,7),(7,7),
|
||||
(4,1),(4,7),(7,3),(2,8),(5,8),(8,9),(3,9),(7,7),(0,8),(4,9),(3,2),(5,0),
|
||||
(1,7),(0,3),(2,9),(9,7),(7,5),(6,9),(8,5),(3,6),(1,1),(2,8),(7,9),(4,9),
|
||||
(6,6),(5,9),(5,3),(9,8),(3,3),(5,6),(0,9),(3,9),(7,9),(7,3),(5,2),(1,4),
|
||||
(4,4),(8,2),(2,2),(8,3),(9,1),(4,9),(9,8),(1,8),(1,8),(9,1),(1,1),(3,0),
|
||||
(4,6),(9,3),(3,3),(5,2),(0,1),(3,4),(3,2),(1,3),(4,4),(7,0),(4,6),(7,2),
|
||||
(4,5),(8,7),(7,8),(8,1),(3,5),(0,6),(3,5),(2,1),(4,4),(3,4),(2,1),(4,1);
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
ALTER TABLE t1 DROP a;
|
||||
ALTER TABLE t1 ADD vb INT AS (b) VIRTUAL;
|
||||
DROP TABLE t1;
|
||||
|
||||
72
mysql-test/suite/innodb/r/instant_alter_import.result
Normal file
72
mysql-test/suite/innodb/r/instant_alter_import.result
Normal file
@@ -0,0 +1,72 @@
|
||||
set default_storage_engine=innodb;
|
||||
#
|
||||
# MDEV-18295 IMPORT TABLESPACE fails with instant-altered tables
|
||||
#
|
||||
create table t2 (x int, z int default 41);
|
||||
alter table t2 discard tablespace;
|
||||
create table t1 (x int);
|
||||
insert into t1 values (1);
|
||||
alter table t1 add z int default 42, algorithm instant;
|
||||
select * from t1;
|
||||
x z
|
||||
1 42
|
||||
flush tables t1 for export;
|
||||
unlock tables;
|
||||
# The metadata has to be updated to instant ADD COLUMN.
|
||||
alter table t2 import tablespace;
|
||||
select * from t2;
|
||||
x z
|
||||
1 42
|
||||
insert into t2 set x=2;
|
||||
select * from t2;
|
||||
x z
|
||||
1 42
|
||||
2 41
|
||||
alter table t1 discard tablespace;
|
||||
flush tables t2 for export;
|
||||
unlock tables;
|
||||
# Both the metadata and the data file used instant ADD COLUMN.
|
||||
alter table t1 import tablespace;
|
||||
select * from t1;
|
||||
x z
|
||||
1 42
|
||||
2 41
|
||||
drop table t2;
|
||||
create table t2 select * from t1;
|
||||
alter table t1 discard tablespace;
|
||||
flush tables t2 for export;
|
||||
unlock tables;
|
||||
# The instant ADD COLUMN has to be removed from the metadata.
|
||||
alter table t1 import tablespace;
|
||||
select * from t1;
|
||||
x z
|
||||
1 42
|
||||
2 41
|
||||
# Remove metadata for instant DROP COLUMN, then import
|
||||
alter table t1 drop x, add column x int first, algorithm instant;
|
||||
select * from t1;
|
||||
x z
|
||||
NULL 42
|
||||
NULL 41
|
||||
alter table t1 discard tablespace;
|
||||
alter table t1 import tablespace;
|
||||
select * from t1;
|
||||
x z
|
||||
1 42
|
||||
2 41
|
||||
# Import a data file that contains instant DROP COLUMN metadata
|
||||
alter table t2 drop x;
|
||||
alter table t1 drop x, force;
|
||||
alter table t1 discard tablespace;
|
||||
flush tables t2 for export;
|
||||
unlock tables;
|
||||
alter table t1 import tablespace;
|
||||
ERROR HY000: Schema mismatch (Index field count 4 doesn't match tablespace metadata file value 5)
|
||||
select * from t1;
|
||||
ERROR HY000: Tablespace has been discarded for table `t1`
|
||||
alter table t1 import tablespace;
|
||||
ERROR HY000: Internal error: Cannot reset LSNs in table `test`.`t1` : Unsupported
|
||||
select * from t1;
|
||||
ERROR HY000: Tablespace has been discarded for table `t1`
|
||||
drop table t2;
|
||||
drop table t1;
|
||||
@@ -26,7 +26,7 @@ CREATE TABLE t1(f1 INT NOT NULL,
|
||||
f2 VARCHAR(100) PRIMARY KEY)ENGINE=InnoDB;
|
||||
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@@ -39,7 +39,7 @@ CREATE TABLE t1(f1 INT NOT NULL,
|
||||
INDEX idx(f2))ENGINE=InnoDB;
|
||||
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@@ -51,7 +51,7 @@ CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100), f3 VARCHAR(100),
|
||||
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), MODIFY f3 VARCHAR(150);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), MODIFY f3 VARCHAR(150), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
|
||||
@@ -65,7 +65,7 @@ CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100),
|
||||
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
|
||||
@@ -80,7 +80,7 @@ CREATE TABLE t1(f1 INT NOT NULL,
|
||||
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
|
||||
@@ -98,7 +98,7 @@ INSERT INTO t1(f1, f2) VALUES(1, repeat('a', 40));
|
||||
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(100);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(100), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
|
||||
@@ -129,7 +129,7 @@ CREATE TABLE t1(f1 INT NOT NULL,
|
||||
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
CALL get_index_id(@tbl_id, "idx", @idx_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), DROP INDEX idx, ADD INDEX idx(f2(10));
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), DROP INDEX idx, ADD INDEX idx(f2(10)), ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
CALL get_index_id(@tbl1_id, "idx", @idx1_id);
|
||||
|
||||
@@ -192,7 +192,7 @@ CREATE TABLE t1(f1 INT NOT NULL,
|
||||
INDEX idx(f2))ENGINE=InnoDB;
|
||||
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT;
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT, ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
@@ -202,7 +202,7 @@ DROP TABLE t1;
|
||||
CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100) PRIMARY KEY)ENGINE=InnoDB;
|
||||
|
||||
CALL get_table_id("test/t1", @tbl_id);
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT;
|
||||
ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT, ALGORITHM=INSTANT;
|
||||
CALL get_table_id("test/t1", @tbl1_id);
|
||||
|
||||
SELECT @tbl1_id = @tbl_id;
|
||||
|
||||
@@ -136,3 +136,52 @@ HANDLER h CLOSE;
|
||||
DROP TABLE t1;
|
||||
--let $datadir= `select @@datadir`
|
||||
--remove_file $datadir/test/load.data
|
||||
|
||||
|
||||
create table t (
|
||||
a varchar(9),
|
||||
b int,
|
||||
c int,
|
||||
row_start bigint unsigned generated always as row start invisible,
|
||||
row_end bigint unsigned generated always as row end invisible,
|
||||
period for system_time (row_start, row_end)
|
||||
) engine=innodb row_format=compressed with system versioning;
|
||||
insert into t values (repeat('a', 9), 1, 1);
|
||||
set @@system_versioning_alter_history = keep;
|
||||
alter table t modify a varchar(10), algorithm=instant;
|
||||
alter table t change b bb int, algorithm=instant;
|
||||
alter table t modify c int without system versioning, algorithm=instant;
|
||||
set @@system_versioning_alter_history = error;
|
||||
check table t;
|
||||
drop table t;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-18219 Assertion `index->n_core_null_bytes <= ...' failed
|
||||
--echo # in rec_init_offsets after instant DROP COLUMN
|
||||
--echo #
|
||||
CREATE TABLE t1 (a INT, b INT NOT NULL) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES
|
||||
(0,9),(2,7),(3,1),(3,4),(8,4),(3,7),(6,1),(3,8),(1,2),(4,1),(0,8),(5,3),
|
||||
(1,3),(1,6),(2,1),(8,7),(6,0),(1,9),(9,4),(0,6),(9,3),(0,9),(9,4),(2,4),
|
||||
(2,7),(7,8),(8,2),(2,5),(6,1),(4,5),(5,3),(6,8),(4,9),(5,7),(7,5),(5,1),
|
||||
(8,8),(5,7),(3,8),(0,1),(8,4),(8,3),(9,7),(4,8),(1,1),(0,4),(2,6),(8,5),
|
||||
(8,8),(8,7),(6,7),(1,7),(9,6),(3,6),(1,9),(0,3),(5,3),(2,4),(0,6),(2,0),
|
||||
(6,5),(1,6),(2,4),(9,1),(3,0),(6,4),(1,3),(0,8),(3,5),(3,1),(8,9),(9,9),
|
||||
(7,9),(4,5),(2,2),(3,8),(0,8),(7,1),(2,0),(1,5),(7,3),(4,4),(3,9),(7,2),
|
||||
(6,2),(0,4),(2,0),(1,5),(5,7),(4,5),(3,7),(6,0),(2,1),(5,0),(1,0),(2,0),
|
||||
(8,4),(5,7),(3,5),(0,5),(7,6),(5,9),(1,2),(4,2),(8,5),(8,7),(2,8),(1,8),
|
||||
(4,3),(1,6),(7,8),(3,7),(4,6),(1,1),(3,0),(1,6),(2,0),(3,4),(4,8),(3,9),
|
||||
(8,0),(4,9),(4,0),(3,9),(6,4),(7,4),(5,8),(4,7),(7,3),(5,9),(2,3),(7,3),
|
||||
(0,4),(5,9),(9,8),(4,2),(3,6),(2,6),(1,8),(7,0),(0,0),(2,3),(1,2),(3,3),
|
||||
(2,7),(6,0),(9,0),(6,9),(4,6),(9,8),(0,7),(9,1),(9,6),(4,3),(7,7),(7,7),
|
||||
(4,1),(4,7),(7,3),(2,8),(5,8),(8,9),(3,9),(7,7),(0,8),(4,9),(3,2),(5,0),
|
||||
(1,7),(0,3),(2,9),(9,7),(7,5),(6,9),(8,5),(3,6),(1,1),(2,8),(7,9),(4,9),
|
||||
(6,6),(5,9),(5,3),(9,8),(3,3),(5,6),(0,9),(3,9),(7,9),(7,3),(5,2),(1,4),
|
||||
(4,4),(8,2),(2,2),(8,3),(9,1),(4,9),(9,8),(1,8),(1,8),(9,1),(1,1),(3,0),
|
||||
(4,6),(9,3),(3,3),(5,2),(0,1),(3,4),(3,2),(1,3),(4,4),(7,0),(4,6),(7,2),
|
||||
(4,5),(8,7),(7,8),(8,1),(3,5),(0,6),(3,5),(2,1),(4,4),(3,4),(2,1),(4,1);
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
ALTER TABLE t1 DROP a;
|
||||
# Exploit MDEV-17468 to force the table definition to be reloaded
|
||||
ALTER TABLE t1 ADD vb INT AS (b) VIRTUAL;
|
||||
DROP TABLE t1;
|
||||
|
||||
84
mysql-test/suite/innodb/t/instant_alter_import.test
Normal file
84
mysql-test/suite/innodb/t/instant_alter_import.test
Normal file
@@ -0,0 +1,84 @@
|
||||
--source include/have_innodb.inc
|
||||
set default_storage_engine=innodb;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-18295 IMPORT TABLESPACE fails with instant-altered tables
|
||||
--echo #
|
||||
|
||||
create table t2 (x int, z int default 41);
|
||||
alter table t2 discard tablespace;
|
||||
|
||||
create table t1 (x int);
|
||||
insert into t1 values (1);
|
||||
alter table t1 add z int default 42, algorithm instant;
|
||||
select * from t1;
|
||||
flush tables t1 for export;
|
||||
--let $MYSQLD_DATADIR= `select @@datadir`
|
||||
--move_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/t2.cfg
|
||||
--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd
|
||||
unlock tables;
|
||||
|
||||
--echo # The metadata has to be updated to instant ADD COLUMN.
|
||||
alter table t2 import tablespace;
|
||||
|
||||
select * from t2;
|
||||
insert into t2 set x=2;
|
||||
select * from t2;
|
||||
|
||||
alter table t1 discard tablespace;
|
||||
flush tables t2 for export;
|
||||
--move_file $MYSQLD_DATADIR/test/t2.cfg $MYSQLD_DATADIR/test/t1.cfg
|
||||
--copy_file $MYSQLD_DATADIR/test/t2.ibd $MYSQLD_DATADIR/test/t1.ibd
|
||||
unlock tables;
|
||||
|
||||
--echo # Both the metadata and the data file used instant ADD COLUMN.
|
||||
alter table t1 import tablespace;
|
||||
select * from t1;
|
||||
|
||||
drop table t2;
|
||||
create table t2 select * from t1;
|
||||
|
||||
alter table t1 discard tablespace;
|
||||
flush tables t2 for export;
|
||||
--move_file $MYSQLD_DATADIR/test/t2.cfg $MYSQLD_DATADIR/test/t1.cfg
|
||||
--copy_file $MYSQLD_DATADIR/test/t2.ibd $MYSQLD_DATADIR/test/t1.ibd
|
||||
unlock tables;
|
||||
--copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/t1b.cfg
|
||||
--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t1b.ibd
|
||||
|
||||
--echo # The instant ADD COLUMN has to be removed from the metadata.
|
||||
alter table t1 import tablespace;
|
||||
select * from t1;
|
||||
|
||||
--echo # Remove metadata for instant DROP COLUMN, then import
|
||||
alter table t1 drop x, add column x int first, algorithm instant;
|
||||
select * from t1;
|
||||
alter table t1 discard tablespace;
|
||||
|
||||
--move_file $MYSQLD_DATADIR/test/t1b.cfg $MYSQLD_DATADIR/test/t1.cfg
|
||||
--move_file $MYSQLD_DATADIR/test/t1b.ibd $MYSQLD_DATADIR/test/t1.ibd
|
||||
alter table t1 import tablespace;
|
||||
select * from t1;
|
||||
|
||||
--echo # Import a data file that contains instant DROP COLUMN metadata
|
||||
alter table t2 drop x;
|
||||
alter table t1 drop x, force;
|
||||
alter table t1 discard tablespace;
|
||||
|
||||
flush tables t2 for export;
|
||||
--move_file $MYSQLD_DATADIR/test/t2.cfg $MYSQLD_DATADIR/test/t1.cfg
|
||||
--copy_file $MYSQLD_DATADIR/test/t2.ibd $MYSQLD_DATADIR/test/t1.ibd
|
||||
unlock tables;
|
||||
|
||||
--error ER_TABLE_SCHEMA_MISMATCH
|
||||
alter table t1 import tablespace;
|
||||
--error ER_TABLESPACE_DISCARDED
|
||||
select * from t1;
|
||||
--remove_file $MYSQLD_DATADIR/test/t1.cfg
|
||||
--error ER_INTERNAL_ERROR
|
||||
alter table t1 import tablespace;
|
||||
--error ER_TABLESPACE_DISCARDED
|
||||
select * from t1;
|
||||
|
||||
drop table t2;
|
||||
drop table t1;
|
||||
@@ -78,4 +78,4 @@ drop role role3;
|
||||
drop role role2;
|
||||
drop role role1;
|
||||
drop user foo;
|
||||
update mysql.global_priv set priv=json_remove(priv, '$.default_role');
|
||||
update mysql.global_priv set priv=json_compact(json_remove(priv, '$.default_role'));
|
||||
|
||||
@@ -59,4 +59,4 @@ drop role role3;
|
||||
drop role role2;
|
||||
drop role role1;
|
||||
drop user foo;
|
||||
update mysql.global_priv set priv=json_remove(priv, '$.default_role');
|
||||
update mysql.global_priv set priv=json_compact(json_remove(priv, '$.default_role'));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2742,6 +2742,34 @@ NUMERIC_BLOCK_SIZE NULL
|
||||
ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,condition_pushdown_for_subquery,default
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME OPTIMIZER_TRACE
|
||||
SESSION_VALUE enabled=off
|
||||
GLOBAL_VALUE enabled=off
|
||||
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||
DEFAULT_VALUE enabled=off
|
||||
VARIABLE_SCOPE SESSION
|
||||
VARIABLE_TYPE FLAGSET
|
||||
VARIABLE_COMMENT Controls tracing of the Optimizer: optimizer_trace=option=val[,option=val...], where option is one of {enabled} and val is one of {on, off, default}
|
||||
NUMERIC_MIN_VALUE NULL
|
||||
NUMERIC_MAX_VALUE NULL
|
||||
NUMERIC_BLOCK_SIZE NULL
|
||||
ENUM_VALUE_LIST enabled,default
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME OPTIMIZER_TRACE_MAX_MEM_SIZE
|
||||
SESSION_VALUE 1048576
|
||||
GLOBAL_VALUE 1048576
|
||||
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||
DEFAULT_VALUE 1048576
|
||||
VARIABLE_SCOPE SESSION
|
||||
VARIABLE_TYPE BIGINT UNSIGNED
|
||||
VARIABLE_COMMENT Maximum allowed size of an optimizer trace
|
||||
NUMERIC_MIN_VALUE 0
|
||||
NUMERIC_MAX_VALUE 18446744073709551615
|
||||
NUMERIC_BLOCK_SIZE 1
|
||||
ENUM_VALUE_LIST NULL
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME OPTIMIZER_USE_CONDITION_SELECTIVITY
|
||||
SESSION_VALUE 4
|
||||
GLOBAL_VALUE 4
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2966,6 +2966,34 @@ NUMERIC_BLOCK_SIZE NULL
|
||||
ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,condition_pushdown_for_subquery,default
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME OPTIMIZER_TRACE
|
||||
SESSION_VALUE enabled=off
|
||||
GLOBAL_VALUE enabled=off
|
||||
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||
DEFAULT_VALUE enabled=off
|
||||
VARIABLE_SCOPE SESSION
|
||||
VARIABLE_TYPE FLAGSET
|
||||
VARIABLE_COMMENT Controls tracing of the Optimizer: optimizer_trace=option=val[,option=val...], where option is one of {enabled} and val is one of {on, off, default}
|
||||
NUMERIC_MIN_VALUE NULL
|
||||
NUMERIC_MAX_VALUE NULL
|
||||
NUMERIC_BLOCK_SIZE NULL
|
||||
ENUM_VALUE_LIST enabled,default
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME OPTIMIZER_TRACE_MAX_MEM_SIZE
|
||||
SESSION_VALUE 1048576
|
||||
GLOBAL_VALUE 1048576
|
||||
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||
DEFAULT_VALUE 1048576
|
||||
VARIABLE_SCOPE SESSION
|
||||
VARIABLE_TYPE BIGINT UNSIGNED
|
||||
VARIABLE_COMMENT Maximum allowed size of an optimizer trace
|
||||
NUMERIC_MIN_VALUE 0
|
||||
NUMERIC_MAX_VALUE 18446744073709551615
|
||||
NUMERIC_BLOCK_SIZE 1
|
||||
ENUM_VALUE_LIST NULL
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME OPTIMIZER_USE_CONDITION_SELECTIVITY
|
||||
SESSION_VALUE 4
|
||||
GLOBAL_VALUE 4
|
||||
|
||||
@@ -171,10 +171,7 @@ int my_fclose(FILE *fd, myf MyFlags)
|
||||
my_file_info[file].type= UNOPEN;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
do
|
||||
{
|
||||
err= fclose(fd);
|
||||
} while (err == -1 && errno == EINTR);
|
||||
err= fclose(fd);
|
||||
#else
|
||||
err= my_win_fclose(fd);
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,7 @@ PLUGIN_AUTHOR Sergey Vojtovich
|
||||
PLUGIN_DESCRIPTION User-defined variables
|
||||
PLUGIN_LICENSE GPL
|
||||
LOAD_OPTION ON
|
||||
PLUGIN_MATURITY Gamma
|
||||
PLUGIN_MATURITY Stable
|
||||
SHOW CREATE TABLE INFORMATION_SCHEMA.USER_VARIABLES;
|
||||
Table Create Table
|
||||
user_variables CREATE TEMPORARY TABLE `user_variables` (
|
||||
|
||||
@@ -135,6 +135,6 @@ maria_declare_plugin(user_variables)
|
||||
NULL,
|
||||
NULL,
|
||||
"1.0",
|
||||
MariaDB_PLUGIN_MATURITY_GAMMA
|
||||
MariaDB_PLUGIN_MATURITY_STABLE
|
||||
}
|
||||
maria_declare_plugin_end;
|
||||
|
||||
@@ -37,8 +37,8 @@ force=0
|
||||
in_rpm=0
|
||||
ip_only=0
|
||||
cross_bootstrap=0
|
||||
auth_root_authentication_method=normal
|
||||
auth_root_socket_user='root'
|
||||
auth_root_authentication_method=socket
|
||||
auth_root_socket_user=""
|
||||
skip_test_db=0
|
||||
|
||||
usage()
|
||||
@@ -46,17 +46,17 @@ usage()
|
||||
cat <<EOF
|
||||
Usage: $0 [OPTIONS]
|
||||
--auth-root-authentication-method=normal|socket
|
||||
Chooses the authentication method for the created initial
|
||||
root user. The default is 'normal' to creates a root user
|
||||
that can login without password, which can be insecure.
|
||||
The alternative 'socket' allows only the system root user
|
||||
to login as MariaDB root; this requires the unix socket
|
||||
authentication plugin.
|
||||
Chooses the authentication method for the created
|
||||
initial root user. The historical behavior is 'normal'
|
||||
to creates a root user that can login without password,
|
||||
which can be insecure. The default behavior 'socket'
|
||||
sets an invalid root password but allows the system root
|
||||
user to login as MariaDB root without a password.
|
||||
--auth-root-socket-user=user
|
||||
Used with --auth-root-authentication-method=socket. It
|
||||
specifies the name of the MariaDB root account, as well
|
||||
as of the system account allowed to access it. Defaults
|
||||
to 'root'.
|
||||
specifies the name of the second MariaDB root account,
|
||||
as well as of the system account allowed to access it.
|
||||
Defaults to the value of --user.
|
||||
--basedir=path The path to the MariaDB installation directory.
|
||||
--builddir=path If using --srcdir with out-of-directory builds, you
|
||||
will need to set this to the location of the build
|
||||
@@ -505,13 +505,16 @@ cat_sql()
|
||||
{
|
||||
echo "use mysql;"
|
||||
|
||||
# Use $auth_root_socket_user if explicitly specified.
|
||||
# Otherwise use the owner of datadir - ${user:-$USER}
|
||||
# Use 'root' as a fallback
|
||||
auth_root_socket_user=${auth_root_socket_user:-${user:-${USER:-root}}}
|
||||
|
||||
case "$auth_root_authentication_method" in
|
||||
normal)
|
||||
echo "SET @skip_auth_root_nopasswd=NULL;"
|
||||
echo "SET @auth_root_socket=NULL;"
|
||||
;;
|
||||
socket)
|
||||
echo "SET @skip_auth_root_nopasswd=1;"
|
||||
echo "SET @auth_root_socket='$auth_root_socket_user';"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
config=".my.cnf.$$"
|
||||
command=".mysql.$$"
|
||||
output=".my.output.$$"
|
||||
|
||||
trap "interrupt" 1 2 3 6 15
|
||||
|
||||
@@ -216,7 +217,7 @@ prepare() {
|
||||
do_query() {
|
||||
echo "$1" >$command
|
||||
#sed 's,^,> ,' < $command # Debugging
|
||||
$mysql_command --defaults-file=$config $defaults_extra_file $no_defaults $args <$command
|
||||
$mysql_command --defaults-file=$config $defaults_extra_file $no_defaults $args <$command >$output
|
||||
return $?
|
||||
}
|
||||
|
||||
@@ -268,15 +269,18 @@ get_root_password() {
|
||||
echo
|
||||
stty echo
|
||||
if [ "x$password" = "x" ]; then
|
||||
hadpass=0
|
||||
emptypass=1
|
||||
else
|
||||
hadpass=1
|
||||
emptypass=0
|
||||
fi
|
||||
rootpass=$password
|
||||
make_config
|
||||
do_query ""
|
||||
do_query "show create user root@localhost"
|
||||
status=$?
|
||||
done
|
||||
if grep -q unix_socket $output; then
|
||||
emptypass=0
|
||||
fi
|
||||
echo "OK, successfully used password, moving on..."
|
||||
echo
|
||||
}
|
||||
@@ -386,7 +390,7 @@ interrupt() {
|
||||
|
||||
cleanup() {
|
||||
echo "Cleaning up..."
|
||||
rm -f $config $command
|
||||
rm -f $config $command $output
|
||||
}
|
||||
|
||||
# Remove the files before exiting.
|
||||
@@ -405,9 +409,8 @@ echo "NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB"
|
||||
echo " SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!"
|
||||
echo
|
||||
echo "In order to log into MariaDB to secure it, we'll need the current"
|
||||
echo "password for the root user. If you've just installed MariaDB, and"
|
||||
echo "you haven't set the root password yet, the password will be blank,"
|
||||
echo "so you should just press enter here."
|
||||
echo "password for the root user. If you've just installed MariaDB, and"
|
||||
echo "haven't set the root password yet, you should just press enter here."
|
||||
echo
|
||||
|
||||
get_root_password
|
||||
@@ -417,15 +420,47 @@ get_root_password
|
||||
# Set the root password
|
||||
#
|
||||
|
||||
echo "Setting the root password ensures that nobody can log into the MariaDB"
|
||||
echo "root user without the proper authorisation."
|
||||
echo "Setting the root password or using the unix_socket ensures that nobody"
|
||||
echo "can log into the MariaDB root user without the proper authorisation."
|
||||
echo
|
||||
|
||||
while true ; do
|
||||
if [ $hadpass -eq 0 ]; then
|
||||
if [ $emptypass -eq 1 ]; then
|
||||
echo $echo_n "Enable unix_socket authentication? [Y/n] $echo_c"
|
||||
else
|
||||
echo "You already have your root account protected, so you can safely answer 'n'."
|
||||
echo
|
||||
echo $echo_n "Switch to unix_socket authentication [Y/n] $echo_c"
|
||||
fi
|
||||
read reply
|
||||
validate_reply $reply && break
|
||||
done
|
||||
|
||||
if [ "$reply" = "n" ]; then
|
||||
echo " ... skipping."
|
||||
else
|
||||
emptypass=0
|
||||
do_query "UPDATE mysql.global_priv SET priv=json_set(priv, '$.plugin', 'mysql_native_password', '$.authentication_string', 'invalid', '$.auth_or', json_array(json_object(), json_object('plugin', 'unix_socket'))) WHERE User='root';"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Enabled successfully!"
|
||||
echo "Reloading privilege tables.."
|
||||
reload_privilege_tables
|
||||
if [ $? -eq 1 ]; then
|
||||
clean_and_exit
|
||||
fi
|
||||
echo
|
||||
else
|
||||
echo "Failed!"
|
||||
clean_and_exit
|
||||
fi
|
||||
fi
|
||||
echo
|
||||
|
||||
while true ; do
|
||||
if [ $emptypass -eq 1 ]; then
|
||||
echo $echo_n "Set root password? [Y/n] $echo_c"
|
||||
else
|
||||
echo "You already have a root password set, so you can safely answer 'n'."
|
||||
echo "You already have your root account protected, so you can safely answer 'n'."
|
||||
echo
|
||||
echo $echo_n "Change the root password? [Y/n] $echo_c"
|
||||
fi
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
-- add escape character in front of wildcard character to convert "_" or "%" to
|
||||
-- a plain character
|
||||
SELECT LOWER( REPLACE((SELECT REPLACE(@@hostname,'_','\_')),'%','\%') )INTO @current_hostname;
|
||||
SELECT json_object('access',cast(-1 as unsigned)) INTO @all_privileges;
|
||||
SELECT '{"access":18446744073709551615}' INTO @all_privileges;
|
||||
SELECT '{"access":18446744073709551615,"plugin":"mysql_native_password","authentication_string":"invalid","auth_or":[{},{"plugin":"unix_socket"}]}' into @all_with_auth;
|
||||
|
||||
|
||||
-- Fill "global_priv" table with default users allowing root access
|
||||
-- from local machine if "global_priv" table didn't exist before
|
||||
@@ -37,12 +39,13 @@ REPLACE INTO tmp_user_nopasswd SELECT @current_hostname,'root',@all_privileges F
|
||||
REPLACE INTO tmp_user_nopasswd VALUES ('127.0.0.1','root',@all_privileges);
|
||||
REPLACE INTO tmp_user_nopasswd VALUES ('::1','root',@all_privileges);
|
||||
-- More secure root account using unix socket auth.
|
||||
INSERT INTO tmp_user_socket VALUES ('localhost',IFNULL(@auth_root_socket, 'root'),json_set(@all_privileges, '$.plugin', 'unix_socket'));
|
||||
INSERT INTO tmp_user_socket VALUES ('localhost', 'root',@all_with_auth);
|
||||
REPLACE INTO tmp_user_socket VALUES ('localhost',IFNULL(@auth_root_socket, 'root'),@all_with_auth);
|
||||
IF @auth_root_socket is not null THEN
|
||||
IF not exists(select 1 from information_schema.plugins where plugin_name='unix_socket') THEN
|
||||
INSTALL SONAME 'auth_socket'; END IF; END IF;
|
||||
|
||||
INSERT INTO global_priv SELECT * FROM tmp_user_nopasswd WHERE @had_user_table=0 AND @skip_auth_root_nopasswd IS NULL;
|
||||
INSERT INTO global_priv SELECT * FROM tmp_user_nopasswd WHERE @had_user_table=0 AND @auth_root_socket IS NULL;
|
||||
INSERT INTO global_priv SELECT * FROM tmp_user_socket WHERE @had_user_table=0 AND @auth_root_socket IS NOT NULL;
|
||||
DROP TABLE tmp_user_nopasswd, tmp_user_socket;
|
||||
|
||||
|
||||
@@ -753,8 +753,8 @@ else
|
||||
|
||||
if [[ "$sstlogarchive" -eq 1 ]]
|
||||
then
|
||||
ARCHIVETIMESTAMP=$(date "+%Y.%m.%d-%H.%M.%S")
|
||||
newfile=""
|
||||
ARCHIVETIMESTAMP=$(date "+%Y.%m.%d-%H.%M.%S.%N")
|
||||
newfile=""
|
||||
|
||||
if [[ ! -z "$sstlogarchivedir" ]]
|
||||
then
|
||||
|
||||
@@ -147,6 +147,7 @@ if ! [ -z $WSREP_SST_OPT_BINLOG_INDEX ]
|
||||
then
|
||||
BINLOG_INDEX_DIRNAME=$(dirname $WSREP_SST_OPT_BINLOG_INDEX)
|
||||
BINLOG_INDEX_FILENAME=$(basename $WSREP_SST_OPT_BINLOG_INDEX)
|
||||
BINLOG_INDEX_FILENAME=${BINLOG_INDEX_FILENAME%.index}.index
|
||||
fi
|
||||
|
||||
WSREP_LOG_DIR=${WSREP_LOG_DIR:-""}
|
||||
@@ -268,12 +269,12 @@ EOF
|
||||
OLD_PWD="$(pwd)"
|
||||
cd $BINLOG_DIRNAME
|
||||
|
||||
if ! [ -z $WSREP_SST_OPT_BINLOG_INDEX ]
|
||||
if [ -z $WSREP_SST_OPT_BINLOG_INDEX ]
|
||||
then
|
||||
binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index)
|
||||
binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index)
|
||||
else
|
||||
cd $BINLOG_INDEX_DIRNAME
|
||||
binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_INDEX_FILENAME}.index)
|
||||
cd $BINLOG_INDEX_DIRNAME
|
||||
binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_INDEX_FILENAME})
|
||||
fi
|
||||
|
||||
cd $BINLOG_DIRNAME
|
||||
@@ -510,16 +511,16 @@ EOF
|
||||
# Clean up old binlog files first
|
||||
rm -f ${BINLOG_FILENAME}.*
|
||||
wsrep_log_info "Extracting binlog files:"
|
||||
tar -xvf $BINLOG_TAR_FILE >&2
|
||||
for ii in $(ls -1 ${BINLOG_FILENAME}.*)
|
||||
do
|
||||
if ! [ -z $WSREP_SST_OPT_BINLOG_INDEX ]
|
||||
tar -xvf $BINLOG_TAR_FILE >> _binlog_tmp_files_$!
|
||||
while read bin_file; do
|
||||
if [ -z $WSREP_SST_OPT_BINLOG_INDEX ]
|
||||
then
|
||||
echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_FILENAME}.index
|
||||
echo ${BINLOG_DIRNAME}/${bin_file} >> ${BINLOG_FILENAME}.index
|
||||
else
|
||||
echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_INDEX_DIRNAME}/${BINLOG_INDEX_FILENAME}.index
|
||||
echo ${BINLOG_DIRNAME}/${bin_file} >> ${BINLOG_INDEX_DIRNAME}/${BINLOG_INDEX_FILENAME}
|
||||
fi
|
||||
done
|
||||
done < _binlog_tmp_files_$!
|
||||
rm -f _binlog_tmp_files_$!
|
||||
fi
|
||||
cd "$OLD_PWD"
|
||||
|
||||
|
||||
@@ -139,6 +139,7 @@ SET (SQL_SOURCE
|
||||
sql_sequence.cc sql_sequence.h ha_sequence.h
|
||||
sql_tvc.cc sql_tvc.h
|
||||
opt_split.cc
|
||||
opt_trace.cc
|
||||
${WSREP_SOURCES}
|
||||
table_cache.cc encryption.cc temporary_tables.cc
|
||||
proxy_protocol.cc backup.cc
|
||||
|
||||
@@ -443,6 +443,6 @@ maria_declare_plugin(sql_sequence)
|
||||
NULL, /* status variables */
|
||||
NULL, /* system variables */
|
||||
"1.0", /* string version */
|
||||
MariaDB_PLUGIN_MATURITY_ALPHA /* maturity */
|
||||
MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
|
||||
}
|
||||
maria_declare_plugin_end;
|
||||
|
||||
@@ -993,6 +993,7 @@ enum enum_schema_tables
|
||||
SCH_KEY_CACHES,
|
||||
SCH_KEY_COLUMN_USAGE,
|
||||
SCH_OPEN_TABLES,
|
||||
SCH_OPT_TRACE,
|
||||
SCH_PARAMETERS,
|
||||
SCH_PARTITIONS,
|
||||
SCH_PLUGINS,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "mariadb.h"
|
||||
#include "sql_priv.h"
|
||||
#include "sql_string.h"
|
||||
|
||||
#include "my_json_writer.h"
|
||||
|
||||
void Json_writer::append_indent()
|
||||
@@ -62,6 +61,7 @@ void Json_writer::end_object()
|
||||
indent_level-=INDENT_SIZE;
|
||||
if (!first_child)
|
||||
append_indent();
|
||||
first_child= false;
|
||||
output.append("}");
|
||||
}
|
||||
|
||||
@@ -129,7 +129,6 @@ void Json_writer::add_ll(longlong val)
|
||||
add_unquoted_str(buf);
|
||||
}
|
||||
|
||||
|
||||
/* Add a memory size, printing in Kb, Kb, Gb if necessary */
|
||||
void Json_writer::add_size(longlong val)
|
||||
{
|
||||
@@ -173,7 +172,7 @@ void Json_writer::add_null()
|
||||
|
||||
void Json_writer::add_unquoted_str(const char* str)
|
||||
{
|
||||
if (fmt_helper.on_add_str(str))
|
||||
if (fmt_helper.on_add_str(str, 0))
|
||||
return;
|
||||
|
||||
if (!element_started)
|
||||
@@ -183,10 +182,9 @@ void Json_writer::add_unquoted_str(const char* str)
|
||||
element_started= false;
|
||||
}
|
||||
|
||||
|
||||
void Json_writer::add_str(const char *str)
|
||||
{
|
||||
if (fmt_helper.on_add_str(str))
|
||||
if (fmt_helper.on_add_str(str, 0))
|
||||
return;
|
||||
|
||||
if (!element_started)
|
||||
@@ -198,12 +196,72 @@ void Json_writer::add_str(const char *str)
|
||||
element_started= false;
|
||||
}
|
||||
|
||||
/*
|
||||
This function is used to add only num_bytes of str to the output string
|
||||
*/
|
||||
|
||||
void Json_writer::add_str(const char* str, size_t num_bytes)
|
||||
{
|
||||
if (fmt_helper.on_add_str(str, num_bytes))
|
||||
return;
|
||||
|
||||
if (!element_started)
|
||||
start_element();
|
||||
|
||||
output.append('"');
|
||||
output.append(str, num_bytes);
|
||||
output.append('"');
|
||||
element_started= false;
|
||||
}
|
||||
|
||||
void Json_writer::add_str(const String &str)
|
||||
{
|
||||
add_str(str.ptr());
|
||||
add_str(str.ptr(), str.length());
|
||||
}
|
||||
|
||||
Json_writer_object::Json_writer_object(THD *thd) :
|
||||
Json_writer_struct(thd)
|
||||
{
|
||||
if (my_writer)
|
||||
my_writer->start_object();
|
||||
}
|
||||
|
||||
Json_writer_object::Json_writer_object(THD* thd, const char *str)
|
||||
: Json_writer_struct(thd)
|
||||
{
|
||||
if (my_writer)
|
||||
my_writer->add_member(str).start_object();
|
||||
}
|
||||
|
||||
Json_writer_object::~Json_writer_object()
|
||||
{
|
||||
if (!closed && my_writer)
|
||||
my_writer->end_object();
|
||||
closed= TRUE;
|
||||
}
|
||||
|
||||
Json_writer_array::Json_writer_array(THD *thd) :
|
||||
Json_writer_struct(thd)
|
||||
{
|
||||
if (my_writer)
|
||||
my_writer->start_array();
|
||||
}
|
||||
|
||||
Json_writer_array::Json_writer_array(THD *thd, const char *str)
|
||||
:Json_writer_struct(thd)
|
||||
{
|
||||
if (my_writer)
|
||||
my_writer->add_member(str).start_array();
|
||||
|
||||
}
|
||||
Json_writer_array::~Json_writer_array()
|
||||
{
|
||||
if (!closed && my_writer)
|
||||
{
|
||||
my_writer->end_array();
|
||||
closed= TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
bool Single_line_formatting_helper::on_add_member(const char *name)
|
||||
{
|
||||
@@ -267,11 +325,12 @@ void Single_line_formatting_helper::on_start_object()
|
||||
}
|
||||
|
||||
|
||||
bool Single_line_formatting_helper::on_add_str(const char *str)
|
||||
bool Single_line_formatting_helper::on_add_str(const char *str,
|
||||
size_t num_bytes)
|
||||
{
|
||||
if (state == IN_ARRAY)
|
||||
{
|
||||
size_t len= strlen(str);
|
||||
size_t len= num_bytes ? num_bytes : strlen(str);
|
||||
|
||||
// New length will be:
|
||||
// "$string",
|
||||
|
||||
@@ -13,7 +13,15 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
|
||||
|
||||
#ifndef JSON_WRITER_INCLUDED
|
||||
#define JSON_WRITER_INCLUDED
|
||||
#include "my_base.h"
|
||||
#include "sql_select.h"
|
||||
class Opt_trace_stmt;
|
||||
class Opt_trace_context;
|
||||
class Json_writer;
|
||||
struct TABLE_LIST;
|
||||
|
||||
|
||||
/*
|
||||
Single_line_formatting_helper is used by Json_writer to do better formatting
|
||||
@@ -85,13 +93,87 @@ public:
|
||||
void on_start_object();
|
||||
// on_end_object() is not needed.
|
||||
|
||||
bool on_add_str(const char *str);
|
||||
bool on_add_str(const char *str, size_t num_bytes);
|
||||
|
||||
void flush_on_one_line();
|
||||
void disable_and_flush();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Something that looks like class String, but has an internal limit of
|
||||
how many bytes one can append to it.
|
||||
|
||||
Bytes that were truncated due to the size limitation are counted.
|
||||
*/
|
||||
|
||||
class String_with_limit
|
||||
{
|
||||
public:
|
||||
|
||||
String_with_limit() : size_limit(SIZE_MAX), truncated_len(0)
|
||||
{
|
||||
str.length(0);
|
||||
}
|
||||
|
||||
size_t get_truncated_bytes() const { return truncated_len; }
|
||||
size_t get_size_limit() { return size_limit; }
|
||||
|
||||
void set_size_limit(size_t limit_arg)
|
||||
{
|
||||
// Setting size limit to be shorter than length will not have the desired
|
||||
// effect
|
||||
DBUG_ASSERT(str.length() < size_limit);
|
||||
size_limit= limit_arg;
|
||||
}
|
||||
|
||||
void append(const char *s, size_t size)
|
||||
{
|
||||
if (str.length() + size <= size_limit)
|
||||
{
|
||||
// Whole string can be added, just do it
|
||||
str.append(s, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We cannot add the whole string
|
||||
if (str.length() < size_limit)
|
||||
{
|
||||
// But we can still add something
|
||||
size_t bytes_to_add = size_limit - str.length();
|
||||
str.append(s, bytes_to_add);
|
||||
truncated_len += size - bytes_to_add;
|
||||
}
|
||||
else
|
||||
truncated_len += size;
|
||||
}
|
||||
}
|
||||
|
||||
void append(const char *s)
|
||||
{
|
||||
append(s, strlen(s));
|
||||
}
|
||||
|
||||
void append(char c)
|
||||
{
|
||||
if (str.length() + 1 > size_limit)
|
||||
truncated_len++;
|
||||
else
|
||||
str.append(c);
|
||||
}
|
||||
|
||||
const String *get_string() { return &str; }
|
||||
size_t length() { return str.length(); }
|
||||
private:
|
||||
String str;
|
||||
|
||||
// str must not get longer than this many bytes.
|
||||
size_t size_limit;
|
||||
|
||||
// How many bytes were truncated from the string
|
||||
size_t truncated_len;
|
||||
};
|
||||
|
||||
/*
|
||||
A class to write well-formed JSON documents. The documents are also formatted
|
||||
for human readability.
|
||||
@@ -105,7 +187,11 @@ public:
|
||||
|
||||
/* Add atomic values */
|
||||
void add_str(const char* val);
|
||||
void add_str(const char* val, size_t num_bytes);
|
||||
void add_str(const String &str);
|
||||
void add_str(Item *item);
|
||||
void add_table_name(const JOIN_TAB *tab);
|
||||
void add_table_name(const TABLE* table);
|
||||
|
||||
void add_ll(longlong val);
|
||||
void add_size(longlong val);
|
||||
@@ -123,9 +209,18 @@ public:
|
||||
void end_object();
|
||||
void end_array();
|
||||
|
||||
/*
|
||||
One can set a limit of how large a JSON document should be.
|
||||
Writes beyond that size will be counted, but will not be collected.
|
||||
*/
|
||||
void set_size_limit(size_t mem_size) { output.set_size_limit(mem_size); }
|
||||
|
||||
// psergey: return how many bytes would be required to store everything
|
||||
size_t get_truncated_bytes() { return output.get_truncated_bytes(); }
|
||||
|
||||
Json_writer() :
|
||||
indent_level(0), document_start(true), element_started(false),
|
||||
first_child(true)
|
||||
first_child(true), allowed_mem_size(0)
|
||||
{
|
||||
fmt_helper.init(this);
|
||||
}
|
||||
@@ -140,15 +235,335 @@ private:
|
||||
bool element_started;
|
||||
bool first_child;
|
||||
|
||||
/*
|
||||
True when we are using the optimizer trace
|
||||
FALSE otherwise
|
||||
*/
|
||||
size_t allowed_mem_size;
|
||||
|
||||
Single_line_formatting_helper fmt_helper;
|
||||
|
||||
void append_indent();
|
||||
void start_element();
|
||||
void start_sub_element();
|
||||
|
||||
//const char *new_member_name;
|
||||
public:
|
||||
String output;
|
||||
String_with_limit output;
|
||||
};
|
||||
|
||||
/* A class to add values to Json_writer_object and Json_writer_array */
|
||||
class Json_value_helper
|
||||
{
|
||||
Json_writer* writer;
|
||||
|
||||
public:
|
||||
void init(Json_writer *my_writer) { writer= my_writer; }
|
||||
void add_str(const char* val)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_str(val);
|
||||
}
|
||||
void add_str(const char* val, size_t length)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_str(val);
|
||||
}
|
||||
void add_str(const String &str)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_str(str);
|
||||
}
|
||||
void add_str(LEX_CSTRING str)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_str(str.str);
|
||||
}
|
||||
void add_str(Item *item)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_str(item);
|
||||
}
|
||||
|
||||
void add_ll(longlong val)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_ll(val);
|
||||
}
|
||||
void add_size(longlong val)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_size(val);
|
||||
}
|
||||
void add_double(double val)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_double(val);
|
||||
}
|
||||
void add_bool(bool val)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_bool(val);
|
||||
}
|
||||
void add_null()
|
||||
{
|
||||
if (writer)
|
||||
writer->add_null();
|
||||
}
|
||||
void add_table_name(const JOIN_TAB *tab)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_table_name(tab);
|
||||
}
|
||||
void add_table_name(const TABLE* table)
|
||||
{
|
||||
if (writer)
|
||||
writer->add_table_name(table);
|
||||
}
|
||||
};
|
||||
|
||||
/* A common base for Json_writer_object and Json_writer_array */
|
||||
class Json_writer_struct
|
||||
{
|
||||
protected:
|
||||
Json_writer* my_writer;
|
||||
Json_value_helper context;
|
||||
/*
|
||||
Tells when a json_writer_struct has been closed or not
|
||||
*/
|
||||
bool closed;
|
||||
|
||||
public:
|
||||
explicit Json_writer_struct(THD *thd)
|
||||
{
|
||||
my_writer= thd->opt_trace.get_current_json();
|
||||
context.init(my_writer);
|
||||
closed= false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
RAII-based class to start/end writing a JSON object into the JSON document
|
||||
|
||||
There is "ignore mode": one can initialize Json_writer_object with a NULL
|
||||
Json_writer argument, and then all its calls will do nothing. This is used
|
||||
by optimizer trace which can be enabled or disabled.
|
||||
*/
|
||||
|
||||
class Json_writer_object : public Json_writer_struct
|
||||
{
|
||||
private:
|
||||
void add_member(const char *name)
|
||||
{
|
||||
if (my_writer)
|
||||
my_writer->add_member(name);
|
||||
}
|
||||
public:
|
||||
explicit Json_writer_object(THD *thd);
|
||||
explicit Json_writer_object(THD *thd, const char *str);
|
||||
|
||||
Json_writer_object& add(const char *name, bool value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member(name);
|
||||
context.add_bool(value);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add(const char *name, ulonglong value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member(name);
|
||||
context.add_ll(static_cast<longlong>(value));
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add(const char *name, longlong value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member(name);
|
||||
context.add_ll(value);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add(const char *name, double value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member(name);
|
||||
context.add_double(value);
|
||||
return *this;
|
||||
}
|
||||
#ifndef _WIN64
|
||||
Json_writer_object& add(const char *name, size_t value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member(name);
|
||||
context.add_ll(static_cast<longlong>(value));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
Json_writer_object& add(const char *name, const char *value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member(name);
|
||||
context.add_str(value);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add(const char *name, const char *value, size_t num_bytes)
|
||||
{
|
||||
add_member(name);
|
||||
context.add_str(value, num_bytes);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add(const char *name, LEX_CSTRING value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member(name);
|
||||
context.add_str(value.str);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add(const char *name, Item *value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member(name);
|
||||
context.add_str(value);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add_null(const char*name)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member(name);
|
||||
context.add_null();
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add_table_name(const JOIN_TAB *tab)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member("table");
|
||||
context.add_table_name(tab);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add_table_name(const TABLE *table)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member("table");
|
||||
context.add_table_name(table);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_object& add_select_number(uint select_number)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
add_member("select_id");
|
||||
if (unlikely(select_number >= INT_MAX))
|
||||
context.add_str("fake");
|
||||
else
|
||||
context.add_ll(static_cast<longlong>(select_number));
|
||||
return *this;
|
||||
}
|
||||
void end()
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
if (my_writer)
|
||||
my_writer->end_object();
|
||||
closed= TRUE;
|
||||
}
|
||||
~Json_writer_object();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
RAII-based class to start/end writing a JSON array into the JSON document
|
||||
|
||||
There is "ignore mode": one can initialize Json_writer_array with a NULL
|
||||
Json_writer argument, and then all its calls will do nothing. This is used
|
||||
by optimizer trace which can be enabled or disabled.
|
||||
*/
|
||||
|
||||
class Json_writer_array : public Json_writer_struct
|
||||
{
|
||||
public:
|
||||
Json_writer_array(THD *thd);
|
||||
Json_writer_array(THD *thd, const char *str);
|
||||
void end()
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
if (my_writer)
|
||||
my_writer->end_array();
|
||||
closed= TRUE;
|
||||
}
|
||||
|
||||
Json_writer_array& add(bool value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_bool(value);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_array& add(ulonglong value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_ll(static_cast<longlong>(value));
|
||||
return *this;
|
||||
}
|
||||
Json_writer_array& add(longlong value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_ll(value);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_array& add(double value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_double(value);
|
||||
return *this;
|
||||
}
|
||||
#ifndef _WIN64
|
||||
Json_writer_array& add(size_t value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_ll(static_cast<longlong>(value));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
Json_writer_array& add(const char *value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_str(value);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_array& add(const char *value, size_t num_bytes)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_str(value, num_bytes);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_array& add(LEX_CSTRING value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_str(value.str);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_array& add(Item *value)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_str(value);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_array& add_null()
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_null();
|
||||
return *this;
|
||||
}
|
||||
Json_writer_array& add_table_name(const JOIN_TAB *tab)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_table_name(tab);
|
||||
return *this;
|
||||
}
|
||||
Json_writer_array& add_table_name(const TABLE *table)
|
||||
{
|
||||
DBUG_ASSERT(!closed);
|
||||
context.add_table_name(table);
|
||||
return *this;
|
||||
}
|
||||
~Json_writer_array();
|
||||
};
|
||||
|
||||
|
||||
@@ -192,4 +607,4 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -647,8 +647,6 @@ Lt_creator lt_creator;
|
||||
Ge_creator ge_creator;
|
||||
Le_creator le_creator;
|
||||
|
||||
int bootstrap_error;
|
||||
|
||||
THD_list server_threads;
|
||||
Rpl_filter* cur_rpl_filter;
|
||||
Rpl_filter* global_rpl_filter;
|
||||
@@ -1105,7 +1103,7 @@ static PSI_cond_info all_server_conds[]=
|
||||
{ &key_TABLE_SHARE_COND_rotation, "TABLE_SHARE::COND_rotation", 0}
|
||||
};
|
||||
|
||||
PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert,
|
||||
PSI_thread_key key_thread_delayed_insert,
|
||||
key_thread_handle_manager, key_thread_main,
|
||||
key_thread_one_connection, key_thread_signal_hand,
|
||||
key_thread_slave_background, key_rpl_parallel_thread;
|
||||
@@ -1113,7 +1111,6 @@ PSI_thread_key key_thread_ack_receiver;
|
||||
|
||||
static PSI_thread_info all_server_threads[]=
|
||||
{
|
||||
{ &key_thread_bootstrap, "bootstrap", PSI_FLAG_GLOBAL},
|
||||
{ &key_thread_delayed_insert, "delayed_insert", 0},
|
||||
{ &key_thread_handle_manager, "manager", PSI_FLAG_GLOBAL},
|
||||
{ &key_thread_main, "main", PSI_FLAG_GLOBAL},
|
||||
@@ -5768,9 +5765,9 @@ int mysqld_main(int argc, char **argv)
|
||||
if (opt_bootstrap)
|
||||
{
|
||||
select_thread_in_use= 0; // Allow 'kill' to work
|
||||
bootstrap(mysql_stdin);
|
||||
int bootstrap_error= bootstrap(mysql_stdin);
|
||||
if (!abort_loop)
|
||||
unireg_abort(bootstrap_error ? 1 : 0);
|
||||
unireg_abort(bootstrap_error);
|
||||
else
|
||||
{
|
||||
sleep(2); // Wait for kill
|
||||
|
||||
@@ -297,7 +297,6 @@ extern "C" MYSQL_PLUGIN_IMPORT char **orig_argv;
|
||||
extern pthread_attr_t connection_attrib;
|
||||
extern my_bool old_mode;
|
||||
extern LEX_STRING opt_init_connect, opt_init_slave;
|
||||
extern int bootstrap_error;
|
||||
extern char err_shared_dir[];
|
||||
extern ulong connection_errors_select;
|
||||
extern ulong connection_errors_accept;
|
||||
@@ -394,7 +393,7 @@ extern PSI_cond_key key_COND_rpl_thread, key_COND_rpl_thread_queue,
|
||||
extern PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates;
|
||||
extern PSI_cond_key key_TABLE_SHARE_COND_rotation;
|
||||
|
||||
extern PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert,
|
||||
extern PSI_thread_key key_thread_delayed_insert,
|
||||
key_thread_handle_manager, key_thread_kill_server, key_thread_main,
|
||||
key_thread_one_connection, key_thread_signal_hand,
|
||||
key_thread_slave_background, key_rpl_parallel_thread;
|
||||
|
||||
845
sql/opt_range.cc
845
sql/opt_range.cc
File diff suppressed because it is too large
Load Diff
@@ -566,7 +566,7 @@ public:
|
||||
FALSE Otherwise
|
||||
*/
|
||||
|
||||
bool is_singlepoint()
|
||||
bool is_singlepoint() const
|
||||
{
|
||||
/*
|
||||
Check for NEAR_MIN ("strictly less") and NO_MIN_RANGE (-inf < field)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "opt_subselect.h"
|
||||
#include "sql_test.h"
|
||||
#include <my_bit.h>
|
||||
#include "opt_trace.h"
|
||||
|
||||
/*
|
||||
This file contains optimizations for semi-join subqueries.
|
||||
@@ -437,7 +438,7 @@ Currently, solution #2 is implemented.
|
||||
LEX_CSTRING weedout_key= {STRING_WITH_LEN("weedout_key")};
|
||||
|
||||
static
|
||||
bool subquery_types_allow_materialization(Item_in_subselect *in_subs);
|
||||
bool subquery_types_allow_materialization(THD *thd, Item_in_subselect *in_subs);
|
||||
static bool replace_where_subcondition(JOIN *, Item **, Item *, Item *, bool);
|
||||
static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2,
|
||||
void *arg);
|
||||
@@ -521,7 +522,7 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
|
||||
parent_unit->first_select()->leaf_tables.elements && // 2
|
||||
child_select->outer_select() &&
|
||||
child_select->outer_select()->leaf_tables.elements && // 2A
|
||||
subquery_types_allow_materialization(in_subs) &&
|
||||
subquery_types_allow_materialization(thd, in_subs) &&
|
||||
(in_subs->is_top_level_item() || //3
|
||||
optimizer_flag(thd,
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE) || //3
|
||||
@@ -682,7 +683,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
||||
{
|
||||
DBUG_PRINT("info", ("Subquery is semi-join conversion candidate"));
|
||||
|
||||
(void)subquery_types_allow_materialization(in_subs);
|
||||
(void)subquery_types_allow_materialization(thd, in_subs);
|
||||
|
||||
in_subs->is_flattenable_semijoin= TRUE;
|
||||
|
||||
@@ -696,6 +697,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
in_subs->is_registered_semijoin= TRUE;
|
||||
OPT_TRACE_TRANSFORM(thd, oto0, oto1, select_lex->select_number,
|
||||
"IN (SELECT)", "semijoin");
|
||||
oto1.add("chosen", true);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -823,7 +827,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
||||
*/
|
||||
|
||||
static
|
||||
bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
|
||||
bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
|
||||
{
|
||||
DBUG_ENTER("subquery_types_allow_materialization");
|
||||
|
||||
@@ -831,9 +835,14 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
|
||||
|
||||
List_iterator<Item> it(in_subs->unit->first_select()->item_list);
|
||||
uint elements= in_subs->unit->first_select()->item_list.elements;
|
||||
const char* cause= NULL;
|
||||
|
||||
in_subs->types_allow_materialization= FALSE; // Assign default values
|
||||
in_subs->sjm_scan_allowed= FALSE;
|
||||
|
||||
OPT_TRACE_TRANSFORM(thd, oto0, oto1,
|
||||
in_subs->get_select_lex()->select_number,
|
||||
"IN (SELECT)", "materialization");
|
||||
|
||||
bool all_are_fields= TRUE;
|
||||
uint32 total_key_length = 0;
|
||||
@@ -846,7 +855,11 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
|
||||
total_key_length += inner->max_length;
|
||||
if (!inner->type_handler()->subquery_type_allows_materialization(inner,
|
||||
outer))
|
||||
{
|
||||
oto1.add("possible", false);
|
||||
oto1.add("cause", "types mismatch");
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -856,14 +869,23 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
|
||||
Make sure that the length of the key for the temp_table is atleast
|
||||
greater than 0.
|
||||
*/
|
||||
if (!total_key_length || total_key_length > tmp_table_max_key_length() ||
|
||||
elements > tmp_table_max_key_parts())
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
in_subs->types_allow_materialization= TRUE;
|
||||
in_subs->sjm_scan_allowed= all_are_fields;
|
||||
DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed"));
|
||||
DBUG_RETURN(TRUE);
|
||||
if (!total_key_length)
|
||||
cause= "zero length key for materialized table";
|
||||
else if (total_key_length > tmp_table_max_key_length())
|
||||
cause= "length of key greater than allowed key length for materialized tables";
|
||||
else if (elements > tmp_table_max_key_parts())
|
||||
cause= "#keyparts greater than allowed key parts for materialized tables";
|
||||
else
|
||||
{
|
||||
in_subs->types_allow_materialization= TRUE;
|
||||
in_subs->sjm_scan_allowed= all_are_fields;
|
||||
oto1.add("sjm_scan_allowed", all_are_fields)
|
||||
.add("possible", true);
|
||||
DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed"));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
oto1.add("possible", false).add("cause", cause);
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1213,15 +1235,30 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
|
||||
|
||||
/* Stop processing if we've reached a subquery that's attached to the ON clause */
|
||||
if (in_subq->do_not_convert_to_sj)
|
||||
{
|
||||
OPT_TRACE_TRANSFORM(thd, oto0, oto1,
|
||||
in_subq->get_select_lex()->select_number,
|
||||
"IN (SELECT)", "semijoin");
|
||||
oto1.add("converted_to_semi_join", false)
|
||||
.add("cause", "subquery attached to the ON clause");
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_subq->is_flattenable_semijoin)
|
||||
{
|
||||
OPT_TRACE_TRANSFORM(thd, oto0, oto1,
|
||||
in_subq->get_select_lex()->select_number,
|
||||
"IN (SELECT)", "semijoin");
|
||||
if (join->table_count +
|
||||
in_subq->unit->first_select()->join->table_count >= MAX_TABLES)
|
||||
{
|
||||
oto1.add("converted_to_semi_join", false);
|
||||
oto1.add("cause", "table in parent join now exceeds MAX_TABLES");
|
||||
break;
|
||||
}
|
||||
if (convert_subq_to_sj(join, in_subq))
|
||||
goto restore_arena_and_fail;
|
||||
oto1.add("converted_to_semi_join", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2340,8 +2377,13 @@ int pull_out_semijoin_tables(JOIN *join)
|
||||
bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
|
||||
{
|
||||
DBUG_ENTER("optimize_semijoin_nests");
|
||||
THD *thd= join->thd;
|
||||
List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
|
||||
TABLE_LIST *sj_nest;
|
||||
Json_writer_object wrapper(thd);
|
||||
Json_writer_object trace_semijoin_nest(thd,
|
||||
"execution_plan_for_potential_materialization");
|
||||
Json_writer_array trace_steps_array(thd, "steps");
|
||||
while ((sj_nest= sj_list_it++))
|
||||
{
|
||||
/* semi-join nests with only constant tables are not valid */
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "mariadb.h"
|
||||
#include "my_bit.h"
|
||||
#include "sql_select.h"
|
||||
#include "opt_trace.h"
|
||||
#include "my_json_writer.h"
|
||||
|
||||
/*
|
||||
OVERVIEW
|
||||
@@ -522,7 +524,8 @@ eliminate_tables_for_list(JOIN *join,
|
||||
List<TABLE_LIST> *join_list,
|
||||
table_map tables_in_list,
|
||||
Item *on_expr,
|
||||
table_map tables_used_elsewhere);
|
||||
table_map tables_used_elsewhere,
|
||||
Json_writer_array* eliminate_tables);
|
||||
static
|
||||
bool check_func_dependency(JOIN *join,
|
||||
table_map dep_tables,
|
||||
@@ -541,7 +544,8 @@ static
|
||||
Dep_module_expr *merge_eq_mods(Dep_module_expr *start,
|
||||
Dep_module_expr *new_fields,
|
||||
Dep_module_expr *end, uint and_level);
|
||||
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl);
|
||||
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl,
|
||||
Json_writer_array* eliminate_tables);
|
||||
static
|
||||
void add_module_expr(Dep_analysis_context *dac, Dep_module_expr **eq_mod,
|
||||
uint and_level, Dep_value_field *field_val, Item *right,
|
||||
@@ -608,6 +612,8 @@ void eliminate_tables(JOIN *join)
|
||||
if (!optimizer_flag(thd, OPTIMIZER_SWITCH_TABLE_ELIMINATION))
|
||||
DBUG_VOID_RETURN; /* purecov: inspected */
|
||||
|
||||
Json_writer_object trace_wrapper(thd);
|
||||
|
||||
/* Find the tables that are referred to from WHERE/HAVING */
|
||||
used_tables= (join->conds? join->conds->used_tables() : 0) |
|
||||
(join->having? join->having->used_tables() : 0);
|
||||
@@ -663,13 +669,14 @@ void eliminate_tables(JOIN *join)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
table_map all_tables= join->all_tables_map();
|
||||
Json_writer_array eliminated_tables(thd,"eliminated_tables");
|
||||
if (all_tables & ~used_tables)
|
||||
{
|
||||
/* There are some tables that we probably could eliminate. Try it. */
|
||||
eliminate_tables_for_list(join, join->join_list, all_tables, NULL,
|
||||
used_tables);
|
||||
used_tables, &eliminated_tables);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -712,7 +719,8 @@ void eliminate_tables(JOIN *join)
|
||||
static bool
|
||||
eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list,
|
||||
table_map list_tables, Item *on_expr,
|
||||
table_map tables_used_elsewhere)
|
||||
table_map tables_used_elsewhere,
|
||||
Json_writer_array *eliminate_tables)
|
||||
{
|
||||
TABLE_LIST *tbl;
|
||||
List_iterator<TABLE_LIST> it(*join_list);
|
||||
@@ -734,9 +742,9 @@ eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list,
|
||||
&tbl->nested_join->join_list,
|
||||
tbl->nested_join->used_tables,
|
||||
tbl->on_expr,
|
||||
outside_used_tables))
|
||||
outside_used_tables, eliminate_tables))
|
||||
{
|
||||
mark_as_eliminated(join, tbl);
|
||||
mark_as_eliminated(join, tbl, eliminate_tables);
|
||||
}
|
||||
else
|
||||
all_eliminated= FALSE;
|
||||
@@ -748,7 +756,7 @@ eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list,
|
||||
check_func_dependency(join, tbl->table->map, NULL, tbl,
|
||||
tbl->on_expr))
|
||||
{
|
||||
mark_as_eliminated(join, tbl);
|
||||
mark_as_eliminated(join, tbl, eliminate_tables);
|
||||
}
|
||||
else
|
||||
all_eliminated= FALSE;
|
||||
@@ -1788,7 +1796,8 @@ Dep_module* Dep_value_field::get_next_unbound_module(Dep_analysis_context *dac,
|
||||
Mark one table or the whole join nest as eliminated.
|
||||
*/
|
||||
|
||||
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl)
|
||||
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl,
|
||||
Json_writer_array* eliminate_tables)
|
||||
{
|
||||
TABLE *table;
|
||||
/*
|
||||
@@ -1801,7 +1810,7 @@ static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl)
|
||||
TABLE_LIST *child;
|
||||
List_iterator<TABLE_LIST> it(tbl->nested_join->join_list);
|
||||
while ((child= it++))
|
||||
mark_as_eliminated(join, child);
|
||||
mark_as_eliminated(join, child, eliminate_tables);
|
||||
}
|
||||
else if ((table= tbl->table))
|
||||
{
|
||||
@@ -1812,6 +1821,7 @@ static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl)
|
||||
tab->type= JT_CONST;
|
||||
tab->table->const_table= 1;
|
||||
join->eliminated_tables |= table->map;
|
||||
eliminate_tables->add(table->alias.c_ptr_safe());
|
||||
join->const_table_map|= table->map;
|
||||
set_position(join, join->const_tables++, tab, (KEYUSE*)0);
|
||||
}
|
||||
|
||||
722
sql/opt_trace.cc
Normal file
722
sql/opt_trace.cc
Normal file
@@ -0,0 +1,722 @@
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "mariadb.h"
|
||||
#include "sql_array.h"
|
||||
#include "sql_string.h"
|
||||
#include "sql_class.h"
|
||||
#include "sql_show.h"
|
||||
#include "field.h"
|
||||
#include "table.h"
|
||||
#include "opt_trace.h"
|
||||
#include "sql_parse.h"
|
||||
#include "set_var.h"
|
||||
#include "my_json_writer.h"
|
||||
#include "sp_head.h"
|
||||
|
||||
const char I_S_table_name[] = "OPTIMIZER_TRACE";
|
||||
|
||||
/**
|
||||
Whether a list of tables contains information_schema.OPTIMIZER_TRACE.
|
||||
@param tbl list of tables
|
||||
|
||||
Can we do better than this here??
|
||||
@note this does not catch that a stored routine or view accesses
|
||||
the OPTIMIZER_TRACE table. So using a stored routine or view to read
|
||||
OPTIMIZER_TRACE will overwrite OPTIMIZER_TRACE as it runs and provide
|
||||
uninteresting info.
|
||||
*/
|
||||
bool list_has_optimizer_trace_table(const TABLE_LIST *tbl)
|
||||
{
|
||||
for (; tbl; tbl = tbl->next_global)
|
||||
{
|
||||
if (tbl->schema_table &&
|
||||
0 == strcmp(tbl->schema_table->table_name, I_S_table_name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns if a query has a set command with optimizer_trace being switched on/off.
|
||||
True: Don't trace the query(uninteresting)
|
||||
*/
|
||||
|
||||
bool sets_var_optimizer_trace(enum enum_sql_command sql_command,
|
||||
List<set_var_base> *set_vars)
|
||||
{
|
||||
if (sql_command == SQLCOM_SET_OPTION)
|
||||
{
|
||||
List_iterator_fast<set_var_base> it(*set_vars);
|
||||
const set_var_base *var;
|
||||
while ((var = it++))
|
||||
if (var->is_var_optimizer_trace()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ST_FIELD_INFO optimizer_trace_info[] = {
|
||||
/* name, length, type, value, maybe_null, old_name, open_method */
|
||||
{"QUERY", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
|
||||
{"TRACE", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
|
||||
{"MISSING_BYTES_BEYOND_MAX_MEM_SIZE", 20, MYSQL_TYPE_LONG, 0, false, NULL,
|
||||
SKIP_OPEN_TABLE},
|
||||
{"INSUFFICIENT_PRIVILEGES", 1, MYSQL_TYPE_TINY, 0, false, NULL,
|
||||
SKIP_OPEN_TABLE},
|
||||
{NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}};
|
||||
|
||||
/*
|
||||
TODO: one-line needs to be implemented seperately
|
||||
*/
|
||||
const char *Opt_trace_context::flag_names[] = {"enabled", "default",
|
||||
NullS};
|
||||
|
||||
/*
|
||||
Returns if a particular command will be traced or not
|
||||
*/
|
||||
|
||||
inline bool sql_command_can_be_traced(enum enum_sql_command sql_command)
|
||||
{
|
||||
/*
|
||||
For first iteration we are only allowing select queries.
|
||||
TODO: change to allow other queries.
|
||||
*/
|
||||
return sql_command == SQLCOM_SELECT ||
|
||||
sql_command == SQLCOM_UPDATE ||
|
||||
sql_command == SQLCOM_DELETE ||
|
||||
sql_command == SQLCOM_DELETE_MULTI ||
|
||||
sql_command == SQLCOM_UPDATE_MULTI;
|
||||
}
|
||||
|
||||
void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex,
|
||||
Json_writer_object *writer)
|
||||
|
||||
{
|
||||
if (!thd->trace_started())
|
||||
return;
|
||||
char buff[1024];
|
||||
String str(buff, sizeof(buff), system_charset_info);
|
||||
str.length(0);
|
||||
select_lex->print(thd, &str,
|
||||
enum_query_type(QT_TO_SYSTEM_CHARSET |
|
||||
QT_SHOW_SELECT_NUMBER |
|
||||
QT_ITEM_IDENT_SKIP_DB_NAMES |
|
||||
QT_VIEW_INTERNAL
|
||||
));
|
||||
/*
|
||||
The output is not very pretty lots of back-ticks, the output
|
||||
is as the one in explain extended , lets try to improved it here.
|
||||
*/
|
||||
writer->add("expanded_query", str.c_ptr_safe(), str.length());
|
||||
}
|
||||
|
||||
void opt_trace_disable_if_no_security_context_access(THD *thd)
|
||||
{
|
||||
if (likely(!(thd->variables.optimizer_trace &
|
||||
Opt_trace_context::FLAG_ENABLED)) || // (1)
|
||||
thd->system_thread) // (2)
|
||||
{
|
||||
/*
|
||||
(1) We know that the routine's execution starts with "enabled=off".
|
||||
If it stays so until the routine ends, we needn't do security checks on
|
||||
the routine.
|
||||
If it does not stay so, it means the definer sets it to "on" somewhere
|
||||
in the routine's body. Then it is his conscious decision to generate
|
||||
traces, thus it is still correct to skip the security check.
|
||||
|
||||
(2) Threads of the Events Scheduler have an unusual security context
|
||||
(thd->m_main_security_ctx.priv_user==NULL, see comment in
|
||||
Security_context::change_security_context()).
|
||||
*/
|
||||
return;
|
||||
}
|
||||
Opt_trace_context *const trace = &thd->opt_trace;
|
||||
if (!thd->trace_started())
|
||||
{
|
||||
/*
|
||||
@@optimizer_trace has "enabled=on" but trace is not started.
|
||||
Either Opt_trace_start ctor was not called for our statement (3), or it
|
||||
was called but at that time, the variable had "enabled=off" (4).
|
||||
|
||||
There are no known cases of (3).
|
||||
|
||||
(4) suggests that the user managed to change the variable during
|
||||
execution of the statement, and this statement is using
|
||||
view/routine (note that we have not been able to provoke this, maybe
|
||||
this is impossible). If it happens it is suspicious.
|
||||
|
||||
We disable I_S output. And we cannot do otherwise: we have no place to
|
||||
store a possible "missing privilege" information (no Opt_trace_stmt, as
|
||||
is_started() is false), so cannot do security checks, so cannot safely
|
||||
do tracing, so have to disable I_S output. And even then, we don't know
|
||||
when to re-enable I_S output, as we have no place to store the
|
||||
information "re-enable tracing at the end of this statement", and we
|
||||
don't even have a notion of statement here (statements in the optimizer
|
||||
trace world mean an Opt_trace_stmt object, and there is none here). So
|
||||
we must disable for the session's life.
|
||||
|
||||
COM_FIELD_LIST opens views, thus used to be a case of (3). To avoid
|
||||
disabling I_S output for the session's life when this command is issued
|
||||
(like in: "SET OPTIMIZER_TRACE='ENABLED=ON';USE somedb;" in the 'mysql'
|
||||
command-line client), we have decided to create a Opt_trace_start for
|
||||
this command. The command itself is not traced though
|
||||
(SQLCOM_SHOW_FIELDS does not have CF_OPTIMIZER_TRACE).
|
||||
*/
|
||||
return;
|
||||
}
|
||||
/*
|
||||
Note that thd->main_security_ctx.master_access is probably invariant
|
||||
accross the life of THD: GRANT/REVOKE don't affect global privileges of an
|
||||
existing connection, per the manual.
|
||||
*/
|
||||
if (!(thd->main_security_ctx.check_access(GLOBAL_ACLS & ~GRANT_ACL)) &&
|
||||
(0 != strcmp(thd->main_security_ctx.priv_user,
|
||||
thd->security_context()->priv_user) ||
|
||||
0 != my_strcasecmp(system_charset_info,
|
||||
thd->main_security_ctx.priv_host,
|
||||
thd->security_context()->priv_host)))
|
||||
trace->missing_privilege();
|
||||
return;
|
||||
}
|
||||
|
||||
void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp)
|
||||
{
|
||||
if (likely(!(thd->variables.optimizer_trace &
|
||||
Opt_trace_context::FLAG_ENABLED)) ||
|
||||
thd->system_thread)
|
||||
return;
|
||||
|
||||
Opt_trace_context *const trace = &thd->opt_trace;
|
||||
if (!thd->trace_started())
|
||||
return;
|
||||
bool full_access;
|
||||
Security_context *const backup_thd_sctx = thd->security_context();
|
||||
thd->set_security_context(&thd->main_security_ctx);
|
||||
const bool rc = check_show_routine_access(thd, sp, &full_access) || !full_access;
|
||||
thd->set_security_context(backup_thd_sctx);
|
||||
if (rc)
|
||||
trace->missing_privilege();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
If tracing is on, checks additional privileges on a list of tables/views,
|
||||
to make sure that the user has the right to do SHOW CREATE TABLE/VIEW and
|
||||
"SELECT *". For that:
|
||||
- this functions checks table-level SELECT
|
||||
- which is sufficient for SHOW CREATE TABLE and "SELECT *", if a base table
|
||||
- if a view, if the view has not been identified as such then
|
||||
opt_trace_disable_if_no_view_access() will be later called and check SHOW
|
||||
VIEW; other we check SHOW VIEW here; SHOW VIEW + SELECT is sufficient for
|
||||
SHOW CREATE VIEW.
|
||||
If a privilege is missing, notifies the trace system.
|
||||
|
||||
@param thd
|
||||
@param tbl list of tables to check
|
||||
*/
|
||||
|
||||
void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl)
|
||||
{
|
||||
if (likely(!(thd->variables.optimizer_trace &
|
||||
Opt_trace_context::FLAG_ENABLED)) || thd->system_thread)
|
||||
return;
|
||||
Opt_trace_context *const trace = &thd->opt_trace;
|
||||
|
||||
if (!thd->trace_started())
|
||||
return;
|
||||
|
||||
Security_context *const backup_thd_sctx = thd->security_context();
|
||||
thd->set_security_context(&thd->main_security_ctx);
|
||||
const TABLE_LIST *const first_not_own_table = thd->lex->first_not_own_table();
|
||||
for (TABLE_LIST *t = tbl; t != NULL && t != first_not_own_table;
|
||||
t = t->next_global)
|
||||
{
|
||||
/*
|
||||
Anonymous derived tables (as in
|
||||
"SELECT ... FROM (SELECT ...)") don't have their grant.privilege set.
|
||||
*/
|
||||
if (!t->is_anonymous_derived_table())
|
||||
{
|
||||
const GRANT_INFO backup_grant_info = t->grant;
|
||||
Security_context *const backup_table_sctx = t->security_ctx;
|
||||
t->security_ctx = NULL;
|
||||
/*
|
||||
(1) check_table_access() fills t->grant.privilege.
|
||||
(2) Because SELECT privileges can be column-based,
|
||||
check_table_access() will return 'false' as long as there is SELECT
|
||||
privilege on one column. But we want a table-level privilege.
|
||||
*/
|
||||
|
||||
bool rc =
|
||||
check_table_access(thd, SELECT_ACL, t, false, 1, true) || // (1)
|
||||
((t->grant.privilege & SELECT_ACL) == 0); // (2)
|
||||
if (t->is_view())
|
||||
{
|
||||
/*
|
||||
It's a view which has already been opened: we are executing a
|
||||
prepared statement. The view has been unfolded in the global list of
|
||||
tables. So underlying tables will be automatically checked in the
|
||||
present function, but we need an explicit check of SHOW VIEW:
|
||||
*/
|
||||
rc |= check_table_access(thd, SHOW_VIEW_ACL, t, false, 1, true);
|
||||
}
|
||||
t->security_ctx = backup_table_sctx;
|
||||
t->grant = backup_grant_info;
|
||||
if (rc)
|
||||
{
|
||||
trace->missing_privilege();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
thd->set_security_context(backup_thd_sctx);
|
||||
return;
|
||||
}
|
||||
|
||||
void opt_trace_disable_if_no_view_access(THD *thd, TABLE_LIST *view,
|
||||
TABLE_LIST *underlying_tables)
|
||||
{
|
||||
|
||||
if (likely(!(thd->variables.optimizer_trace &
|
||||
Opt_trace_context::FLAG_ENABLED)) ||
|
||||
thd->system_thread)
|
||||
return;
|
||||
Opt_trace_context *const trace = &thd->opt_trace;
|
||||
if (!thd->trace_started())
|
||||
return;
|
||||
|
||||
Security_context *const backup_table_sctx = view->security_ctx;
|
||||
Security_context *const backup_thd_sctx = thd->security_context();
|
||||
const GRANT_INFO backup_grant_info = view->grant;
|
||||
|
||||
view->security_ctx = NULL; // no SUID context for view
|
||||
// no SUID context for THD
|
||||
thd->set_security_context(&thd->main_security_ctx);
|
||||
const int rc = check_table_access(thd, SHOW_VIEW_ACL, view, false, 1, true);
|
||||
|
||||
view->security_ctx = backup_table_sctx;
|
||||
thd->set_security_context(backup_thd_sctx);
|
||||
view->grant = backup_grant_info;
|
||||
|
||||
if (rc)
|
||||
{
|
||||
trace->missing_privilege();
|
||||
return;
|
||||
}
|
||||
/*
|
||||
We needn't check SELECT privilege on this view. Some
|
||||
opt_trace_disable_if_no_tables_access() call has or will check it.
|
||||
|
||||
Now we check underlying tables/views of our view:
|
||||
*/
|
||||
opt_trace_disable_if_no_tables_access(thd, underlying_tables);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@class Opt_trace_stmt
|
||||
|
||||
The trace of one statement.
|
||||
*/
|
||||
|
||||
class Opt_trace_stmt {
|
||||
public:
|
||||
/**
|
||||
Constructor, starts a trace for information_schema and dbug.
|
||||
@param ctx_arg context
|
||||
*/
|
||||
Opt_trace_stmt(Opt_trace_context *ctx_arg)
|
||||
{
|
||||
ctx= ctx_arg;
|
||||
current_json= new Json_writer();
|
||||
missing_priv= false;
|
||||
I_S_disabled= 0;
|
||||
}
|
||||
~Opt_trace_stmt()
|
||||
{
|
||||
delete current_json;
|
||||
missing_priv= false;
|
||||
ctx= NULL;
|
||||
I_S_disabled= 0;
|
||||
}
|
||||
void set_query(const char *query_ptr, size_t length, const CHARSET_INFO *charset);
|
||||
void open_struct(const char *key, char opening_bracket);
|
||||
void close_struct(const char *saved_key, char closing_bracket);
|
||||
void fill_info(Opt_trace_info* info);
|
||||
void add(const char *key, char *opening_bracket, size_t val_length);
|
||||
Json_writer* get_current_json(){return current_json;}
|
||||
void missing_privilege();
|
||||
void disable_tracing_for_children();
|
||||
void enable_tracing_for_children();
|
||||
bool is_enabled();
|
||||
|
||||
void set_allowed_mem_size(size_t mem_size);
|
||||
size_t get_length() { return current_json->output.length(); }
|
||||
size_t get_truncated_bytes() { return current_json->get_truncated_bytes(); }
|
||||
bool get_missing_priv() { return missing_priv; }
|
||||
|
||||
private:
|
||||
Opt_trace_context *ctx;
|
||||
String query; // store the query sent by the user
|
||||
Json_writer *current_json; // stores the trace
|
||||
bool missing_priv; ///< whether user lacks privilege to see this trace
|
||||
uint I_S_disabled;
|
||||
};
|
||||
|
||||
void Opt_trace_stmt::set_query(const char *query_ptr, size_t length,
|
||||
const CHARSET_INFO *charset)
|
||||
{
|
||||
query.append(query_ptr, length, charset);
|
||||
}
|
||||
|
||||
Json_writer* Opt_trace_context::get_current_json()
|
||||
{
|
||||
if (!is_started())
|
||||
return NULL;
|
||||
return current_trace->get_current_json();
|
||||
}
|
||||
|
||||
void Opt_trace_context::missing_privilege()
|
||||
{
|
||||
if (current_trace)
|
||||
current_trace->missing_privilege();
|
||||
}
|
||||
|
||||
void Opt_trace_context::set_allowed_mem_size(size_t mem_size)
|
||||
{
|
||||
current_trace->set_allowed_mem_size(mem_size);
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: In future when we would be saving multiple trace,
|
||||
this function would return
|
||||
max_mem_size - memory_occupied_by_the_saved_traces
|
||||
*/
|
||||
|
||||
size_t Opt_trace_context::remaining_mem_size()
|
||||
{
|
||||
return max_mem_size;
|
||||
}
|
||||
|
||||
bool Opt_trace_context::disable_tracing_if_required()
|
||||
{
|
||||
if (current_trace)
|
||||
{
|
||||
current_trace->disable_tracing_for_children();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Opt_trace_context::enable_tracing_if_required()
|
||||
{
|
||||
if (current_trace)
|
||||
{
|
||||
current_trace->enable_tracing_for_children();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Opt_trace_context::is_enabled()
|
||||
{
|
||||
if (current_trace)
|
||||
return current_trace->is_enabled();
|
||||
return false;
|
||||
}
|
||||
|
||||
Opt_trace_context::Opt_trace_context()
|
||||
{
|
||||
current_trace= NULL;
|
||||
inited= FALSE;
|
||||
traces= NULL;
|
||||
max_mem_size= 0;
|
||||
}
|
||||
Opt_trace_context::~Opt_trace_context()
|
||||
{
|
||||
inited= FALSE;
|
||||
/*
|
||||
would be nice to move this to a function
|
||||
*/
|
||||
if (traces)
|
||||
{
|
||||
while (traces->elements())
|
||||
{
|
||||
Opt_trace_stmt *prev= traces->at(0);
|
||||
delete prev;
|
||||
traces->del(0);
|
||||
}
|
||||
delete traces;
|
||||
traces= NULL;
|
||||
}
|
||||
max_mem_size= 0;
|
||||
}
|
||||
|
||||
void Opt_trace_context::set_query(const char *query, size_t length, const CHARSET_INFO *charset)
|
||||
{
|
||||
current_trace->set_query(query, length, charset);
|
||||
}
|
||||
|
||||
void Opt_trace_context::start(THD *thd, TABLE_LIST *tbl,
|
||||
enum enum_sql_command sql_command,
|
||||
const char *query,
|
||||
size_t query_length,
|
||||
const CHARSET_INFO *query_charset,
|
||||
ulong max_mem_size_arg)
|
||||
{
|
||||
/*
|
||||
This is done currently because we don't want to have multiple
|
||||
traces open at the same time, so as soon as a new trace is created
|
||||
we forcefully end the previous one, if it has not ended by itself.
|
||||
This would mostly happen with stored functions or procedures.
|
||||
|
||||
TODO: handle multiple traces
|
||||
*/
|
||||
DBUG_ASSERT(!current_trace);
|
||||
current_trace= new Opt_trace_stmt(this);
|
||||
max_mem_size= max_mem_size_arg;
|
||||
if (!inited)
|
||||
{
|
||||
traces= new Dynamic_array<Opt_trace_stmt*>();
|
||||
inited= TRUE;
|
||||
}
|
||||
set_allowed_mem_size(remaining_mem_size());
|
||||
}
|
||||
|
||||
void Opt_trace_context::end()
|
||||
{
|
||||
if (current_trace)
|
||||
traces->push(current_trace);
|
||||
|
||||
if (!traces->elements())
|
||||
return;
|
||||
if (traces->elements() > 1)
|
||||
{
|
||||
Opt_trace_stmt *prev= traces->at(0);
|
||||
delete prev;
|
||||
traces->del(0);
|
||||
}
|
||||
current_trace= NULL;
|
||||
}
|
||||
|
||||
Opt_trace_start::Opt_trace_start(THD *thd, TABLE_LIST *tbl,
|
||||
enum enum_sql_command sql_command,
|
||||
List<set_var_base> *set_vars,
|
||||
const char *query,
|
||||
size_t query_length,
|
||||
const CHARSET_INFO *query_charset):ctx(&thd->opt_trace)
|
||||
{
|
||||
/*
|
||||
if optimizer trace is enabled and the statment we have is traceable,
|
||||
then we start the context.
|
||||
*/
|
||||
const ulonglong var = thd->variables.optimizer_trace;
|
||||
traceable= FALSE;
|
||||
if (unlikely(var & Opt_trace_context::FLAG_ENABLED) &&
|
||||
sql_command_can_be_traced(sql_command) &&
|
||||
!list_has_optimizer_trace_table(tbl) &&
|
||||
!sets_var_optimizer_trace(sql_command, set_vars) &&
|
||||
!thd->system_thread &&
|
||||
!ctx->disable_tracing_if_required())
|
||||
{
|
||||
ctx->start(thd, tbl, sql_command, query, query_length, query_charset,
|
||||
thd->variables.optimizer_trace_max_mem_size);
|
||||
ctx->set_query(query, query_length, query_charset);
|
||||
traceable= TRUE;
|
||||
opt_trace_disable_if_no_tables_access(thd, tbl);
|
||||
}
|
||||
}
|
||||
|
||||
Opt_trace_start::~Opt_trace_start()
|
||||
{
|
||||
if (traceable)
|
||||
{
|
||||
ctx->end();
|
||||
traceable= FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->enable_tracing_if_required();
|
||||
}
|
||||
}
|
||||
|
||||
void Opt_trace_stmt::fill_info(Opt_trace_info* info)
|
||||
{
|
||||
if (unlikely(info->missing_priv = get_missing_priv()))
|
||||
{
|
||||
info->trace_ptr = info->query_ptr = "";
|
||||
info->trace_length = info->query_length = 0;
|
||||
info->query_charset = &my_charset_bin;
|
||||
info->missing_bytes = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->trace_ptr = current_json->output.get_string()->ptr();
|
||||
info->trace_length = get_length();
|
||||
info->query_ptr = query.ptr();
|
||||
info->query_length = query.length();
|
||||
info->query_charset = query.charset();
|
||||
info->missing_bytes = get_truncated_bytes();
|
||||
info->missing_priv= get_missing_priv();
|
||||
}
|
||||
}
|
||||
|
||||
void Opt_trace_stmt::missing_privilege()
|
||||
{
|
||||
missing_priv= true;
|
||||
}
|
||||
|
||||
void Opt_trace_stmt::disable_tracing_for_children()
|
||||
{
|
||||
++I_S_disabled;
|
||||
}
|
||||
|
||||
void Opt_trace_stmt::enable_tracing_for_children()
|
||||
{
|
||||
if (I_S_disabled)
|
||||
--I_S_disabled;
|
||||
}
|
||||
|
||||
bool Opt_trace_stmt::is_enabled()
|
||||
{
|
||||
return I_S_disabled == 0;
|
||||
}
|
||||
|
||||
void Opt_trace_stmt::set_allowed_mem_size(size_t mem_size)
|
||||
{
|
||||
current_json->set_size_limit(mem_size);
|
||||
}
|
||||
|
||||
/*
|
||||
Prefer this when you are iterating over JOIN_TABs
|
||||
*/
|
||||
|
||||
void Json_writer::add_table_name(const JOIN_TAB *tab)
|
||||
{
|
||||
if (tab != NULL)
|
||||
{
|
||||
char table_name_buffer[SAFE_NAME_LEN];
|
||||
if (tab->table && tab->table->derived_select_number)
|
||||
{
|
||||
/* Derived table name generation */
|
||||
size_t len= my_snprintf(table_name_buffer, sizeof(table_name_buffer)-1,
|
||||
"<derived%u>",
|
||||
tab->table->derived_select_number);
|
||||
add_str(table_name_buffer, len);
|
||||
}
|
||||
else if (tab->bush_children)
|
||||
{
|
||||
JOIN_TAB *ctab= tab->bush_children->start;
|
||||
size_t len= my_snprintf(table_name_buffer,
|
||||
sizeof(table_name_buffer)-1,
|
||||
"<subquery%d>",
|
||||
ctab->emb_sj_nest->sj_subq_pred->get_identifier());
|
||||
add_str(table_name_buffer, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
TABLE_LIST *real_table= tab->table->pos_in_table_list;
|
||||
add_str(real_table->alias.str, real_table->alias.length);
|
||||
}
|
||||
}
|
||||
else
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
|
||||
void Json_writer::add_table_name(const TABLE *table)
|
||||
{
|
||||
add_str(table->pos_in_table_list->alias.str);
|
||||
}
|
||||
|
||||
|
||||
void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab)
|
||||
{
|
||||
Json_writer_object table_records(thd);
|
||||
table_records.add_table_name(tab);
|
||||
Json_writer_object table_rec(thd, "table_scan");
|
||||
table_rec.add("rows", tab->found_records)
|
||||
.add("cost", tab->read_time);
|
||||
}
|
||||
/*
|
||||
Introduce enum_query_type flags parameter, maybe also allow
|
||||
EXPLAIN also use this function.
|
||||
*/
|
||||
|
||||
void Json_writer::add_str(Item *item)
|
||||
{
|
||||
if (item)
|
||||
{
|
||||
THD *thd= current_thd;
|
||||
char buff[256];
|
||||
String str(buff, sizeof(buff), system_charset_info);
|
||||
str.length(0);
|
||||
|
||||
ulonglong save_option_bits= thd->variables.option_bits;
|
||||
thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
|
||||
item->print(&str,
|
||||
enum_query_type(QT_TO_SYSTEM_CHARSET | QT_SHOW_SELECT_NUMBER
|
||||
| QT_ITEM_IDENT_SKIP_DB_NAMES));
|
||||
thd->variables.option_bits= save_option_bits;
|
||||
add_str(str.c_ptr_safe());
|
||||
}
|
||||
else
|
||||
add_null();
|
||||
}
|
||||
|
||||
void Opt_trace_context::flush_optimizer_trace()
|
||||
{
|
||||
inited= false;
|
||||
if (traces)
|
||||
{
|
||||
while (traces->elements())
|
||||
{
|
||||
Opt_trace_stmt *prev= traces->at(0);
|
||||
delete prev;
|
||||
traces->del(0);
|
||||
}
|
||||
delete traces;
|
||||
traces= NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *)
|
||||
{
|
||||
TABLE *table = tables->table;
|
||||
Opt_trace_info info;
|
||||
|
||||
/* get_values of trace, query , missing bytes and missing_priv
|
||||
|
||||
@todo: Need an iterator here to walk over all the traces
|
||||
*/
|
||||
Opt_trace_context* ctx= &thd->opt_trace;
|
||||
|
||||
if (thd->opt_trace.empty())
|
||||
{
|
||||
Opt_trace_stmt *stmt= ctx->get_top_trace();
|
||||
stmt->fill_info(&info);
|
||||
|
||||
table->field[0]->store(info.query_ptr, static_cast<uint>(info.query_length),
|
||||
info.query_charset);
|
||||
table->field[1]->store(info.trace_ptr, static_cast<uint>(info.trace_length),
|
||||
system_charset_info);
|
||||
table->field[2]->store(info.missing_bytes, true);
|
||||
table->field[3]->store(info.missing_priv, true);
|
||||
// Store in IS
|
||||
if (schema_table_store_record(thd, table))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
201
sql/opt_trace.h
Normal file
201
sql/opt_trace.h
Normal file
@@ -0,0 +1,201 @@
|
||||
#ifndef OPT_TRACE_INCLUDED
|
||||
#define OPT_TRACE_INCLUDED
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "opt_trace_context.h" // Opt_trace_context
|
||||
#include "sql_lex.h"
|
||||
#include "my_json_writer.h"
|
||||
#include "sql_select.h"
|
||||
class Item;
|
||||
class THD;
|
||||
struct TABLE_LIST;
|
||||
|
||||
class Opt_trace_stmt;
|
||||
|
||||
/*
|
||||
User-visible information about a trace.
|
||||
*/
|
||||
|
||||
struct Opt_trace_info
|
||||
{
|
||||
/**
|
||||
String containing trace.
|
||||
If trace has been end()ed, this is 0-terminated, which is only to aid
|
||||
debugging or unit testing; this property is not relied upon in normal
|
||||
server usage.
|
||||
If trace has not been ended, this is not 0-terminated. That rare case can
|
||||
happen when a substatement reads OPTIMIZER_TRACE (at that stage, the top
|
||||
statement is still executing so its trace is not ended yet, but may still
|
||||
be read by the sub-statement).
|
||||
*/
|
||||
const char *trace_ptr;
|
||||
size_t trace_length;
|
||||
//// String containing original query.
|
||||
const char *query_ptr;
|
||||
size_t query_length;
|
||||
const CHARSET_INFO *query_charset; ///< charset of query string
|
||||
/**
|
||||
How many bytes this trace is missing (for traces which were truncated
|
||||
because of @@@@optimizer-trace-max-mem-size).
|
||||
The trace is not extended beyond trace-max-mem-size.
|
||||
*/
|
||||
size_t missing_bytes;
|
||||
/*
|
||||
Whether user lacks privilege to see this trace.
|
||||
If this is set to TRUE, then we return an empty trace
|
||||
*/
|
||||
bool missing_priv;
|
||||
};
|
||||
|
||||
/**
|
||||
Instantiate this class to start tracing a THD's actions (generally at a
|
||||
statement's start), and to set the "original" query (not transformed, as
|
||||
sent by client) for the new trace. Destructor will end the trace.
|
||||
|
||||
@param thd the THD
|
||||
@param tbl list of tables read/written by the statement.
|
||||
@param sql_command SQL command being prepared or executed
|
||||
@param set_vars what variables are set by this command (only used if
|
||||
sql_command is SQLCOM_SET_OPTION)
|
||||
@param query query
|
||||
@param length query's length
|
||||
@param charset charset which was used to encode this query
|
||||
*/
|
||||
|
||||
|
||||
class Opt_trace_start {
|
||||
public:
|
||||
Opt_trace_start(THD *thd_arg, TABLE_LIST *tbl,
|
||||
enum enum_sql_command sql_command,
|
||||
List<set_var_base> *set_vars,
|
||||
const char *query,
|
||||
size_t query_length,
|
||||
const CHARSET_INFO *query_charset);
|
||||
~Opt_trace_start();
|
||||
|
||||
private:
|
||||
Opt_trace_context *const ctx;
|
||||
/*
|
||||
True: the query will be traced
|
||||
False: otherwise
|
||||
*/
|
||||
bool traceable;
|
||||
};
|
||||
|
||||
/**
|
||||
Prints SELECT query to optimizer trace. It is not the original query (as in
|
||||
@c Opt_trace_context::set_query()) but a printout of the parse tree
|
||||
(Item-s).
|
||||
@param thd the THD
|
||||
@param select_lex query's parse tree
|
||||
@param trace_object Json_writer object to which the query will be added
|
||||
*/
|
||||
void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex,
|
||||
Json_writer_object *trace_object);
|
||||
|
||||
void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab);
|
||||
|
||||
/*
|
||||
Security related (need to add a proper comment here)
|
||||
*/
|
||||
|
||||
/**
|
||||
If the security context is not that of the connected user, inform the trace
|
||||
system that a privilege is missing. With one exception: see below.
|
||||
|
||||
@param thd
|
||||
|
||||
This serves to eliminate the following issue.
|
||||
Any information readable by a SELECT may theoretically end up in
|
||||
the trace. And a SELECT may read information from other places than tables:
|
||||
- from views (reading their bodies)
|
||||
- from stored routines (reading their bodies)
|
||||
- from files (reading their content), with LOAD_FILE()
|
||||
- from the list of connections (reading their queries...), with
|
||||
I_S.PROCESSLIST.
|
||||
If the connected user has EXECUTE privilege on a routine which does a
|
||||
security context change, the routine can retrieve information internally
|
||||
(if allowed by the SUID context's privileges), and present only a portion
|
||||
of it to the connected user. But with tracing on, all information is
|
||||
possibly in the trace. So the connected user receives more information than
|
||||
the routine's definer intended to provide. Fixing this issue would require
|
||||
adding, near many privilege checks in the server, a new
|
||||
optimizer-trace-specific check done against the connected user's context,
|
||||
to verify that the connected user has the right to see the retrieved
|
||||
information.
|
||||
|
||||
Instead, our chosen simpler solution is that if we see a security context
|
||||
change where SUID user is not the connected user, we disable tracing. With
|
||||
only one safe exception: if the connected user has all global privileges
|
||||
(because then she/he can find any information anyway). By "all global
|
||||
privileges" we mean everything but WITH GRANT OPTION (that latter one isn't
|
||||
related to information gathering).
|
||||
|
||||
Read access to I_S.OPTIMIZER_TRACE by another user than the connected user
|
||||
is restricted: @see fill_optimizer_trace_info().
|
||||
*/
|
||||
void opt_trace_disable_if_no_security_context_access(THD *thd);
|
||||
|
||||
void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl);
|
||||
|
||||
/**
|
||||
If tracing is on, checks additional privileges for a view, to make sure
|
||||
that the user has the right to do SHOW CREATE VIEW. For that:
|
||||
- this function checks SHOW VIEW
|
||||
- SELECT is tested in opt_trace_disable_if_no_tables_access()
|
||||
- SELECT + SHOW VIEW is sufficient for SHOW CREATE VIEW.
|
||||
We also check underlying tables.
|
||||
If a privilege is missing, notifies the trace system.
|
||||
This function should be called when the view's underlying tables have not
|
||||
yet been merged.
|
||||
|
||||
@param thd THD context
|
||||
@param view view to check
|
||||
@param underlying_tables underlying tables/views of 'view'
|
||||
*/
|
||||
|
||||
void opt_trace_disable_if_no_view_access(THD *thd, TABLE_LIST *view,
|
||||
TABLE_LIST *underlying_tables);
|
||||
|
||||
/**
|
||||
If tracing is on, checks additional privileges on a stored routine, to make
|
||||
sure that the user has the right to do SHOW CREATE PROCEDURE/FUNCTION. For
|
||||
that, we use the same checks as in those SHOW commands.
|
||||
If a privilege is missing, notifies the trace system.
|
||||
|
||||
This function is not redundant with
|
||||
opt_trace_disable_if_no_security_context_access().
|
||||
Indeed, for a SQL SECURITY INVOKER routine, there is no context change, but
|
||||
we must still verify that the invoker can do SHOW CREATE.
|
||||
|
||||
For triggers, see note in sp_head::execute_trigger().
|
||||
|
||||
@param thd
|
||||
@param sp routine to check
|
||||
*/
|
||||
void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp);
|
||||
|
||||
/**
|
||||
Fills information_schema.OPTIMIZER_TRACE with rows (one per trace)
|
||||
@retval 0 ok
|
||||
@retval 1 error
|
||||
*/
|
||||
int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *);
|
||||
|
||||
#define OPT_TRACE_TRANSFORM(writer, object_level0, object_level1, \
|
||||
select_number, from, to) \
|
||||
Json_writer_object object_level0(writer); \
|
||||
Json_writer_object object_level1(writer, "transformation"); \
|
||||
object_level1.add_select_number(select_number).add("from", from).add("to", to);
|
||||
#endif
|
||||
92
sql/opt_trace_context.h
Normal file
92
sql/opt_trace_context.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#ifndef OPT_TRACE_CONTEXT_INCLUDED
|
||||
#define OPT_TRACE_CONTEXT_INCLUDED
|
||||
|
||||
#include "sql_array.h"
|
||||
|
||||
class Opt_trace_stmt;
|
||||
|
||||
class Opt_trace_context
|
||||
{
|
||||
public:
|
||||
Opt_trace_context();
|
||||
~Opt_trace_context();
|
||||
|
||||
void start(THD *thd, TABLE_LIST *tbl,
|
||||
enum enum_sql_command sql_command,
|
||||
const char *query,
|
||||
size_t query_length,
|
||||
const CHARSET_INFO *query_charset,
|
||||
ulong max_mem_size_arg);
|
||||
void end();
|
||||
void set_query(const char *query, size_t length, const CHARSET_INFO *charset);
|
||||
void flush_optimizer_trace();
|
||||
void set_allowed_mem_size(size_t mem_size);
|
||||
size_t remaining_mem_size();
|
||||
|
||||
private:
|
||||
Opt_trace_stmt* top_trace()
|
||||
{
|
||||
return *(traces->front());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
This returns the top trace from the list of traces. This function
|
||||
is used when we want to see the contents of the INFORMATION_SCHEMA.OPTIMIZER_TRACE
|
||||
table.
|
||||
*/
|
||||
|
||||
Opt_trace_stmt* get_top_trace()
|
||||
{
|
||||
if (!traces || !traces->elements())
|
||||
return NULL;
|
||||
return top_trace();
|
||||
}
|
||||
|
||||
/*
|
||||
This returns the current trace, to which we are still writing and has not been finished
|
||||
*/
|
||||
|
||||
Json_writer* get_current_json();
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return traces && (static_cast<uint>(traces->elements()) != 0);
|
||||
}
|
||||
|
||||
bool is_started()
|
||||
{
|
||||
return current_trace && is_enabled();
|
||||
}
|
||||
|
||||
bool disable_tracing_if_required();
|
||||
|
||||
bool enable_tracing_if_required();
|
||||
|
||||
bool is_enabled();
|
||||
|
||||
void missing_privilege();
|
||||
|
||||
static const char *flag_names[];
|
||||
enum
|
||||
{
|
||||
FLAG_DEFAULT = 0,
|
||||
FLAG_ENABLED = 1 << 0
|
||||
};
|
||||
|
||||
private:
|
||||
/*
|
||||
List of traces (currently it stores only 1 trace)
|
||||
*/
|
||||
Dynamic_array<Opt_trace_stmt*> *traces;
|
||||
Opt_trace_stmt *current_trace;
|
||||
/*
|
||||
TRUE: if we allocate memory for list of traces
|
||||
FALSE: otherwise
|
||||
*/
|
||||
bool inited;
|
||||
size_t max_mem_size;
|
||||
};
|
||||
|
||||
#endif /* OPT_TRACE_CONTEXT_INCLUDED */
|
||||
@@ -275,6 +275,10 @@ public:
|
||||
virtual int update(THD *thd)=0; /* To set the value */
|
||||
virtual int light_check(THD *thd) { return check(thd); } /* for PS */
|
||||
virtual bool is_system() { return FALSE; }
|
||||
/**
|
||||
@returns whether this variable is @@@@optimizer_trace.
|
||||
*/
|
||||
virtual bool is_var_optimizer_trace() const { return false; }
|
||||
};
|
||||
|
||||
|
||||
@@ -306,6 +310,11 @@ public:
|
||||
int check(THD *thd);
|
||||
int update(THD *thd);
|
||||
int light_check(THD *thd);
|
||||
virtual bool is_var_optimizer_trace() const
|
||||
{
|
||||
extern sys_var *Sys_optimizer_trace_ptr;
|
||||
return var == Sys_optimizer_trace_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "sql_derived.h" // mysql_handle_derived
|
||||
#include "sql_cte.h"
|
||||
#include "sql_select.h" // Virtual_tmp_table
|
||||
#include "opt_trace.h"
|
||||
#include "my_json_writer.h"
|
||||
|
||||
#ifdef USE_PRAGMA_IMPLEMENTATION
|
||||
#pragma implementation
|
||||
@@ -1146,6 +1148,8 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
|
||||
if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
opt_trace_disable_if_no_security_context_access(thd);
|
||||
|
||||
/* init per-instruction memroot */
|
||||
init_sql_alloc(&execute_mem_root, "per_instruction_memroot",
|
||||
MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
|
||||
@@ -1982,6 +1986,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
|
||||
thd->variables.option_bits&= ~OPTION_BIN_LOG;
|
||||
}
|
||||
|
||||
opt_trace_disable_if_no_stored_proc_func_access(thd, this);
|
||||
/*
|
||||
Switch to call arena/mem_root so objects like sp_cursor or
|
||||
Item_cache holders for case expressions can be allocated on it.
|
||||
@@ -2272,6 +2277,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
||||
err_status= set_routine_security_ctx(thd, this, &save_security_ctx);
|
||||
#endif
|
||||
|
||||
opt_trace_disable_if_no_stored_proc_func_access(thd, this);
|
||||
if (!err_status)
|
||||
{
|
||||
err_status= execute(thd, TRUE);
|
||||
@@ -3297,6 +3303,13 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
|
||||
thd->lex->safe_to_cache_query= 0;
|
||||
#endif
|
||||
|
||||
Opt_trace_start ots(thd, m_lex->query_tables,
|
||||
SQLCOM_SELECT, &m_lex->var_list,
|
||||
NULL, 0,
|
||||
thd->variables.character_set_client);
|
||||
|
||||
Json_writer_object trace_command(thd);
|
||||
Json_writer_array trace_command_steps(thd, "steps");
|
||||
if (open_tables)
|
||||
res= check_dependencies_in_with_clauses(m_lex->with_clauses_list) ||
|
||||
instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
|
||||
|
||||
@@ -2024,6 +2024,7 @@ private:
|
||||
|
||||
}; // class sp_instr_set_case_expr : public sp_instr_opt_meta
|
||||
|
||||
bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access);
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
bool
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
#include "wsrep_thd.h"
|
||||
#include "wsrep_trans_observer.h"
|
||||
#endif /* WITH_WSREP */
|
||||
#include "opt_trace.h"
|
||||
|
||||
#ifdef HAVE_SYS_SYSCALL_H
|
||||
#include <sys/syscall.h>
|
||||
@@ -1410,6 +1411,7 @@ void THD::change_user(void)
|
||||
sp_cache_clear(&sp_func_cache);
|
||||
sp_cache_clear(&sp_package_spec_cache);
|
||||
sp_cache_clear(&sp_package_body_cache);
|
||||
opt_trace.flush_optimizer_trace();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2187,6 +2189,11 @@ void THD::reset_globals()
|
||||
net.thd= 0;
|
||||
}
|
||||
|
||||
bool THD::trace_started()
|
||||
{
|
||||
return opt_trace.is_started();
|
||||
}
|
||||
|
||||
/*
|
||||
Cleanup after query.
|
||||
|
||||
@@ -4337,6 +4344,13 @@ bool Security_context::set_user(char *user_arg)
|
||||
return user == 0;
|
||||
}
|
||||
|
||||
bool Security_context::check_access(ulong want_access, bool match_any)
|
||||
{
|
||||
DBUG_ENTER("Security_context::check_access");
|
||||
DBUG_RETURN((match_any ? (master_access & want_access)
|
||||
: ((master_access & want_access) == want_access)));
|
||||
}
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
/**
|
||||
Initialize this security context from the passed in credentials
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "rpl_tblmap.h"
|
||||
#include "mdl.h"
|
||||
#include "field.h" // Create_field
|
||||
#include "opt_trace_context.h"
|
||||
#include "probes_mysql.h"
|
||||
#include "sql_locale.h" /* my_locale_st */
|
||||
#include "sql_profile.h" /* PROFILING */
|
||||
@@ -569,6 +570,8 @@ typedef struct system_variables
|
||||
ulonglong long_query_time;
|
||||
ulonglong max_statement_time;
|
||||
ulonglong optimizer_switch;
|
||||
ulonglong optimizer_trace;
|
||||
ulong optimizer_trace_max_mem_size;
|
||||
sql_mode_t sql_mode; ///< which non-standard SQL behaviour should be enabled
|
||||
sql_mode_t old_behavior; ///< which old SQL behaviour should be enabled
|
||||
ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING
|
||||
@@ -1350,6 +1353,14 @@ public:
|
||||
restore_security_context(THD *thd, Security_context *backup);
|
||||
#endif
|
||||
bool user_matches(Security_context *);
|
||||
/**
|
||||
Check global access
|
||||
@param want_access The required privileges
|
||||
@param match_any if the security context must match all or any of the req.
|
||||
* privileges.
|
||||
@return True if the security context fulfills the access requirements.
|
||||
*/
|
||||
bool check_access(ulong want_access, bool match_any = false);
|
||||
};
|
||||
|
||||
|
||||
@@ -2306,6 +2317,8 @@ public:
|
||||
|
||||
Security_context main_security_ctx;
|
||||
Security_context *security_ctx;
|
||||
Security_context *security_context() const { return security_ctx; }
|
||||
void set_security_context(Security_context *sctx) { security_ctx = sctx; }
|
||||
|
||||
/*
|
||||
Points to info-string that we show in SHOW PROCESSLIST
|
||||
@@ -2989,6 +3002,7 @@ public:
|
||||
ulonglong bytes_sent_old;
|
||||
ulonglong affected_rows; /* Number of changed rows */
|
||||
|
||||
Opt_trace_context opt_trace;
|
||||
pthread_t real_id; /* For debugging */
|
||||
my_thread_id thread_id, thread_dbug_id;
|
||||
uint32 os_thread_id;
|
||||
@@ -3297,6 +3311,7 @@ public:
|
||||
void reset_for_reuse();
|
||||
bool store_globals();
|
||||
void reset_globals();
|
||||
bool trace_started();
|
||||
#ifdef SIGNAL_WITH_VIO_CLOSE
|
||||
inline void set_active_vio(Vio* vio)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "sql_acl.h" // SELECT_ACL
|
||||
#include "sql_class.h"
|
||||
#include "sql_cte.h"
|
||||
#include "my_json_writer.h"
|
||||
|
||||
typedef bool (*dt_processor)(THD *thd, LEX *lex, TABLE_LIST *derived);
|
||||
|
||||
@@ -199,6 +200,7 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases)
|
||||
if ((res= (*processors[phase])(lex->thd, lex, derived)))
|
||||
break;
|
||||
}
|
||||
|
||||
lex->thd->derived_tables_processing= FALSE;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
@@ -369,6 +371,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
|
||||
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
|
||||
(derived->alias.str ? derived->alias.str : "<NULL>"),
|
||||
derived->get_unit()));
|
||||
const char *cause= NULL;
|
||||
|
||||
if (derived->merged)
|
||||
{
|
||||
@@ -380,6 +383,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
|
||||
if (dt_select->uncacheable & UNCACHEABLE_RAND)
|
||||
{
|
||||
/* There is random function => fall back to materialization. */
|
||||
cause= "Random function in the select";
|
||||
derived->change_refs_to_fields();
|
||||
derived->set_materialized_derived();
|
||||
DBUG_RETURN(FALSE);
|
||||
@@ -409,15 +413,11 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
|
||||
and small subqueries, and the bigger one can't be merged it wouldn't
|
||||
block the smaller one.
|
||||
*/
|
||||
if (parent_lex->get_free_table_map(&map, &tablenr))
|
||||
{
|
||||
/* There is no enough table bits, fall back to materialization. */
|
||||
goto unconditional_materialization;
|
||||
}
|
||||
|
||||
if (dt_select->leaf_tables.elements + tablenr > MAX_TABLES)
|
||||
if (parent_lex->get_free_table_map(&map, &tablenr) ||
|
||||
dt_select->leaf_tables.elements + tablenr > MAX_TABLES)
|
||||
{
|
||||
/* There is no enough table bits, fall back to materialization. */
|
||||
cause= "Not enough table bits to merge subquery";
|
||||
goto unconditional_materialization;
|
||||
}
|
||||
|
||||
@@ -494,6 +494,24 @@ exit_merge:
|
||||
DBUG_RETURN(res);
|
||||
|
||||
unconditional_materialization:
|
||||
|
||||
if (unlikely(thd->trace_started()))
|
||||
{
|
||||
/*
|
||||
Add to the optimizer trace the change in choice for merged
|
||||
derived tables/views to materialised ones.
|
||||
*/
|
||||
Json_writer_object trace_wrapper(thd);
|
||||
Json_writer_object trace_derived(thd, derived->is_derived() ?
|
||||
"derived" : "view");
|
||||
trace_derived.add("table", derived->alias.str ? derived->alias.str : "<NULL>")
|
||||
.add_select_number(derived->get_unit()->
|
||||
first_select()->select_number)
|
||||
.add("initial_choice", "merged")
|
||||
.add("final_choice", "materialized")
|
||||
.add("cause", cause);
|
||||
}
|
||||
|
||||
derived->change_refs_to_fields();
|
||||
derived->set_materialized_derived();
|
||||
if (!derived->table || !derived->table->is_created())
|
||||
@@ -662,7 +680,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
|
||||
DBUG_ENTER("mysql_derived_prepare");
|
||||
DBUG_PRINT("enter", ("unit: %p table_list: %p alias: '%s'",
|
||||
unit, derived, derived->alias.str));
|
||||
|
||||
if (!unit)
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
@@ -755,6 +772,22 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(thd->trace_started()))
|
||||
{
|
||||
/*
|
||||
Add to optimizer trace whether a derived table/view
|
||||
is merged into the parent select or not.
|
||||
*/
|
||||
Json_writer_object trace_wrapper(thd);
|
||||
Json_writer_object trace_derived(thd, derived->is_derived() ?
|
||||
"derived" : "view");
|
||||
trace_derived.add("table", derived->alias.str ? derived->alias.str : "<NULL>")
|
||||
.add_select_number(derived->get_unit()->first_select()->select_number);
|
||||
if (derived->is_materialized_derived())
|
||||
trace_derived.add("materialized", true);
|
||||
if (derived->is_merged_derived())
|
||||
trace_derived.add("merged", true);
|
||||
}
|
||||
/*
|
||||
Above cascade call of prepare is important for PS protocol, but after it
|
||||
is called we can check if we really need prepare for this derived
|
||||
|
||||
@@ -236,7 +236,7 @@ void Explain_query::print_explain_json(select_result_sink *output,
|
||||
|
||||
CHARSET_INFO *cs= system_charset_info;
|
||||
List<Item> item_list;
|
||||
String *buf= &writer.output;
|
||||
const String *buf= writer.output.get_string();
|
||||
item_list.push_back(new (thd->mem_root)
|
||||
Item_string(thd, buf->ptr(), buf->length(), cs),
|
||||
thd->mem_root);
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
#include "set_var.h"
|
||||
#include "sql_bootstrap.h"
|
||||
#include "sql_sequence.h"
|
||||
#include "opt_trace.h"
|
||||
|
||||
#include "my_json_writer.h"
|
||||
|
||||
@@ -979,8 +980,9 @@ static char *fgets_fn(char *buffer, size_t size, fgets_input_t input, int *error
|
||||
}
|
||||
|
||||
|
||||
void bootstrap(MYSQL_FILE *file)
|
||||
int bootstrap(MYSQL_FILE *file)
|
||||
{
|
||||
int bootstrap_error= 0;
|
||||
DBUG_ENTER("handle_bootstrap");
|
||||
|
||||
THD *thd= new THD(next_thread_id());
|
||||
@@ -1105,7 +1107,7 @@ void bootstrap(MYSQL_FILE *file)
|
||||
thd->lex->restore_set_statement_var();
|
||||
}
|
||||
delete thd;
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(bootstrap_error);
|
||||
}
|
||||
|
||||
|
||||
@@ -3411,6 +3413,13 @@ mysql_execute_command(THD *thd)
|
||||
#ifdef HAVE_REPLICATION
|
||||
} /* endif unlikely slave */
|
||||
#endif
|
||||
Opt_trace_start ots(thd, all_tables, lex->sql_command, &lex->var_list,
|
||||
thd->query(), thd->query_length(),
|
||||
thd->variables.character_set_client);
|
||||
|
||||
Json_writer_object trace_command(thd);
|
||||
Json_writer_array trace_command_steps(thd, "steps");
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
if (WSREP(thd))
|
||||
{
|
||||
|
||||
@@ -99,7 +99,7 @@ void create_table_set_open_action_and_adjust_tables(LEX *lex);
|
||||
void mysql_init_multi_delete(LEX *lex);
|
||||
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
|
||||
void create_table_set_open_action_and_adjust_tables(LEX *lex);
|
||||
void bootstrap(MYSQL_FILE *file);
|
||||
int bootstrap(MYSQL_FILE *file);
|
||||
int mysql_execute_command(THD *thd);
|
||||
bool do_command(THD *thd);
|
||||
bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
|
||||
@@ -112,6 +112,7 @@ When one supplies long data for a placeholder:
|
||||
#include "sp_cache.h"
|
||||
#include "sql_handler.h" // mysql_ha_rm_tables
|
||||
#include "probes_mysql.h"
|
||||
#include "opt_trace.h"
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
/* include MYSQL_BIND headers */
|
||||
#include <mysql.h>
|
||||
@@ -2273,6 +2274,17 @@ static bool check_prepared_statement(Prepared_statement *stmt)
|
||||
lex->first_select_lex()->context.resolve_in_table_list_only(select_lex->
|
||||
get_table_list());
|
||||
|
||||
/*
|
||||
For the optimizer trace, this is the symmetric, for statement preparation,
|
||||
of what is done at statement execution (in mysql_execute_command()).
|
||||
*/
|
||||
Opt_trace_start ots(thd, tables, lex->sql_command, &lex->var_list,
|
||||
thd->query(), thd->query_length(),
|
||||
thd->variables.character_set_client);
|
||||
|
||||
Json_writer_object trace_command(thd);
|
||||
Json_writer_array trace_command_steps(thd, "steps");
|
||||
|
||||
/* Reset warning count for each query that uses tables */
|
||||
if (tables)
|
||||
thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -63,6 +63,7 @@
|
||||
#include "ha_partition.h"
|
||||
#endif
|
||||
#include "transaction.h"
|
||||
#include "opt_trace.h"
|
||||
|
||||
enum enum_i_s_events_fields
|
||||
{
|
||||
@@ -9764,6 +9765,10 @@ ST_FIELD_INFO check_constraints_fields_info[]=
|
||||
OPEN_FULL_TABLE},
|
||||
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
|
||||
};
|
||||
|
||||
/** For creating fields of information_schema.OPTIMIZER_TRACE */
|
||||
extern ST_FIELD_INFO optimizer_trace_info[];
|
||||
|
||||
/*
|
||||
Description of ST_FIELD_INFO in table.h
|
||||
|
||||
@@ -9816,6 +9821,8 @@ ST_SCHEMA_TABLE schema_tables[]=
|
||||
OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
|
||||
{"OPEN_TABLES", open_tables_fields_info, 0,
|
||||
fill_open_tables, make_old_format, 0, -1, -1, 1, 0},
|
||||
{"OPTIMIZER_TRACE", optimizer_trace_info, 0,
|
||||
fill_optimizer_trace_info, NULL, NULL, -1, -1, false, 0},
|
||||
{"PARAMETERS", parameters_fields_info, 0,
|
||||
fill_schema_proc, 0, 0, -1, -1, 0, 0},
|
||||
{"PARTITIONS", partitions_fields_info, 0,
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "sql_show.h" // calc_sum_of_all_status
|
||||
#include "sql_select.h"
|
||||
#include "keycaches.h"
|
||||
#include "my_json_writer.h"
|
||||
#include <hash.h>
|
||||
#include <thr_alarm.h>
|
||||
#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
|
||||
@@ -36,6 +37,8 @@
|
||||
#include "events.h"
|
||||
#endif
|
||||
|
||||
#define FT_KEYPART (MAX_FIELDS+10)
|
||||
|
||||
static const char *lock_descriptions[] =
|
||||
{
|
||||
/* TL_UNLOCK */ "No lock",
|
||||
@@ -225,8 +228,6 @@ TEST_join(JOIN *join)
|
||||
}
|
||||
|
||||
|
||||
#define FT_KEYPART (MAX_FIELDS+10)
|
||||
|
||||
static void print_keyuse(KEYUSE *keyuse)
|
||||
{
|
||||
char buff[256];
|
||||
@@ -263,7 +264,6 @@ void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array)
|
||||
DBUG_UNLOCK_FILE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Print the current state during query optimization.
|
||||
|
||||
@@ -655,3 +655,24 @@ Memory allocated by threads: %s\n",
|
||||
puts("");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void print_keyuse_array_for_trace(THD *thd, DYNAMIC_ARRAY *keyuse_array)
|
||||
{
|
||||
Json_writer_object wrapper(thd);
|
||||
Json_writer_array trace_key_uses(thd, "ref_optimizer_key_uses");
|
||||
for(uint i=0; i < keyuse_array->elements; i++)
|
||||
{
|
||||
KEYUSE *keyuse= (KEYUSE*)dynamic_array_ptr(keyuse_array, i);
|
||||
Json_writer_object keyuse_elem(thd);
|
||||
keyuse_elem.add_table_name(keyuse->table->reginfo.join_tab);
|
||||
keyuse_elem.add("field", (keyuse->keypart == FT_KEYPART) ? "<fulltext>"
|
||||
: (keyuse->is_for_hash_join()
|
||||
? keyuse->table->field[keyuse->keypart]
|
||||
->field_name.str
|
||||
: keyuse->table->key_info[keyuse->key]
|
||||
.key_part[keyuse->keypart]
|
||||
.field->field_name.str));
|
||||
keyuse_elem.add("equals",keyuse->val);
|
||||
keyuse_elem.add("null_rejecting",keyuse->null_rejecting);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define SQL_TEST_INCLUDED
|
||||
|
||||
#include "mysqld.h"
|
||||
#include "opt_trace_context.h"
|
||||
|
||||
class JOIN;
|
||||
struct TABLE_LIST;
|
||||
@@ -34,6 +35,7 @@ void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array);
|
||||
void print_sjm(SJ_MATERIALIZATION_INFO *sjm);
|
||||
void dump_TABLE_LIST_graph(SELECT_LEX *select_lex, TABLE_LIST* tl);
|
||||
#endif
|
||||
void print_keyuse_array_for_trace(THD *thd, DYNAMIC_ARRAY *keyuse_array);
|
||||
void mysql_print_status();
|
||||
|
||||
#endif /* SQL_TEST_INCLUDED */
|
||||
|
||||
@@ -2435,6 +2435,12 @@ public:
|
||||
length(0); // safety
|
||||
}
|
||||
int save_in_field(Field *field, uint decimals) const;
|
||||
Datetime to_datetime(THD *thd) const
|
||||
{
|
||||
return is_zero_datetime() ?
|
||||
Datetime() :
|
||||
Datetime(thd, Timestamp_or_zero_datetime(*this).tv());
|
||||
}
|
||||
bool is_zero_datetime() const
|
||||
{
|
||||
return length() == 0;
|
||||
@@ -2459,7 +2465,7 @@ public:
|
||||
Datetime to_datetime(THD *thd) const
|
||||
{
|
||||
return is_null() ? Datetime() :
|
||||
Datetime(thd, Timestamp_or_zero_datetime(*this).tv());
|
||||
Timestamp_or_zero_datetime_native::to_datetime(thd);
|
||||
}
|
||||
void to_TIME(THD *thd, MYSQL_TIME *to)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "datadict.h" // dd_frm_is_view()
|
||||
#include "sql_derived.h"
|
||||
#include "sql_cte.h" // check_dependencies_in_with_clauses()
|
||||
#include "opt_trace.h"
|
||||
|
||||
#define MD5_BUFF_LENGTH 33
|
||||
|
||||
@@ -1419,6 +1420,15 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
|
||||
if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
Check rights to run commands which show underlying tables.
|
||||
In the optimizer trace we would not like to show trace for
|
||||
cases when the current user does not have rights for the
|
||||
underlying tables.
|
||||
*/
|
||||
if (!table->prelocking_placeholder)
|
||||
opt_trace_disable_if_no_view_access(thd, table, view_tables);
|
||||
|
||||
/*
|
||||
Check rights to run commands (ANALYZE SELECT, EXPLAIN SELECT &
|
||||
SHOW CREATE) which show underlying tables.
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include <myisam.h>
|
||||
#include "debug_sync.h" // DEBUG_SYNC
|
||||
#include "sql_show.h"
|
||||
#include "opt_trace_context.h"
|
||||
|
||||
#include "log_event.h"
|
||||
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
|
||||
@@ -2542,6 +2543,23 @@ static Sys_var_flagset Sys_optimizer_switch(
|
||||
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
|
||||
ON_UPDATE(fix_optimizer_switch));
|
||||
|
||||
static Sys_var_flagset Sys_optimizer_trace(
|
||||
"optimizer_trace",
|
||||
"Controls tracing of the Optimizer:"
|
||||
" optimizer_trace=option=val[,option=val...], where option is one of"
|
||||
" {enabled}"
|
||||
" and val is one of {on, off, default}",
|
||||
SESSION_VAR(optimizer_trace), CMD_LINE(REQUIRED_ARG),
|
||||
Opt_trace_context::flag_names, DEFAULT(Opt_trace_context::FLAG_DEFAULT));
|
||||
// @see set_var::is_var_optimizer_trace()
|
||||
export sys_var *Sys_optimizer_trace_ptr = &Sys_optimizer_trace;
|
||||
|
||||
static Sys_var_ulong Sys_optimizer_trace_max_mem_size(
|
||||
"optimizer_trace_max_mem_size",
|
||||
"Maximum allowed size of an optimizer trace",
|
||||
SESSION_VAR(optimizer_trace_max_mem_size), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(0, ULONG_MAX), DEFAULT(1024 * 1024), BLOCK_SIZE(1));
|
||||
|
||||
static Sys_var_charptr Sys_pid_file(
|
||||
"pid_file", "Pid file used by safe_mysqld",
|
||||
READ_ONLY GLOBAL_VAR(pidfile_name_ptr), CMD_LINE(REQUIRED_ARG),
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "sql_cte.h"
|
||||
#include "ha_sequence.h"
|
||||
#include "sql_show.h"
|
||||
#include "opt_trace.h"
|
||||
|
||||
/* For MySQL 5.7 virtual fields */
|
||||
#define MYSQL57_GENERATED_FIELD 128
|
||||
@@ -5714,6 +5715,7 @@ bool TABLE_LIST::prepare_security(THD *thd)
|
||||
if (prepare_view_security_context(thd))
|
||||
DBUG_RETURN(TRUE);
|
||||
thd->security_ctx= find_view_security_context(thd);
|
||||
opt_trace_disable_if_no_security_context_access(thd);
|
||||
while ((tbl= tb++))
|
||||
{
|
||||
DBUG_ASSERT(tbl->referencing_view);
|
||||
|
||||
@@ -1884,7 +1884,6 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
|
||||
}
|
||||
|
||||
static void wsrep_TOI_end(THD *thd) {
|
||||
int ret;
|
||||
wsrep_to_isolation--;
|
||||
wsrep::client_state& client_state(thd->wsrep_cs());
|
||||
DBUG_ASSERT(wsrep_thd_is_local_toi(thd));
|
||||
@@ -1894,18 +1893,8 @@ static void wsrep_TOI_end(THD *thd) {
|
||||
if (wsrep_thd_is_local_toi(thd))
|
||||
{
|
||||
wsrep_set_SE_checkpoint(client_state.toi_meta().gtid());
|
||||
if (thd->is_error() && !wsrep_must_ignore_error(thd))
|
||||
{
|
||||
wsrep_apply_error err;
|
||||
err.store(thd);
|
||||
client_state.leave_toi();
|
||||
}
|
||||
else
|
||||
{
|
||||
ret= client_state.leave_toi();
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
int ret= client_state.leave_toi();
|
||||
if (!ret)
|
||||
{
|
||||
WSREP_DEBUG("TO END: %lld", client_state.toi_meta().seqno().get());
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ Wsrep_server_state::Wsrep_server_state(const std::string& name,
|
||||
: wsrep::server_state(m_mutex,
|
||||
m_cond,
|
||||
m_service,
|
||||
NULL,
|
||||
name,
|
||||
incoming_address,
|
||||
address,
|
||||
|
||||
@@ -337,7 +337,8 @@ static int generate_binlog_index_opt_val(char** ret)
|
||||
{
|
||||
DBUG_ASSERT(ret);
|
||||
*ret= NULL;
|
||||
if (opt_binlog_index_name) {
|
||||
if (opt_bin_log)
|
||||
{
|
||||
*ret= strcmp(opt_binlog_index_name, "0") ?
|
||||
my_strdup(opt_binlog_index_name, MYF(0)) : my_strdup("", MYF(0));
|
||||
}
|
||||
@@ -1293,7 +1294,9 @@ static int sst_donate_other (const char* method,
|
||||
}
|
||||
|
||||
const char* binlog_opt= "";
|
||||
const char* binlog_index_opt= "";
|
||||
char* binlog_opt_val= NULL;
|
||||
char* binlog_index_opt_val= NULL;
|
||||
|
||||
int ret;
|
||||
if ((ret= generate_binlog_opt_val(&binlog_opt_val)))
|
||||
@@ -1301,7 +1304,15 @@ static int sst_donate_other (const char* method,
|
||||
WSREP_ERROR("sst_donate_other(): generate_binlog_opt_val() failed: %d",ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret= generate_binlog_index_opt_val(&binlog_index_opt_val)))
|
||||
{
|
||||
WSREP_ERROR("sst_prepare_other(): generate_binlog_index_opt_val() failed %d",
|
||||
ret);
|
||||
}
|
||||
|
||||
if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG;
|
||||
if (strlen(binlog_index_opt_val)) binlog_index_opt= WSREP_SST_OPT_BINLOG_INDEX;
|
||||
|
||||
make_wsrep_defaults_file();
|
||||
|
||||
@@ -1315,15 +1326,18 @@ static int sst_donate_other (const char* method,
|
||||
WSREP_SST_OPT_DATA " '%s' "
|
||||
" %s "
|
||||
" %s '%s' "
|
||||
" %s '%s' "
|
||||
WSREP_SST_OPT_GTID " '%s:%lld' "
|
||||
WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'"
|
||||
"%s",
|
||||
method, addr, mysqld_unix_port, mysql_real_data_home,
|
||||
wsrep_defaults_file,
|
||||
binlog_opt, binlog_opt_val,
|
||||
binlog_index_opt, binlog_index_opt_val,
|
||||
uuid_oss.str().c_str(), gtid.seqno().get(), wsrep_gtid_domain_id,
|
||||
bypass ? " " WSREP_SST_OPT_BYPASS : "");
|
||||
my_free(binlog_opt_val);
|
||||
my_free(binlog_index_opt_val);
|
||||
|
||||
if (ret < 0 || ret >= cmd_len)
|
||||
{
|
||||
@@ -1397,4 +1411,3 @@ int wsrep_sst_donate(const std::string& msg,
|
||||
|
||||
return (ret >= 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2014, 2018, MariaDB Corporation.
|
||||
Copyright (c) 2014, 2019, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -225,7 +225,7 @@ btr_root_block_get(
|
||||
|
||||
buf_block_t* block = btr_block_get(
|
||||
page_id_t(index->table->space_id, index->page),
|
||||
page_size_t(index->table->space->flags), mode,
|
||||
index->table->space->zip_size(), mode,
|
||||
index, mtr);
|
||||
|
||||
if (!block) {
|
||||
@@ -363,7 +363,7 @@ btr_root_adjust_on_import(
|
||||
page_zip_des_t* page_zip;
|
||||
dict_table_t* table = index->table;
|
||||
const page_id_t page_id(table->space_id, index->page);
|
||||
const page_size_t page_size(table->space->flags);
|
||||
const ulint zip_size = table->space->zip_size();
|
||||
|
||||
DBUG_EXECUTE_IF("ib_import_trigger_corruption_3",
|
||||
return(DB_CORRUPTION););
|
||||
@@ -372,7 +372,7 @@ btr_root_adjust_on_import(
|
||||
|
||||
mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO);
|
||||
|
||||
block = btr_block_get(page_id, page_size, RW_X_LATCH, index, &mtr);
|
||||
block = btr_block_get(page_id, zip_size, RW_X_LATCH, index, &mtr);
|
||||
|
||||
page = buf_block_get_frame(block);
|
||||
page_zip = buf_block_get_page_zip(block);
|
||||
@@ -474,7 +474,7 @@ btr_page_alloc_for_ibuf(
|
||||
|
||||
new_block = buf_page_get(
|
||||
page_id_t(index->table->space_id, node_addr.page),
|
||||
page_size_t(index->table->space->flags),
|
||||
index->table->space->zip_size(),
|
||||
RW_X_LATCH, mtr);
|
||||
|
||||
new_page = buf_block_get_frame(new_block);
|
||||
@@ -928,7 +928,7 @@ btr_node_ptr_get_child(
|
||||
return btr_block_get(
|
||||
page_id_t(index->table->space_id,
|
||||
btr_node_ptr_get_child_page_no(node_ptr, offsets)),
|
||||
page_size_t(index->table->space->flags),
|
||||
index->table->space->zip_size(),
|
||||
RW_SX_LATCH, index, mtr);
|
||||
}
|
||||
|
||||
@@ -1137,7 +1137,7 @@ btr_free_root_invalidate(
|
||||
|
||||
/** Prepare to free a B-tree.
|
||||
@param[in] page_id page id
|
||||
@param[in] page_size page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] index_id PAGE_INDEX_ID contents
|
||||
@param[in,out] mtr mini-transaction
|
||||
@return root block, to invoke btr_free_but_not_root() and btr_free_root()
|
||||
@@ -1146,7 +1146,7 @@ static MY_ATTRIBUTE((warn_unused_result))
|
||||
buf_block_t*
|
||||
btr_free_root_check(
|
||||
const page_id_t page_id,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
index_id_t index_id,
|
||||
mtr_t* mtr)
|
||||
{
|
||||
@@ -1154,7 +1154,7 @@ btr_free_root_check(
|
||||
ut_ad(index_id != BTR_FREED_INDEX_ID);
|
||||
|
||||
buf_block_t* block = buf_page_get(
|
||||
page_id, page_size, RW_X_LATCH, mtr);
|
||||
page_id, zip_size, RW_X_LATCH, mtr);
|
||||
|
||||
if (block) {
|
||||
buf_block_dbg_add_level(block, SYNC_TREE_NODE);
|
||||
@@ -1368,18 +1368,18 @@ top_loop:
|
||||
|
||||
/** Free a persistent index tree if it exists.
|
||||
@param[in] page_id root page id
|
||||
@param[in] page_size page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] index_id PAGE_INDEX_ID contents
|
||||
@param[in,out] mtr mini-transaction */
|
||||
void
|
||||
btr_free_if_exists(
|
||||
const page_id_t page_id,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
index_id_t index_id,
|
||||
mtr_t* mtr)
|
||||
{
|
||||
buf_block_t* root = btr_free_root_check(
|
||||
page_id, page_size, index_id, mtr);
|
||||
page_id, zip_size, index_id, mtr);
|
||||
|
||||
if (root == NULL) {
|
||||
return;
|
||||
@@ -1392,20 +1392,15 @@ btr_free_if_exists(
|
||||
btr_free_root_invalidate(root, mtr);
|
||||
}
|
||||
|
||||
/** Free an index tree in a temporary tablespace or during TRUNCATE TABLE.
|
||||
@param[in] page_id root page id
|
||||
@param[in] page_size page size */
|
||||
void
|
||||
btr_free(
|
||||
const page_id_t page_id,
|
||||
const page_size_t& page_size)
|
||||
/** Free an index tree in a temporary tablespace.
|
||||
@param[in] page_id root page id */
|
||||
void btr_free(const page_id_t page_id)
|
||||
{
|
||||
mtr_t mtr;
|
||||
mtr.start();
|
||||
mtr.set_log_mode(MTR_LOG_NO_REDO);
|
||||
|
||||
buf_block_t* block = buf_page_get(
|
||||
page_id, page_size, RW_X_LATCH, &mtr);
|
||||
buf_block_t* block = buf_page_get(page_id, 0, RW_X_LATCH, &mtr);
|
||||
|
||||
if (block) {
|
||||
ut_ad(page_is_root(block->frame));
|
||||
@@ -1431,7 +1426,7 @@ btr_read_autoinc(dict_index_t* index)
|
||||
ib_uint64_t autoinc;
|
||||
if (buf_block_t* block = buf_page_get(
|
||||
page_id_t(index->table->space_id, index->page),
|
||||
page_size_t(index->table->space->flags),
|
||||
index->table->space->zip_size(),
|
||||
RW_S_LATCH, &mtr)) {
|
||||
autoinc = page_get_autoinc(block->frame);
|
||||
} else {
|
||||
@@ -1463,7 +1458,7 @@ btr_read_autoinc_with_fallback(const dict_table_t* table, unsigned col_no)
|
||||
mtr.start();
|
||||
buf_block_t* block = buf_page_get(
|
||||
page_id_t(index->table->space_id, index->page),
|
||||
page_size_t(index->table->space->flags),
|
||||
index->table->space->zip_size(),
|
||||
RW_S_LATCH, &mtr);
|
||||
|
||||
ib_uint64_t autoinc = block ? page_get_autoinc(block->frame) : 0;
|
||||
@@ -1508,7 +1503,7 @@ btr_write_autoinc(dict_index_t* index, ib_uint64_t autoinc, bool reset)
|
||||
fil_space_t* space = index->table->space;
|
||||
mtr.set_named_space(space);
|
||||
page_set_autoinc(buf_page_get(page_id_t(space->id, index->page),
|
||||
page_size_t(space->flags),
|
||||
space->zip_size(),
|
||||
RW_SX_LATCH, &mtr),
|
||||
index, autoinc, &mtr, reset);
|
||||
mtr.commit();
|
||||
@@ -2683,12 +2678,12 @@ btr_attach_half_pages(
|
||||
/* for consistency, both blocks should be locked, before change */
|
||||
if (prev_page_no != FIL_NULL && direction == FSP_DOWN) {
|
||||
prev_block = btr_block_get(
|
||||
page_id_t(space, prev_page_no), block->page.size,
|
||||
page_id_t(space, prev_page_no), block->zip_size(),
|
||||
RW_X_LATCH, index, mtr);
|
||||
}
|
||||
if (next_page_no != FIL_NULL && direction != FSP_DOWN) {
|
||||
next_block = btr_block_get(
|
||||
page_id_t(space, next_page_no), block->page.size,
|
||||
page_id_t(space, next_page_no), block->zip_size(),
|
||||
RW_X_LATCH, index, mtr);
|
||||
}
|
||||
|
||||
@@ -2838,7 +2833,7 @@ btr_insert_into_right_sibling(
|
||||
const ulint space = block->page.id.space();
|
||||
|
||||
next_block = btr_block_get(
|
||||
page_id_t(space, next_page_no), block->page.size,
|
||||
page_id_t(space, next_page_no), block->zip_size(),
|
||||
RW_X_LATCH, cursor->index, mtr);
|
||||
next_page = buf_block_get_frame(next_block);
|
||||
|
||||
@@ -2864,7 +2859,7 @@ btr_insert_into_right_sibling(
|
||||
|
||||
if (rec == NULL) {
|
||||
if (is_leaf
|
||||
&& next_block->page.size.is_compressed()
|
||||
&& next_block->page.zip.ssize
|
||||
&& !dict_index_is_clust(cursor->index)
|
||||
&& !cursor->index->table->is_temporary()) {
|
||||
/* Reset the IBUF_BITMAP_FREE bits, because
|
||||
@@ -2912,7 +2907,7 @@ btr_insert_into_right_sibling(
|
||||
/* Update the free bits of the B-tree page in the
|
||||
insert buffer bitmap. */
|
||||
|
||||
if (next_block->page.size.is_compressed()) {
|
||||
if (next_block->page.zip.ssize) {
|
||||
ibuf_update_free_bits_zip(next_block, mtr);
|
||||
} else {
|
||||
ibuf_update_free_bits_if_full(
|
||||
@@ -3357,16 +3352,16 @@ func_exit:
|
||||
return(rec);
|
||||
}
|
||||
|
||||
/** Removes a page from the level list of pages.
|
||||
/** Remove a page from the level list of pages.
|
||||
@param[in] space space where removed
|
||||
@param[in] page_size page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in,out] page page to remove
|
||||
@param[in] index index tree
|
||||
@param[in,out] mtr mini-transaction */
|
||||
void
|
||||
btr_level_list_remove_func(
|
||||
ulint space,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
page_t* page,
|
||||
dict_index_t* index,
|
||||
mtr_t* mtr)
|
||||
@@ -3385,7 +3380,7 @@ btr_level_list_remove_func(
|
||||
if (prev_page_no != FIL_NULL) {
|
||||
buf_block_t* prev_block
|
||||
= btr_block_get(page_id_t(space, prev_page_no),
|
||||
page_size, RW_X_LATCH, index, mtr);
|
||||
zip_size, RW_X_LATCH, index, mtr);
|
||||
|
||||
page_t* prev_page
|
||||
= buf_block_get_frame(prev_block);
|
||||
@@ -3403,7 +3398,7 @@ btr_level_list_remove_func(
|
||||
if (next_page_no != FIL_NULL) {
|
||||
buf_block_t* next_block
|
||||
= btr_block_get(
|
||||
page_id_t(space, next_page_no), page_size,
|
||||
page_id_t(space, next_page_no), zip_size,
|
||||
RW_X_LATCH, index, mtr);
|
||||
|
||||
page_t* next_page
|
||||
@@ -3774,7 +3769,7 @@ btr_compress(
|
||||
|
||||
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
|
||||
|
||||
const page_size_t page_size(index->table->space->flags);
|
||||
const ulint zip_size = index->table->space->zip_size();
|
||||
|
||||
MONITOR_INC(MONITOR_INDEX_MERGE_ATTEMPTS);
|
||||
|
||||
@@ -3932,7 +3927,7 @@ retry:
|
||||
|
||||
/* Remove the page from the level list */
|
||||
btr_level_list_remove(index->table->space_id,
|
||||
page_size, page, index, mtr);
|
||||
zip_size, page, index, mtr);
|
||||
|
||||
if (dict_index_is_spatial(index)) {
|
||||
rec_t* my_rec = father_cursor.page_cur.rec;
|
||||
@@ -4062,7 +4057,7 @@ retry:
|
||||
|
||||
/* Remove the page from the level list */
|
||||
btr_level_list_remove(index->table->space_id,
|
||||
page_size, page, index, mtr);
|
||||
zip_size, page, index, mtr);
|
||||
|
||||
ut_ad(btr_node_ptr_get_child_page_no(
|
||||
btr_cur_get_rec(&father_cursor), offsets)
|
||||
@@ -4170,7 +4165,7 @@ retry:
|
||||
committed mini-transaction, because in crash recovery,
|
||||
the free bits could momentarily be set too high. */
|
||||
|
||||
if (page_size.is_compressed()) {
|
||||
if (zip_size) {
|
||||
/* Because the free bits may be incremented
|
||||
and we cannot update the insert buffer bitmap
|
||||
in the same mini-transaction, the only safe
|
||||
@@ -4230,7 +4225,7 @@ func_exit:
|
||||
|
||||
err_exit:
|
||||
/* We play it safe and reset the free bits. */
|
||||
if (page_size.is_compressed()
|
||||
if (zip_size
|
||||
&& merge_page
|
||||
&& page_is_leaf(merge_page)
|
||||
&& !dict_index_is_clust(index)) {
|
||||
@@ -4405,12 +4400,12 @@ btr_discard_page(
|
||||
left_page_no = btr_page_get_prev(buf_block_get_frame(block), mtr);
|
||||
right_page_no = btr_page_get_next(buf_block_get_frame(block), mtr);
|
||||
|
||||
const page_size_t page_size(index->table->space->flags);
|
||||
const ulint zip_size = index->table->space->zip_size();
|
||||
|
||||
if (left_page_no != FIL_NULL) {
|
||||
merge_block = btr_block_get(
|
||||
page_id_t(index->table->space_id, left_page_no),
|
||||
page_size, RW_X_LATCH, index, mtr);
|
||||
zip_size, RW_X_LATCH, index, mtr);
|
||||
|
||||
merge_page = buf_block_get_frame(merge_block);
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
@@ -4426,7 +4421,7 @@ btr_discard_page(
|
||||
} else if (right_page_no != FIL_NULL) {
|
||||
merge_block = btr_block_get(
|
||||
page_id_t(index->table->space_id, right_page_no),
|
||||
page_size, RW_X_LATCH, index, mtr);
|
||||
zip_size, RW_X_LATCH, index, mtr);
|
||||
|
||||
merge_page = buf_block_get_frame(merge_block);
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
@@ -4474,7 +4469,7 @@ btr_discard_page(
|
||||
}
|
||||
|
||||
/* Remove the page from the level list */
|
||||
btr_level_list_remove(index->table->space_id, page_size,
|
||||
btr_level_list_remove(index->table->space_id, zip_size,
|
||||
page, index, mtr);
|
||||
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
@@ -5038,19 +5033,7 @@ btr_validate_level(
|
||||
#endif
|
||||
|
||||
fil_space_t* space = index->table->space;
|
||||
const page_size_t table_page_size(
|
||||
dict_table_page_size(index->table));
|
||||
const page_size_t space_page_size(space->flags);
|
||||
|
||||
if (!table_page_size.equals_to(space_page_size)) {
|
||||
|
||||
ib::warn() << "Flags mismatch: table=" << index->table->flags
|
||||
<< ", tablespace=" << space->flags;
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
return(false);
|
||||
}
|
||||
const ulint zip_size = space->zip_size();
|
||||
|
||||
while (level != btr_page_get_level(page)) {
|
||||
const rec_t* node_ptr;
|
||||
@@ -5103,7 +5086,7 @@ btr_validate_level(
|
||||
block = btr_block_get(
|
||||
page_id_t(index->table->space_id,
|
||||
left_page_no),
|
||||
table_page_size,
|
||||
zip_size,
|
||||
RW_SX_LATCH, index, &mtr);
|
||||
page = buf_block_get_frame(block);
|
||||
left_page_no = btr_page_get_prev(page, &mtr);
|
||||
@@ -5174,7 +5157,7 @@ loop:
|
||||
|
||||
right_block = btr_block_get(
|
||||
page_id_t(index->table->space_id, right_page_no),
|
||||
table_page_size,
|
||||
zip_size,
|
||||
RW_SX_LATCH, index, &mtr);
|
||||
|
||||
right_page = buf_block_get_frame(right_block);
|
||||
@@ -5352,13 +5335,13 @@ loop:
|
||||
btr_block_get(
|
||||
page_id_t(index->table->space_id,
|
||||
parent_right_page_no),
|
||||
table_page_size,
|
||||
zip_size,
|
||||
RW_SX_LATCH, index, &mtr);
|
||||
|
||||
right_block = btr_block_get(
|
||||
page_id_t(index->table->space_id,
|
||||
right_page_no),
|
||||
table_page_size,
|
||||
zip_size,
|
||||
RW_SX_LATCH, index, &mtr);
|
||||
}
|
||||
|
||||
@@ -5436,21 +5419,21 @@ node_ptr_fails:
|
||||
page_id_t(
|
||||
index->table->space_id,
|
||||
parent_right_page_no),
|
||||
table_page_size,
|
||||
zip_size,
|
||||
RW_SX_LATCH, index, &mtr);
|
||||
}
|
||||
} else if (parent_page_no != FIL_NULL) {
|
||||
btr_block_get(
|
||||
page_id_t(index->table->space_id,
|
||||
parent_page_no),
|
||||
table_page_size,
|
||||
zip_size,
|
||||
RW_SX_LATCH, index, &mtr);
|
||||
}
|
||||
}
|
||||
|
||||
block = btr_block_get(
|
||||
page_id_t(index->table->space_id, right_page_no),
|
||||
table_page_size,
|
||||
zip_size,
|
||||
RW_SX_LATCH, index, &mtr);
|
||||
|
||||
page = buf_block_get_frame(block);
|
||||
@@ -5556,9 +5539,9 @@ btr_can_merge_with_page(
|
||||
page = btr_cur_get_page(cursor);
|
||||
|
||||
const page_id_t page_id(index->table->space_id, page_no);
|
||||
const page_size_t page_size(index->table->space->flags);
|
||||
const ulint zip_size = index->table->space->zip_size();
|
||||
|
||||
mblock = btr_block_get(page_id, page_size, RW_X_LATCH, index, mtr);
|
||||
mblock = btr_block_get(page_id, zip_size, RW_X_LATCH, index, mtr);
|
||||
mpage = buf_block_get_frame(mblock);
|
||||
|
||||
n_recs = page_get_n_recs(page);
|
||||
@@ -5574,7 +5557,7 @@ btr_can_merge_with_page(
|
||||
/* If compression padding tells us that merging will result in
|
||||
too packed up page i.e.: which is likely to cause compression
|
||||
failure then don't merge the pages. */
|
||||
if (page_size.is_compressed() && page_is_leaf(mpage)
|
||||
if (zip_size && page_is_leaf(mpage)
|
||||
&& (page_get_data_size(mpage) + data_size
|
||||
>= dict_index_zip_pad_optimal_page_size(index))) {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2018, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2019, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -121,7 +121,7 @@ PageBulk::init()
|
||||
} else {
|
||||
new_block = btr_block_get(
|
||||
page_id_t(m_index->table->space_id, m_page_no),
|
||||
page_size_t(m_index->table->space->flags),
|
||||
m_index->table->space->zip_size(),
|
||||
RW_X_LATCH, m_index, &m_mtr);
|
||||
|
||||
new_page = buf_block_get_frame(new_block);
|
||||
@@ -589,8 +589,9 @@ PageBulk::needExt(
|
||||
const dtuple_t* tuple,
|
||||
ulint rec_size)
|
||||
{
|
||||
return(page_zip_rec_needs_ext(rec_size, m_is_comp,
|
||||
dtuple_get_n_fields(tuple), m_block->page.size));
|
||||
return page_zip_rec_needs_ext(rec_size, m_is_comp,
|
||||
dtuple_get_n_fields(tuple),
|
||||
m_block->zip_size());
|
||||
}
|
||||
|
||||
/** Store external record
|
||||
@@ -664,7 +665,7 @@ PageBulk::latch()
|
||||
__FILE__, __LINE__, &m_mtr)) {
|
||||
m_block = buf_page_get_gen(
|
||||
page_id_t(m_index->table->space_id, m_page_no),
|
||||
page_size_t(m_index->table->space->flags),
|
||||
m_index->table->space->zip_size(),
|
||||
RW_X_LATCH, m_block, BUF_GET_IF_IN_POOL,
|
||||
__FILE__, __LINE__, &m_mtr, &m_err);
|
||||
|
||||
@@ -1017,7 +1018,7 @@ BtrBulk::finish(dberr_t err)
|
||||
ut_ad(last_page_no != FIL_NULL);
|
||||
last_block = btr_block_get(
|
||||
page_id_t(m_index->table->space_id, last_page_no),
|
||||
page_size_t(m_index->table->space->flags),
|
||||
m_index->table->space->zip_size(),
|
||||
RW_X_LATCH, m_index, &mtr);
|
||||
first_rec = page_rec_get_next(
|
||||
page_get_infimum_rec(last_block->frame));
|
||||
|
||||
@@ -210,6 +210,7 @@ btr_rec_free_externally_stored_fields(
|
||||
/** Latches the leaf page or pages requested.
|
||||
@param[in] block leaf page where the search converged
|
||||
@param[in] page_id page id of the leaf
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] latch_mode BTR_SEARCH_LEAF, ...
|
||||
@param[in] cursor cursor
|
||||
@param[in] mtr mini-transaction
|
||||
@@ -218,7 +219,7 @@ btr_latch_leaves_t
|
||||
btr_cur_latch_leaves(
|
||||
buf_block_t* block,
|
||||
const page_id_t page_id,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
ulint latch_mode,
|
||||
btr_cur_t* cursor,
|
||||
mtr_t* mtr)
|
||||
@@ -249,7 +250,7 @@ btr_cur_latch_leaves(
|
||||
|
||||
mode = latch_mode == BTR_MODIFY_LEAF ? RW_X_LATCH : RW_S_LATCH;
|
||||
latch_leaves.savepoints[1] = mtr_set_savepoint(mtr);
|
||||
get_block = btr_block_get(page_id, page_size, mode,
|
||||
get_block = btr_block_get(page_id, zip_size, mode,
|
||||
cursor->index, mtr);
|
||||
latch_leaves.blocks[1] = get_block;
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
@@ -282,7 +283,7 @@ btr_cur_latch_leaves(
|
||||
latch_leaves.savepoints[0] = mtr_set_savepoint(mtr);
|
||||
get_block = btr_block_get(
|
||||
page_id_t(page_id.space(), left_page_no),
|
||||
page_size, RW_X_LATCH, cursor->index, mtr);
|
||||
zip_size, RW_X_LATCH, cursor->index, mtr);
|
||||
latch_leaves.blocks[0] = get_block;
|
||||
|
||||
if (spatial) {
|
||||
@@ -298,7 +299,7 @@ btr_cur_latch_leaves(
|
||||
|
||||
latch_leaves.savepoints[1] = mtr_set_savepoint(mtr);
|
||||
get_block = btr_block_get(
|
||||
page_id, page_size, RW_X_LATCH, cursor->index, mtr);
|
||||
page_id, zip_size, RW_X_LATCH, cursor->index, mtr);
|
||||
latch_leaves.blocks[1] = get_block;
|
||||
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
@@ -329,7 +330,7 @@ btr_cur_latch_leaves(
|
||||
latch_leaves.savepoints[2] = mtr_set_savepoint(mtr);
|
||||
get_block = btr_block_get(
|
||||
page_id_t(page_id.space(), right_page_no),
|
||||
page_size, RW_X_LATCH, cursor->index, mtr);
|
||||
zip_size, RW_X_LATCH, cursor->index, mtr);
|
||||
latch_leaves.blocks[2] = get_block;
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
ut_a(page_is_comp(get_block->frame)
|
||||
@@ -357,7 +358,7 @@ btr_cur_latch_leaves(
|
||||
latch_leaves.savepoints[0] = mtr_set_savepoint(mtr);
|
||||
get_block = btr_block_get(
|
||||
page_id_t(page_id.space(), left_page_no),
|
||||
page_size, mode, cursor->index, mtr);
|
||||
zip_size, mode, cursor->index, mtr);
|
||||
latch_leaves.blocks[0] = get_block;
|
||||
cursor->left_block = get_block;
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
@@ -369,7 +370,7 @@ btr_cur_latch_leaves(
|
||||
}
|
||||
|
||||
latch_leaves.savepoints[1] = mtr_set_savepoint(mtr);
|
||||
get_block = btr_block_get(page_id, page_size, mode,
|
||||
get_block = btr_block_get(page_id, zip_size, mode,
|
||||
cursor->index, mtr);
|
||||
latch_leaves.blocks[1] = get_block;
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
@@ -509,7 +510,7 @@ incompatible:
|
||||
buf_block_t* block = buf_page_get(
|
||||
page_id_t(space->id,
|
||||
mach_read_from_4(ptr + BTR_EXTERN_PAGE_NO)),
|
||||
univ_page_size, RW_S_LATCH, mtr);
|
||||
0, RW_S_LATCH, mtr);
|
||||
buf_block_dbg_add_level(block, SYNC_EXTERN_STORAGE);
|
||||
if (fil_page_get_type(block->frame) != FIL_PAGE_TYPE_BLOB
|
||||
|| mach_read_from_4(&block->frame[FIL_PAGE_DATA
|
||||
@@ -591,7 +592,7 @@ inconsistent:
|
||||
} else {
|
||||
col->def_val.data = btr_copy_externally_stored_field(
|
||||
&col->def_val.len, data,
|
||||
cur.page_cur.block->page.size,
|
||||
cur.page_cur.block->zip_size(),
|
||||
len, index->table->heap);
|
||||
}
|
||||
}
|
||||
@@ -756,8 +757,7 @@ btr_cur_optimistic_latch_leaves(
|
||||
cursor->left_block = btr_block_get(
|
||||
page_id_t(cursor->index->table->space_id,
|
||||
left_page_no),
|
||||
page_size_t(cursor->index->table->space
|
||||
->flags),
|
||||
cursor->index->table->space->zip_size(),
|
||||
mode, cursor->index, mtr);
|
||||
} else {
|
||||
cursor->left_block = NULL;
|
||||
@@ -865,7 +865,7 @@ btr_cur_latch_for_root_leaf(
|
||||
@param[in] lock_intention lock intention for the tree operation
|
||||
@param[in] rec record (current node_ptr)
|
||||
@param[in] rec_size size of the record or max size of node_ptr
|
||||
@param[in] page_size page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] mtr mtr
|
||||
@return true if tree modification is needed */
|
||||
static
|
||||
@@ -876,7 +876,7 @@ btr_cur_will_modify_tree(
|
||||
btr_intention_t lock_intention,
|
||||
const rec_t* rec,
|
||||
ulint rec_size,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
mtr_t* mtr)
|
||||
{
|
||||
ut_ad(!page_is_leaf(page));
|
||||
@@ -964,9 +964,8 @@ btr_cur_will_modify_tree(
|
||||
This is based on the worst case, and we could invoke
|
||||
page_zip_available() on the block->page.zip. */
|
||||
/* needs 2 records' space also for worst compress rate. */
|
||||
if (page_size.is_compressed()
|
||||
&& page_zip_empty_size(index->n_fields,
|
||||
page_size.physical())
|
||||
if (zip_size
|
||||
&& page_zip_empty_size(index->n_fields, zip_size)
|
||||
<= rec_size * 2 + page_get_data_size(page)
|
||||
+ page_dir_calc_reserved_space(n_recs + 2)) {
|
||||
return(true);
|
||||
@@ -1462,7 +1461,7 @@ btr_cur_search_to_nth_level_func(
|
||||
|
||||
page_cursor = btr_cur_get_page_cur(cursor);
|
||||
|
||||
const page_size_t page_size(index->table->space->flags);
|
||||
const ulint zip_size = index->table->space->zip_size();
|
||||
|
||||
/* Start with the root page. */
|
||||
page_id_t page_id(index->table->space_id, index->page);
|
||||
@@ -1545,7 +1544,7 @@ search_loop:
|
||||
retry_page_get:
|
||||
ut_ad(n_blocks < BTR_MAX_LEVELS);
|
||||
tree_savepoints[n_blocks] = mtr_set_savepoint(mtr);
|
||||
block = buf_page_get_gen(page_id, page_size, rw_latch, guess,
|
||||
block = buf_page_get_gen(page_id, zip_size, rw_latch, guess,
|
||||
buf_mode, file, line, mtr, &err);
|
||||
tree_blocks[n_blocks] = block;
|
||||
|
||||
@@ -1581,7 +1580,7 @@ retry_page_get:
|
||||
ut_ad(!dict_index_is_spatial(index));
|
||||
|
||||
if (ibuf_insert(IBUF_OP_INSERT, tuple, index,
|
||||
page_id, page_size, cursor->thr)) {
|
||||
page_id, zip_size, cursor->thr)) {
|
||||
|
||||
cursor->flag = BTR_CUR_INSERT_TO_IBUF;
|
||||
|
||||
@@ -1594,7 +1593,7 @@ retry_page_get:
|
||||
ut_ad(!dict_index_is_spatial(index));
|
||||
|
||||
if (ibuf_insert(IBUF_OP_DELETE_MARK, tuple,
|
||||
index, page_id, page_size,
|
||||
index, page_id, zip_size,
|
||||
cursor->thr)) {
|
||||
|
||||
cursor->flag = BTR_CUR_DEL_MARK_IBUF;
|
||||
@@ -1614,7 +1613,7 @@ retry_page_get:
|
||||
/* The record cannot be purged yet. */
|
||||
cursor->flag = BTR_CUR_DELETE_REF;
|
||||
} else if (ibuf_insert(IBUF_OP_DELETE, tuple,
|
||||
index, page_id, page_size,
|
||||
index, page_id, zip_size,
|
||||
cursor->thr)) {
|
||||
|
||||
/* The purge was buffered. */
|
||||
@@ -1661,7 +1660,7 @@ retry_page_get:
|
||||
= mtr_set_savepoint(mtr);
|
||||
get_block = buf_page_get_gen(
|
||||
page_id_t(page_id.space(), left_page_no),
|
||||
page_size, rw_latch, NULL, buf_mode,
|
||||
zip_size, rw_latch, NULL, buf_mode,
|
||||
file, line, mtr, &err);
|
||||
prev_tree_blocks[prev_n_blocks] = get_block;
|
||||
prev_n_blocks++;
|
||||
@@ -1691,7 +1690,7 @@ retry_page_get:
|
||||
tree_blocks[n_blocks]);
|
||||
|
||||
tree_savepoints[n_blocks] = mtr_set_savepoint(mtr);
|
||||
block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
|
||||
block = buf_page_get_gen(page_id, zip_size, rw_latch, NULL,
|
||||
buf_mode, file, line, mtr, &err);
|
||||
tree_blocks[n_blocks] = block;
|
||||
|
||||
@@ -1789,7 +1788,7 @@ retry_page_get:
|
||||
if (rw_latch == RW_NO_LATCH) {
|
||||
|
||||
latch_leaves = btr_cur_latch_leaves(
|
||||
block, page_id, page_size, latch_mode,
|
||||
block, page_id, zip_size, latch_mode,
|
||||
cursor, mtr);
|
||||
}
|
||||
|
||||
@@ -2153,7 +2152,7 @@ need_opposite_intention:
|
||||
&& latch_mode == BTR_MODIFY_TREE
|
||||
&& !btr_cur_will_modify_tree(
|
||||
index, page, lock_intention, node_ptr,
|
||||
node_ptr_max_size, page_size, mtr)
|
||||
node_ptr_max_size, zip_size, mtr)
|
||||
&& !rtree_parent_modified) {
|
||||
ut_ad(upper_rw_latch == RW_X_LATCH);
|
||||
ut_ad(n_releases <= n_blocks);
|
||||
@@ -2351,12 +2350,12 @@ need_opposite_intention:
|
||||
|
||||
if (latch_mode == BTR_CONT_MODIFY_TREE) {
|
||||
child_block = btr_block_get(
|
||||
page_id, page_size, RW_X_LATCH,
|
||||
page_id, zip_size, RW_X_LATCH,
|
||||
index, mtr);
|
||||
} else {
|
||||
ut_ad(latch_mode == BTR_CONT_SEARCH_TREE);
|
||||
child_block = btr_block_get(
|
||||
page_id, page_size, RW_SX_LATCH,
|
||||
page_id, zip_size, RW_SX_LATCH,
|
||||
index, mtr);
|
||||
}
|
||||
|
||||
@@ -2574,7 +2573,7 @@ btr_cur_open_at_index_side_func(
|
||||
cursor->index = index;
|
||||
|
||||
page_id_t page_id(index->table->space_id, index->page);
|
||||
const page_size_t page_size(index->table->space->flags);
|
||||
const ulint zip_size = index->table->space->zip_size();
|
||||
|
||||
if (root_leaf_rw_latch == RW_X_LATCH) {
|
||||
node_ptr_max_size = btr_node_ptr_max_size(index);
|
||||
@@ -2597,7 +2596,7 @@ btr_cur_open_at_index_side_func(
|
||||
}
|
||||
|
||||
tree_savepoints[n_blocks] = mtr_set_savepoint(mtr);
|
||||
block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
|
||||
block = buf_page_get_gen(page_id, zip_size, rw_latch, NULL,
|
||||
BUF_GET, file, line, mtr, &err);
|
||||
ut_ad((block != NULL) == (err == DB_SUCCESS));
|
||||
tree_blocks[n_blocks] = block;
|
||||
@@ -2653,12 +2652,12 @@ btr_cur_open_at_index_side_func(
|
||||
if (height == level) {
|
||||
if (srv_read_only_mode) {
|
||||
btr_cur_latch_leaves(
|
||||
block, page_id, page_size,
|
||||
block, page_id, zip_size,
|
||||
latch_mode, cursor, mtr);
|
||||
} else if (height == 0) {
|
||||
if (rw_latch == RW_NO_LATCH) {
|
||||
btr_cur_latch_leaves(
|
||||
block, page_id, page_size,
|
||||
block, page_id, zip_size,
|
||||
latch_mode, cursor, mtr);
|
||||
}
|
||||
/* In versions <= 3.23.52 we had
|
||||
@@ -2789,7 +2788,7 @@ btr_cur_open_at_index_side_func(
|
||||
if (latch_mode == BTR_MODIFY_TREE
|
||||
&& !btr_cur_will_modify_tree(
|
||||
cursor->index, page, lock_intention, node_ptr,
|
||||
node_ptr_max_size, page_size, mtr)) {
|
||||
node_ptr_max_size, zip_size, mtr)) {
|
||||
ut_ad(upper_rw_latch == RW_X_LATCH);
|
||||
ut_ad(n_releases <= n_blocks);
|
||||
|
||||
@@ -2931,7 +2930,7 @@ btr_cur_open_at_rnd_pos_func(
|
||||
cursor->index = index;
|
||||
|
||||
page_id_t page_id(index->table->space_id, index->page);
|
||||
const page_size_t page_size(index->table->space->flags);
|
||||
const ulint zip_size = index->table->space->zip_size();
|
||||
dberr_t err = DB_SUCCESS;
|
||||
|
||||
if (root_leaf_rw_latch == RW_X_LATCH) {
|
||||
@@ -2955,7 +2954,7 @@ btr_cur_open_at_rnd_pos_func(
|
||||
}
|
||||
|
||||
tree_savepoints[n_blocks] = mtr_set_savepoint(mtr);
|
||||
block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
|
||||
block = buf_page_get_gen(page_id, zip_size, rw_latch, NULL,
|
||||
BUF_GET, file, line, mtr, &err);
|
||||
tree_blocks[n_blocks] = block;
|
||||
|
||||
@@ -3008,7 +3007,7 @@ btr_cur_open_at_rnd_pos_func(
|
||||
if (rw_latch == RW_NO_LATCH
|
||||
|| srv_read_only_mode) {
|
||||
btr_cur_latch_leaves(
|
||||
block, page_id, page_size,
|
||||
block, page_id, zip_size,
|
||||
latch_mode, cursor, mtr);
|
||||
}
|
||||
|
||||
@@ -3084,7 +3083,7 @@ btr_cur_open_at_rnd_pos_func(
|
||||
if (latch_mode == BTR_MODIFY_TREE
|
||||
&& !btr_cur_will_modify_tree(
|
||||
cursor->index, page, lock_intention, node_ptr,
|
||||
node_ptr_max_size, page_size, mtr)) {
|
||||
node_ptr_max_size, zip_size, mtr)) {
|
||||
ut_ad(upper_rw_latch == RW_X_LATCH);
|
||||
ut_ad(n_releases <= n_blocks);
|
||||
|
||||
@@ -3297,12 +3296,12 @@ btr_cur_prefetch_siblings(
|
||||
if (left_page_no != FIL_NULL) {
|
||||
buf_read_page_background(
|
||||
page_id_t(block->page.id.space(), left_page_no),
|
||||
block->page.size, false);
|
||||
block->zip_size(), false);
|
||||
}
|
||||
if (right_page_no != FIL_NULL) {
|
||||
buf_read_page_background(
|
||||
page_id_t(block->page.id.space(), right_page_no),
|
||||
block->page.size, false);
|
||||
block->zip_size(), false);
|
||||
}
|
||||
if (left_page_no != FIL_NULL
|
||||
|| right_page_no != FIL_NULL) {
|
||||
@@ -3369,12 +3368,11 @@ btr_cur_optimistic_insert(
|
||||
|| (flags & BTR_CREATE_FLAG));
|
||||
ut_ad(dtuple_check_typed(entry));
|
||||
|
||||
const page_size_t& page_size = block->page.size;
|
||||
|
||||
#ifdef UNIV_DEBUG_VALGRIND
|
||||
if (page_size.is_compressed()) {
|
||||
UNIV_MEM_ASSERT_RW(page, page_size.logical());
|
||||
UNIV_MEM_ASSERT_RW(block->page.zip.data, page_size.physical());
|
||||
if (block->page.zip.data) {
|
||||
UNIV_MEM_ASSERT_RW(page, srv_page_size);
|
||||
UNIV_MEM_ASSERT_RW(block->page.zip.data,
|
||||
block->zip_size());
|
||||
}
|
||||
#endif /* UNIV_DEBUG_VALGRIND */
|
||||
|
||||
@@ -3389,7 +3387,8 @@ btr_cur_optimistic_insert(
|
||||
rec_size = rec_get_converted_size(index, entry, n_ext);
|
||||
|
||||
if (page_zip_rec_needs_ext(rec_size, page_is_comp(page),
|
||||
dtuple_get_n_fields(entry), page_size)) {
|
||||
dtuple_get_n_fields(entry),
|
||||
block->zip_size())) {
|
||||
convert_big_rec:
|
||||
/* The record is so big that we have to store some fields
|
||||
externally on separate database pages */
|
||||
@@ -3403,7 +3402,7 @@ convert_big_rec:
|
||||
rec_size = rec_get_converted_size(index, entry, n_ext);
|
||||
}
|
||||
|
||||
if (page_size.is_compressed() && page_zip_is_too_big(index, entry)) {
|
||||
if (block->page.zip.data && page_zip_is_too_big(index, entry)) {
|
||||
if (big_rec_vec != NULL) {
|
||||
dtuple_convert_back_big_rec(index, entry, big_rec_vec);
|
||||
}
|
||||
@@ -3414,7 +3413,7 @@ convert_big_rec:
|
||||
LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page),
|
||||
goto fail);
|
||||
|
||||
if (leaf && page_size.is_compressed()
|
||||
if (block->page.zip.data && leaf
|
||||
&& (page_get_data_size(page) + rec_size
|
||||
>= dict_index_zip_pad_optimal_page_size(index))) {
|
||||
/* If compression padding tells us that insertion will
|
||||
@@ -3457,7 +3456,7 @@ fail_err:
|
||||
we have to split the page to reserve enough free space for
|
||||
future updates of records. */
|
||||
|
||||
if (leaf && !page_size.is_compressed() && dict_index_is_clust(index)
|
||||
if (leaf && !block->page.zip.data && dict_index_is_clust(index)
|
||||
&& page_get_n_recs(page) >= 2
|
||||
&& dict_index_get_space_reserve() + rec_size > max_size
|
||||
&& (btr_page_get_split_rec_to_right(cursor, &dummy)
|
||||
@@ -3520,7 +3519,7 @@ fail_err:
|
||||
}
|
||||
|
||||
if (*rec) {
|
||||
} else if (page_size.is_compressed()) {
|
||||
} else if (block->page.zip.data) {
|
||||
ut_ad(!index->table->is_temporary());
|
||||
/* Reset the IBUF_BITMAP_FREE bits, because
|
||||
page_cur_tuple_insert() will have attempted page
|
||||
@@ -3596,7 +3595,7 @@ fail_err:
|
||||
committed mini-transaction, because in crash recovery,
|
||||
the free bits could momentarily be set too high. */
|
||||
|
||||
if (page_size.is_compressed()) {
|
||||
if (block->page.zip.data) {
|
||||
/* Update the bits in the same mini-transaction. */
|
||||
ibuf_update_free_bits_zip(block, mtr);
|
||||
} else {
|
||||
@@ -3696,7 +3695,7 @@ btr_cur_pessimistic_insert(
|
||||
if (page_zip_rec_needs_ext(rec_get_converted_size(index, entry, n_ext),
|
||||
index->table->not_redundant(),
|
||||
dtuple_get_n_fields(entry),
|
||||
btr_cur_get_block(cursor)->page.size)
|
||||
btr_cur_get_block(cursor)->zip_size())
|
||||
|| UNIV_UNLIKELY(entry->is_alter_metadata()
|
||||
&& !dfield_is_ext(
|
||||
dtuple_get_nth_field(
|
||||
@@ -4337,7 +4336,7 @@ static void btr_cur_trim_alter_metadata(dtuple_t* entry,
|
||||
buf_block_t* block = buf_page_get(
|
||||
page_id_t(index->table->space->id,
|
||||
mach_read_from_4(ptr + BTR_EXTERN_PAGE_NO)),
|
||||
univ_page_size, RW_S_LATCH, &mtr);
|
||||
0, RW_S_LATCH, &mtr);
|
||||
buf_block_dbg_add_level(block, SYNC_EXTERN_STORAGE);
|
||||
ut_ad(fil_page_get_type(block->frame) == FIL_PAGE_TYPE_BLOB);
|
||||
ut_ad(mach_read_from_4(&block->frame[FIL_PAGE_DATA
|
||||
@@ -4570,7 +4569,7 @@ any_extern:
|
||||
|
||||
if (page_zip_rec_needs_ext(new_rec_size, page_is_comp(page),
|
||||
dict_index_get_n_fields(index),
|
||||
block->page.size)) {
|
||||
block->zip_size())) {
|
||||
goto any_extern;
|
||||
}
|
||||
|
||||
@@ -4749,7 +4748,8 @@ btr_cur_pess_upd_restore_supremum(
|
||||
const page_id_t page_id(block->page.id.space(), prev_page_no);
|
||||
|
||||
ut_ad(prev_page_no != FIL_NULL);
|
||||
prev_block = buf_page_get_with_no_latch(page_id, block->page.size, mtr);
|
||||
prev_block = buf_page_get_with_no_latch(page_id, block->zip_size(),
|
||||
mtr);
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
ut_a(btr_page_get_next(prev_block->frame, mtr)
|
||||
== page_get_page_no(page));
|
||||
@@ -4938,7 +4938,7 @@ btr_cur_pessimistic_update(
|
||||
rec_get_converted_size(index, new_entry, n_ext),
|
||||
page_is_comp(page),
|
||||
dict_index_get_n_fields(index),
|
||||
block->page.size)
|
||||
block->zip_size())
|
||||
|| (UNIV_UNLIKELY(update->is_alter_metadata())
|
||||
&& !dfield_is_ext(dtuple_get_nth_field(
|
||||
new_entry,
|
||||
@@ -6062,7 +6062,7 @@ discard_page:
|
||||
|| btr_cur_will_modify_tree(
|
||||
index, page, BTR_INTENTION_DELETE, rec,
|
||||
btr_node_ptr_max_size(index),
|
||||
block->page.size, mtr);
|
||||
block->zip_size(), mtr);
|
||||
page_cur_delete_rec(btr_cur_get_page_cur(cursor), index,
|
||||
offsets, mtr);
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
@@ -6212,7 +6212,7 @@ btr_estimate_n_rows_in_range_on_level(
|
||||
|
||||
const fil_space_t* space = index->table->space;
|
||||
page_id_t page_id(space->id, slot1->page_no);
|
||||
const page_size_t page_size(space->flags);
|
||||
const ulint zip_size = space->zip_size();
|
||||
|
||||
level = slot1->page_level;
|
||||
|
||||
@@ -6229,7 +6229,7 @@ btr_estimate_n_rows_in_range_on_level(
|
||||
attempting to read a page that is no longer part of
|
||||
the B-tree. We pass BUF_GET_POSSIBLY_FREED in order to
|
||||
silence a debug assertion about this. */
|
||||
block = buf_page_get_gen(page_id, page_size, RW_S_LATCH,
|
||||
block = buf_page_get_gen(page_id, zip_size, RW_S_LATCH,
|
||||
NULL, BUF_GET_POSSIBLY_FREED,
|
||||
__FILE__, __LINE__, &mtr, &err);
|
||||
|
||||
@@ -7450,7 +7450,7 @@ struct btr_blob_log_check_t {
|
||||
mtr_x_lock(dict_index_get_lock(index), m_mtr);
|
||||
m_pcur->btr_cur.page_cur.block = btr_block_get(
|
||||
page_id_t(index->table->space_id, page_no),
|
||||
page_size_t(index->table->space->flags),
|
||||
index->table->space->zip_size(),
|
||||
RW_X_LATCH, index, m_mtr);
|
||||
m_pcur->btr_cur.page_cur.rec
|
||||
= m_pcur->btr_cur.page_cur.block->frame
|
||||
@@ -7538,9 +7538,6 @@ btr_store_big_rec_extern_fields(
|
||||
ut_ad(buf_block_get_frame(rec_block) == page_align(rec));
|
||||
ut_a(dict_index_is_clust(index));
|
||||
|
||||
ut_ad(dict_table_page_size(index->table)
|
||||
.equals_to(rec_block->page.size));
|
||||
|
||||
btr_blob_log_check_t redo_log(pcur, btr_mtr, offsets, &rec_block,
|
||||
&rec, op);
|
||||
page_zip = buf_block_get_page_zip(rec_block);
|
||||
@@ -7585,7 +7582,7 @@ btr_store_big_rec_extern_fields(
|
||||
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
|
||||
|
||||
/* Space available in compressed page to carry blob data */
|
||||
const ulint payload_size_zip = rec_block->page.size.physical()
|
||||
const ulint payload_size_zip = rec_block->physical_size()
|
||||
- FIL_PAGE_DATA;
|
||||
|
||||
/* Space available in uncompressed page to carry blob data */
|
||||
@@ -7646,7 +7643,7 @@ btr_store_big_rec_extern_fields(
|
||||
mtr.set_flush_observer(btr_mtr->get_flush_observer());
|
||||
|
||||
buf_page_get(rec_block->page.id,
|
||||
rec_block->page.size, RW_X_LATCH, &mtr);
|
||||
rec_block->zip_size(), RW_X_LATCH, &mtr);
|
||||
|
||||
if (prev_page_no == FIL_NULL) {
|
||||
hint_page_no = 1 + rec_page_no;
|
||||
@@ -7694,7 +7691,7 @@ btr_store_big_rec_extern_fields(
|
||||
|
||||
prev_block = buf_page_get(
|
||||
page_id_t(space_id, prev_page_no),
|
||||
rec_block->page.size,
|
||||
rec_block->zip_size(),
|
||||
RW_X_LATCH, &mtr);
|
||||
|
||||
buf_block_dbg_add_level(prev_block,
|
||||
@@ -8057,10 +8054,9 @@ btr_free_externally_stored_field(
|
||||
ut_ad(space_id == index->table->space->id);
|
||||
ut_ad(space_id == index->table->space_id);
|
||||
|
||||
const page_size_t ext_page_size(dict_table_page_size(index->table));
|
||||
const page_size_t& rec_page_size(rec == NULL
|
||||
? univ_page_size
|
||||
: ext_page_size);
|
||||
const ulint ext_zip_size = index->table->space->zip_size();
|
||||
const ulint rec_zip_size = rec ? ext_zip_size : 0;
|
||||
|
||||
if (rec == NULL) {
|
||||
/* This is a call from row_purge_upd_exist_or_extern(). */
|
||||
ut_ad(!page_zip);
|
||||
@@ -8087,7 +8083,7 @@ btr_free_externally_stored_field(
|
||||
#ifdef UNIV_DEBUG
|
||||
rec_block =
|
||||
#endif /* UNIV_DEBUG */
|
||||
buf_page_get(page_id, rec_page_size, RW_X_LATCH, &mtr);
|
||||
buf_page_get(page_id, rec_zip_size, RW_X_LATCH, &mtr);
|
||||
|
||||
buf_block_dbg_add_level(rec_block, SYNC_NO_ORDER_CHECK);
|
||||
page_no = mach_read_from_4(field_ref + BTR_EXTERN_PAGE_NO);
|
||||
@@ -8113,13 +8109,13 @@ btr_free_externally_stored_field(
|
||||
}
|
||||
|
||||
ext_block = buf_page_get(
|
||||
page_id_t(space_id, page_no), ext_page_size,
|
||||
page_id_t(space_id, page_no), ext_zip_size,
|
||||
RW_X_LATCH, &mtr);
|
||||
|
||||
buf_block_dbg_add_level(ext_block, SYNC_EXTERN_STORAGE);
|
||||
page = buf_block_get_frame(ext_block);
|
||||
|
||||
if (ext_page_size.is_compressed()) {
|
||||
if (ext_zip_size) {
|
||||
/* Note that page_zip will be NULL
|
||||
in row_purge_upd_exist_or_extern(). */
|
||||
switch (fil_page_get_type(page)) {
|
||||
@@ -8294,7 +8290,7 @@ btr_copy_blob_prefix(
|
||||
mtr_start(&mtr);
|
||||
|
||||
block = buf_page_get(page_id_t(space_id, page_no),
|
||||
univ_page_size, RW_S_LATCH, &mtr);
|
||||
0, RW_S_LATCH, &mtr);
|
||||
buf_block_dbg_add_level(block, SYNC_EXTERN_STORAGE);
|
||||
page = buf_block_get_frame(block);
|
||||
|
||||
@@ -8332,7 +8328,7 @@ by a lock or a page latch.
|
||||
@param[out] buf the externally stored part of the field,
|
||||
or a prefix of it
|
||||
@param[in] len length of buf, in bytes
|
||||
@param[in] page_size compressed BLOB page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size
|
||||
@param[in] space_id space id of the BLOB pages
|
||||
@param[in] offset offset on the first BLOB page
|
||||
@return number of bytes written to buf */
|
||||
@@ -8341,7 +8337,7 @@ ulint
|
||||
btr_copy_zblob_prefix(
|
||||
byte* buf,
|
||||
ulint len,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
ulint space_id,
|
||||
ulint page_no,
|
||||
ulint offset)
|
||||
@@ -8361,7 +8357,8 @@ btr_copy_zblob_prefix(
|
||||
heap = mem_heap_create(40000);
|
||||
page_zip_set_alloc(&d_stream, heap);
|
||||
|
||||
ut_ad(page_size.is_compressed());
|
||||
ut_ad(zip_size);
|
||||
ut_ad(ut_is_2pow(zip_size));
|
||||
ut_ad(space_id);
|
||||
|
||||
err = inflateInit(&d_stream);
|
||||
@@ -8376,7 +8373,7 @@ btr_copy_zblob_prefix(
|
||||
is being held on the clustered index record, or,
|
||||
in row_merge_copy_blobs(), by an exclusive table lock. */
|
||||
bpage = buf_page_get_zip(page_id_t(space_id, page_no),
|
||||
page_size);
|
||||
zip_size);
|
||||
|
||||
if (UNIV_UNLIKELY(!bpage)) {
|
||||
ib::error() << "Cannot load compressed BLOB "
|
||||
@@ -8408,8 +8405,7 @@ btr_copy_zblob_prefix(
|
||||
}
|
||||
|
||||
d_stream.next_in = bpage->zip.data + offset;
|
||||
d_stream.avail_in = static_cast<uInt>(page_size.physical()
|
||||
- offset);
|
||||
d_stream.avail_in = uInt(zip_size - offset);
|
||||
|
||||
err = inflate(&d_stream, Z_NO_FLUSH);
|
||||
switch (err) {
|
||||
@@ -8479,7 +8475,7 @@ by a lock or a page latch.
|
||||
@param[out] buf the externally stored part of the
|
||||
field, or a prefix of it
|
||||
@param[in] len length of buf, in bytes
|
||||
@param[in] page_size BLOB page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] space_id space id of the first BLOB page
|
||||
@param[in] page_no page number of the first BLOB page
|
||||
@param[in] offset offset on the first BLOB page
|
||||
@@ -8489,7 +8485,7 @@ ulint
|
||||
btr_copy_externally_stored_field_prefix_low(
|
||||
byte* buf,
|
||||
ulint len,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
ulint space_id,
|
||||
ulint page_no,
|
||||
ulint offset)
|
||||
@@ -8498,11 +8494,10 @@ btr_copy_externally_stored_field_prefix_low(
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (page_size.is_compressed()) {
|
||||
return(btr_copy_zblob_prefix(buf, len, page_size,
|
||||
if (zip_size) {
|
||||
return(btr_copy_zblob_prefix(buf, len, zip_size,
|
||||
space_id, page_no, offset));
|
||||
} else {
|
||||
ut_ad(page_size.equals_to(univ_page_size));
|
||||
return(btr_copy_blob_prefix(buf, len, space_id,
|
||||
page_no, offset));
|
||||
}
|
||||
@@ -8512,7 +8507,7 @@ btr_copy_externally_stored_field_prefix_low(
|
||||
The clustered index record must be protected by a lock or a page latch.
|
||||
@param[out] buf the field, or a prefix of it
|
||||
@param[in] len length of buf, in bytes
|
||||
@param[in] page_size BLOB page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] data 'internally' stored part of the field
|
||||
containing also the reference to the external part; must be protected by
|
||||
a lock or a page latch
|
||||
@@ -8523,7 +8518,7 @@ ulint
|
||||
btr_copy_externally_stored_field_prefix(
|
||||
byte* buf,
|
||||
ulint len,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
const byte* data,
|
||||
ulint local_len)
|
||||
{
|
||||
@@ -8562,7 +8557,7 @@ btr_copy_externally_stored_field_prefix(
|
||||
return(local_len
|
||||
+ btr_copy_externally_stored_field_prefix_low(buf + local_len,
|
||||
len - local_len,
|
||||
page_size,
|
||||
zip_size,
|
||||
space_id, page_no,
|
||||
offset));
|
||||
}
|
||||
@@ -8573,7 +8568,7 @@ The clustered index record must be protected by a lock or a page latch.
|
||||
@param[in] data 'internally' stored part of the field
|
||||
containing also the reference to the external part; must be protected by
|
||||
a lock or a page latch
|
||||
@param[in] page_size BLOB page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] local_len length of data
|
||||
@param[in,out] heap mem heap
|
||||
@return the whole field copied to heap */
|
||||
@@ -8581,7 +8576,7 @@ byte*
|
||||
btr_copy_externally_stored_field(
|
||||
ulint* len,
|
||||
const byte* data,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
ulint local_len,
|
||||
mem_heap_t* heap)
|
||||
{
|
||||
@@ -8612,7 +8607,7 @@ btr_copy_externally_stored_field(
|
||||
*len = local_len
|
||||
+ btr_copy_externally_stored_field_prefix_low(buf + local_len,
|
||||
extern_len,
|
||||
page_size,
|
||||
zip_size,
|
||||
space_id,
|
||||
page_no, offset);
|
||||
|
||||
@@ -8623,7 +8618,7 @@ btr_copy_externally_stored_field(
|
||||
@param[in] rec record in a clustered index; must be
|
||||
protected by a lock or a page latch
|
||||
@param[in] offset array returned by rec_get_offsets()
|
||||
@param[in] page_size BLOB page size
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] no field number
|
||||
@param[out] len length of the field
|
||||
@param[in,out] heap mem heap
|
||||
@@ -8632,7 +8627,7 @@ byte*
|
||||
btr_rec_copy_externally_stored_field(
|
||||
const rec_t* rec,
|
||||
const ulint* offsets,
|
||||
const page_size_t& page_size,
|
||||
ulint zip_size,
|
||||
ulint no,
|
||||
ulint* len,
|
||||
mem_heap_t* heap)
|
||||
@@ -8666,5 +8661,5 @@ btr_rec_copy_externally_stored_field(
|
||||
}
|
||||
|
||||
return(btr_copy_externally_stored_field(len, data,
|
||||
page_size, local_len, heap));
|
||||
zip_size, local_len, heap));
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ btr_defragment_add_index(
|
||||
// Load index rood page.
|
||||
buf_block_t* block = btr_block_get(
|
||||
page_id_t(index->table->space_id, index->page),
|
||||
page_size_t(index->table->space->flags),
|
||||
index->table->space->zip_size(),
|
||||
RW_NO_LATCH, index, &mtr);
|
||||
page_t* page = NULL;
|
||||
|
||||
@@ -376,7 +376,7 @@ btr_defragment_merge_pages(
|
||||
dict_index_t* index, /*!< in: index tree */
|
||||
buf_block_t* from_block, /*!< in: origin of merge */
|
||||
buf_block_t* to_block, /*!< in: destination of merge */
|
||||
const page_size_t page_size, /*!< in: page size of the block */
|
||||
ulint zip_size, /*!< in: ROW_FORMAT=COMPRESSED size */
|
||||
ulint reserved_space, /*!< in: space reserved for future
|
||||
insert to avoid immediate page split */
|
||||
ulint* max_data_size, /*!< in/out: max data size to
|
||||
@@ -404,7 +404,7 @@ btr_defragment_merge_pages(
|
||||
|
||||
// Estimate how many records can be moved from the from_page to
|
||||
// the to_page.
|
||||
if (page_size.is_compressed()) {
|
||||
if (zip_size) {
|
||||
ulint page_diff = srv_page_size - *max_data_size;
|
||||
max_ins_size_to_use = (max_ins_size_to_use > page_diff)
|
||||
? max_ins_size_to_use - page_diff : 0;
|
||||
@@ -472,7 +472,7 @@ btr_defragment_merge_pages(
|
||||
// Set ibuf free bits if necessary.
|
||||
if (!dict_index_is_clust(index)
|
||||
&& page_is_leaf(to_page)) {
|
||||
if (page_size.is_compressed()) {
|
||||
if (zip_size) {
|
||||
ibuf_reset_free_bits(to_block);
|
||||
} else {
|
||||
ibuf_update_free_bits_if_full(
|
||||
@@ -489,7 +489,7 @@ btr_defragment_merge_pages(
|
||||
btr_search_drop_page_hash_index(from_block);
|
||||
btr_level_list_remove(
|
||||
index->table->space_id,
|
||||
page_size, from_page, index, mtr);
|
||||
zip_size, from_page, index, mtr);
|
||||
btr_node_ptr_delete(index, from_block, mtr);
|
||||
/* btr_blob_dbg_remove(from_page, index,
|
||||
"btr_defragment_n_pages"); */
|
||||
@@ -573,7 +573,7 @@ btr_defragment_n_pages(
|
||||
}
|
||||
|
||||
first_page = buf_block_get_frame(block);
|
||||
const page_size_t page_size(index->table->space->flags);
|
||||
const ulint zip_size = index->table->space->zip_size();
|
||||
|
||||
/* 1. Load the pages and calculate the total data size. */
|
||||
blocks[0] = block;
|
||||
@@ -589,7 +589,7 @@ btr_defragment_n_pages(
|
||||
}
|
||||
|
||||
blocks[i] = btr_block_get(page_id_t(index->table->space_id,
|
||||
page_no), page_size,
|
||||
page_no), zip_size,
|
||||
RW_X_LATCH, index, mtr);
|
||||
}
|
||||
|
||||
@@ -615,7 +615,7 @@ btr_defragment_n_pages(
|
||||
optimal_page_size = page_get_free_space_of_empty(
|
||||
page_is_comp(first_page));
|
||||
// For compressed pages, we take compression failures into account.
|
||||
if (page_size.is_compressed()) {
|
||||
if (zip_size) {
|
||||
ulint size = 0;
|
||||
uint i = 0;
|
||||
// We estimate the optimal data size of the index use samples of
|
||||
@@ -658,7 +658,7 @@ btr_defragment_n_pages(
|
||||
// Start from the second page.
|
||||
for (uint i = 1; i < n_pages; i ++) {
|
||||
buf_block_t* new_block = btr_defragment_merge_pages(
|
||||
index, blocks[i], current_block, page_size,
|
||||
index, blocks[i], current_block, zip_size,
|
||||
reserved_space, &max_data_size, heap, mtr);
|
||||
if (new_block != current_block) {
|
||||
n_defragmented ++;
|
||||
|
||||
@@ -476,7 +476,7 @@ btr_pcur_move_to_next_page(
|
||||
|
||||
next_block = btr_block_get(
|
||||
page_id_t(block->page.id.space(), next_page_no),
|
||||
block->page.size, mode,
|
||||
block->zip_size(), mode,
|
||||
btr_pcur_get_btr_cur(cursor)->index, mtr);
|
||||
|
||||
if (UNIV_UNLIKELY(!next_block)) {
|
||||
|
||||
@@ -434,7 +434,7 @@ btr_pessimistic_scrub(
|
||||
const ulint page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
|
||||
const ulint left_page_no = mach_read_from_4(page + FIL_PAGE_PREV);
|
||||
const ulint right_page_no = mach_read_from_4(page + FIL_PAGE_NEXT);
|
||||
const page_size_t page_size(index->table->space->flags);
|
||||
const ulint zip_size = index->table->space->zip_size();
|
||||
|
||||
/**
|
||||
* When splitting page, we need X-latches on left/right brothers
|
||||
@@ -449,16 +449,16 @@ btr_pessimistic_scrub(
|
||||
*/
|
||||
mtr->release_block_at_savepoint(scrub_data->savepoint, block);
|
||||
|
||||
buf_block_t* get_block __attribute__((unused)) = btr_block_get(
|
||||
btr_block_get(
|
||||
page_id_t(index->table->space_id, left_page_no),
|
||||
page_size, RW_X_LATCH, index, mtr);
|
||||
zip_size, RW_X_LATCH, index, mtr);
|
||||
|
||||
/**
|
||||
* Refetch block and re-initialize page
|
||||
*/
|
||||
block = btr_block_get(
|
||||
page_id_t(index->table->space_id, page_no),
|
||||
page_size, RW_X_LATCH, index, mtr);
|
||||
zip_size, RW_X_LATCH, index, mtr);
|
||||
|
||||
page = buf_block_get_frame(block);
|
||||
|
||||
@@ -470,9 +470,9 @@ btr_pessimistic_scrub(
|
||||
}
|
||||
|
||||
if (right_page_no != FIL_NULL) {
|
||||
buf_block_t* get_block __attribute__((unused))= btr_block_get(
|
||||
btr_block_get(
|
||||
page_id_t(index->table->space_id, right_page_no),
|
||||
page_size, RW_X_LATCH, index, mtr);
|
||||
zip_size, RW_X_LATCH, index, mtr);
|
||||
}
|
||||
|
||||
/* arguments to btr_page_split_and_insert */
|
||||
@@ -842,13 +842,15 @@ btr_scrub_start_space(
|
||||
ulint space, /*!< in: space */
|
||||
btr_scrub_t* scrub_data) /*!< in/out: scrub data */
|
||||
{
|
||||
bool found;
|
||||
scrub_data->space = space;
|
||||
scrub_data->current_table = NULL;
|
||||
scrub_data->current_index = NULL;
|
||||
const page_size_t page_size = fil_space_get_page_size(space, &found);
|
||||
|
||||
scrub_data->compressed = page_size.is_compressed();
|
||||
if (fil_space_t* s = fil_space_acquire_silent(space)) {
|
||||
scrub_data->compressed = s->zip_size();
|
||||
s->release();
|
||||
} else {
|
||||
scrub_data->compressed = 0;
|
||||
}
|
||||
scrub_data->scrubbing = check_scrub_setting(scrub_data);
|
||||
return scrub_data->scrubbing;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user